技術をかじる猫

適当に気になった技術や言語、思ったこと考えた事など。

Playframework 2.4.x でセキュリティヘッダの設定など

まず前提として、Playframework にはフィルタという機能がある。

Playframework 2.3.x 以下の場合は、Global オブジェクトにミックスインする形式をとっていた。

ScalaHttpFilters

だが、Playframework 2.4.x 以降は、DI も含めて形式が変更となり、root パッケージに、Filters クラスを配置する形式に変わった。
名称の変更方法などは、公式を見て欲しい。

ScalaHttpFilters

そもそもが 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.xmlFlash がリモートにデータお取りに行く時のポリシー)が配置できない場合の代わり。
    この設定だと、マスターポリシーファイル( /crossdomain.xml)のみが許可される。
    詳細は、 うさぎ文学日記 を参照。

という状況。

だが、よくよくセキュリティを齧った人間には物足りない。

  • Strict-Transport-Security
    指定されたサイトが常に HTTPS プロトコルを使ってアクセスするようにブラウザに指示
  • X-Download-Options
    ユーザがダウンロードしたファイルを直接開示するのを阻止。
  • expires
    サイトキャッシュの保持を禁止するなど
  • Public Key Pinning - Web security | MDN

とか色々足りない気がする。

ならソース見りゃいいじゃない?

そもそもどこまで対応してるものなのかについて、直接見ればいいじゃない。
てなことで

github.com

オープンソースって素晴らしい。

やはり、デフォルトでは上記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したファイルのコンテンツタイプを自動認識する機能