PlayFramework JSからのプリフライトリクエストを検証する

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

スポンサードリンク

CSRFとプリフライトリクエスト

PlayFrameworkは通常の入力フォームからのリクエストはCSRFFileterが常備されていてhelperでform生成している限り問題なく対策できるんだけど、JSからのPOSTメソッドなんかにCSRFTokenを付与して検証するのは結構手間。

いくらヘッダーにAccess-Control-Allow-Originで、クロスオリジンを許可していなくても、届いたリクエストはサーバ側で処理した上で、「レスポンスをブラウザ側のJSが読めない」だけなのでCSRFの対策とはならない。

で、最近はクロスオリジン(cors、Cross-Origin Resource Sharing)でJS等がリクエストする時は、予めサーバ側にOPTIONメソッドで送信可能であるか?(プリフライトリクエスト)を確認することでCSRFの対策を施すことが出来るようです。

PlayFrameworkは標準でCORSFilterが搭載されていて簡単に透過的に検証することができる。

Cors Filter - 2.8.x


CORSFilterを有効にする

サイトによってはbuild.sbt

libraryDependencies += filters

として依存解決するよう定義しているページもあるが、現PlayFrameworkのバージョン2.8では多分不要。

application.conに以下のようにすることでCORSFilterが有効になり、プリフライトリクエストが定義に従って検証される。デフォルトの定義は上記のドキュメントで確認できる。

application.conf

# この記述でデフォルトの定義で自動的に検証される
play.filters.enabled += "play.filters.cors.CORSFilter"

設定を変更する場合は同じくapplication.conf

play.filters.cors {
  allowedOrigins = ["http://domain.com:8080"]
}

のように記述すればよい。

このフィルターの定義に引っかかったリクエストはControllerにDispatchされず、Failureのレスポンスがクライアントに返される。故にControllerに定義された更新等の処理が行われない。

尚、CORSFilterを通過したリクエストには、自動的にAccess-Control-Allow-Originが付与されたレスポンスヘッダーが返されるのでController側で、withHeaders()を記述する必要はない。


JSからプリフライトリクエストを送信

JsonをPOSTで送信すると自動的にプリフライトリクエストを送信する。と思う。

axios.post("http://domain.com", {})

この時、僕の環境のChrome developer toolなんかではOPTIONメソッドの送信が表示されていなくてハマりにハマったので、みんなの環境でも注意して欲しい。


検証時の疑問点

僕が検証した時は、プリフライトのみならずJSからのクロスオリジンでのajax GETリクエストなんかもFilter対象になっていた。

GETは全てのオリジンから許可してPOSTのプリフライトのみオリジンを検証するといったことはひょっとして出来ないかもしれない。


検証当時はハマってた笑

こうやって整理するととても簡単な設定なんだけど、設定時は色々とハマってて笑う