Playframework 2.5 で足りてなさそうなセキュリティヘッダ設定を追加する
セキュリティヘッダなんて、ヘッダに組み込むだけのものなので、ザクッと。
package filters import javax.inject.{Inject, Singleton} import akka.stream.Materializer import play.api.Configuration import play.api.mvc.{Filter, RequestHeader, Result} import scala.concurrent.{ExecutionContext, Future} /** * Add custom security header responds. * Created by azalea on 2016/08/29. */ @Singleton class SecureHeaderFilter @Inject() ( implicit override val mat: Materializer, exec: ExecutionContext, conf: Configuration ) extends Filter { private def prefix(k: String) = s"play.filters.$k" val XFrameOptions = conf.getString(prefix("frameOptions")) val xssProtection = conf.getString(prefix("xssProtection")) val contentTypeOptions = conf.getString(prefix("contentTypeOptions")) val permittedCrossDomainPolicies = conf.getString(prefix("permittedCrossDomainPolicies")) val contentSecurityPolicy = conf.getString(prefix("contentSecurityPolicy")) val strictTransport = conf.getString(prefix("strictTransport")) val downloadOptions = conf.getString(prefix("downloadOptions")) val cacheControl = conf.getString(prefix("cacheControl")) val pragma = conf.getString(prefix("pragma")) val expires = conf.getString(prefix("expires")) val headers = Seq( XFrameOptions.map(v => "X-Frame-Options" -> v), xssProtection.map(v => "X-XSS-Protection" -> v), contentTypeOptions.map(v => "X-XSS-Protection" -> v), contentSecurityPolicy.map(v => "Content-Security-Policy" -> v), permittedCrossDomainPolicies.map(v => "X-Permitted-Cross-Domain-Policies" -> v), strictTransport.map(v => "Strict-Transport-Security" -> v), downloadOptions.map(v => "X-Download-Options" -> v), cacheControl.map(v => "Cache-Control" -> v), pragma.map(v => "pragma" -> v), expires.map(v => "expires" -> v) ).flatten /** * add secure headers. * * @param nextFilter next filter function. * @param rh request header. * @return header annotated result. */ override def apply(nextFilter: (RequestHeader) => Future[Result])(rh: RequestHeader): Future[Result] = { nextFilter(rh).map(res => res.withHeaders(headers:_*)) } }
設定ファイルはこんな感じ。もともとあった Play のセキュリティ設定に追記する形。
play.filters { headers { # The X-Frame-Options header. If null, the header is not set. frameOptions = "SAMEORIGIN" # The X-XSS-Protection header. If null, the header is not set. xssProtection = "1; mode=block" # The X-Content-Type-Options header. If null, the header is not set. contentTypeOptions = "nosniff" # The X-Permitted-Cross-Domain-Policies header. If null, the header is not set. permittedCrossDomainPolicies = "master-only" # The Content-Security-Policy header. If null, the header is not set. contentSecurityPolicy = "default-src 'self'" # My custom security headers. # The Strict-Transport-Security header. #strictTransport = "max-age=31536000; includeSubDomains" # The X-Download-Options header. #downloadOptions = "noopen" # The Cache-Control header. cacheControl = "no-cache, no-store, must-revalidate" # The pragma header. for old cache server. pragma = "no-cache" # The expires header. expires = "-1" }
上から順に説明すると、
- X-Frame-Options
画面内フレームコンテンツの制限。 DENY:フレームの全面禁止、SAMEORIGIN:同じドメインコンテンツは許可、ALLOW-FROM origin_uri 指定URLのコンテンツはフレーム表示許可
意図しない、詐欺サイト表示対策など。 - X-XSS-Protection
ブラウザの XSS 保護機能を有効化する。0: で保護を無効化。1で有効化 - X-Content-Type-Options
サーバが返してきたヘッダに従ってファイルを処理する。
特に IE なんかだと、ファイルの中身を確認して勝手に対応アプリを開く悪癖があって、拡張子を js にした JavaScript なんかを仕込む攻撃の対策 - X-Permitted-Cross-Domain-Policies
crossdomain.xml の置き換え。JavaScript で複数のサーバと通信する場合の、許可証設定。 - Content-Security-Policy
HTML,JavaScript,音声,画像などなど、アクセスしていいドメインの制限。default-src 'self'
は同一ドメイン以外からの一切のデータ取得禁止。 - Strict-Transport-Security
このURLは HTTPS でアクセスセーよというお達し。中身はお察し - X-Download-Options
ダウンロードしたファイルは、HTML 内での img タグとかを除いて、勝手に開くんじゃねーよ指定。
アップロード・ダウンロードをするシステムでは有用 - Cache-Control
プロクシとか、キャッシュサーバとかに「キャッシュしてんじゃねーよ」と通知。
個人情報入りのページをキャッシュされたら個人情報漏洩になるでしょ〜が!
no-cache: キャッシュすんじゃねーぞ。有効性確認しなけりゃキャッシュ使うんじゃねーぞ
no-store: リクエスト・レスポンスの一部分をローカルストレージに保存するんじゃない must-revalidate: 毎回サーバに確認しろ - pragma
Cache-Control の no-cache と同様。古いキャッシュサーバ向け。 - expires
キャッシュコンテンツの有効期限。-1 では常に「そのキャッシュは無効」