読者です 読者をやめる 読者になる 読者になる

謎言語使いの徒然

適当に気になった技術や言語を流すブログ。

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

Tips 勉強 Playframework

まず前提として、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したファイルのコンテンツタイプを自動認識する機能