Playframework 2.4.x でセキュリティヘッダの設定など
まず前提として、Playframework にはフィルタという機能がある。
Playframework 2.3.x 以下の場合は、Global オブジェクトにミックスインする形式をとっていた。
だが、Playframework 2.4.x 以降は、DI も含めて形式が変更となり、root パッケージに、Filters クラスを配置する形式に変わった。
名称の変更方法などは、公式を見て欲しい。
そもそもが 2.4 のロードマップに、Global を廃止して、Plaggable である事を謳っているので、この方針変更は移植の時注意すべき点だろう。
で、実装方法については、下記の操作を行う。
標準で用意されているヘッダーを使う準備
まずは、./build.sbt
の libraryDependencies に filters を追記する。これには Cross-Origin Resource Sharing Filter, GzipFilter, SecurityHeaderFilter 機能が入っている。
libraryDependencies ++= Seq( filters, jdbc, cache, ws, specs2 % Test )
Filters.scala の実装
次に、Filters を作成して、フィルタの実装を行う。
今回は Gzip と Security だけ適用してみる。
import javax.inject.Inject import play.api.http.HttpFilters import play.api.mvc.EssentialFilter import play.filters.gzip.GzipFilter import play.filters.headers.SecurityHeadersFilter /** * Example filters. * Created by azalea on 2015/08/23. */ class Filters @Inject() (gzipFilter: GzipFilter, secure: SecurityHeadersFilter) extends HttpFilters { val filters: Seq[EssentialFilter] = Seq(gzipFilter, secure) }
なんとこれで設定は完了。
セキュリティヘッダの考察
ここまでで帰ってくるヘッダの中身を眺めると、
HTTP/1.1 200 OK Vary: Accept-Encoding Content-Type: text/html; charset=utf-8 Content-Length: 2350 X-Frame-Options: DENY Content-Encoding: gzip X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'self' X-Permitted-Cross-Domain-Policies: master-only Date: Sun, 23 Aug 2015 08:36:25 GMT
セキュリティ関連ヘッダは下記の通り。
X-Frame-Options: DENY
画面内インラインフレーム、及びフレームの使用禁止。
このポリシーには、SAMEORIGIN
,ALLOW-FROM uri
などがある。
クリックジャッキング攻撃対策。
X-Frame-Options レスポンスヘッダ - HTTP | MDN を参照。X-XSS-Protection: 1; mode=block
クライアントサイドの XSS 検出、無効化のオプション。X-Content-Type-Options: nosniff
コンテンツタイプスニッフィング*1無効。
コンンテンツタイプを偽ってXSSを動かす攻撃の対策。
詳しくは X-Content-Type-Options: nosniff の効果 : swdyh を参照。Content-Security-Policy: default-src 'self'
黙ってたら、画像もJavaScriptもHTMLも、同じサイト上のものしか実行するなという指定。
悪意あるリンクやタグを埋め込まれても実行しないようにする。
詳細は CSP ポリシーディレクティブ - Security | MDN を参照。X-Permitted-Cross-Domain-Policies: master-only
crossdomain.xml (Flash がリモートにデータお取りに行く時のポリシー)が配置できない場合の代わり。
この設定だと、マスターポリシーファイル( /crossdomain.xml)のみが許可される。
詳細は、 うさぎ文学日記 を参照。
という状況。
だが、よくよくセキュリティを齧った人間には物足りない。
- Strict-Transport-Security
指定されたサイトが常に HTTPS プロトコルを使ってアクセスするようにブラウザに指示 - X-Download-Options
ユーザがダウンロードしたファイルを直接開示するのを阻止。 - expires
サイトキャッシュの保持を禁止するなど - Public Key Pinning - Web security | MDN
とか色々足りない気がする。
ならソース見りゃいいじゃない?
そもそもどこまで対応してるものなのかについて、直接見ればいいじゃない。
てなことで
オープンソースって素晴らしい。
やはり、デフォルトでは上記5つの対応らしい。
その動作自体は、SecurityHeadersConfig
インスタンスを作って食わせれば問題ないという事だそうな。
ここでわかった設定方法は、conf/application.conf
に次のような記述を入れるようだ。
play.filters.headers { frameOptions = "SAMEORIGIN" xssProtection = "1; mode=block" contentTypeOptions = "nosniff" permittedCrossDomainPolicies = "master-only" contentSecurityPolicy = "default-src 'self'" }
作り的には、DI で食わせているので、結局 DI の使い方をきちんと覚える必要がありそう。
ってことで今日のところはネカフェの時間制限(3h だったんだけど、1h 漫画に潰した)を受けて調査終了。
*1:ブラウザがDLしたファイルのコンテンツタイプを自動認識する機能