はじめに
-
spatie/laravel-cspについて理解するために整理してみました
spatie/laravel-csp とは
- Laravelで
Content Security Policy(CSP)を扱いやすくするpackage
CSPはHTTPレスポンスヘッダーのひとつで、ブラウザに対して
- どこからJavaScriptを読み込んでよいか
- どこからCSSを読み込んでよいか
- どこへ通信してよいか
- iframeで埋め込みを許可するか
- インラインscriptを許可するか
のようなルールを伝えるための仕組みのこと
CSPについて
- このページで動いてよいものの範囲を、ブラウザに宣言する仕組みのこと
- script は自サイトのものだけ許可する
- style も自サイトのものだけ許可する
- 外部 API への通信先を制限する
- インライン script は禁止する
といったルールをブラウザ側に渡すことができる。XSS対策としてscript を動かしにくくできることができる。
packageでなんで使用するか
CSP 自体は package がなくても設定可能だけど、管理が難しくなると想定しています。
script-srcstyle-srcimg-srcconnect-srcframe-ancestors
のように directive が増えていくと、ヘッダーを文字列で持つだけでは見通しが悪くなる。
spatie/laravel-csp を使うと、このあたりを Laravel の設定としてまとめやすくなる。
イメージは以下のような感じです。
// 概念説明用のイメージ
'directives' => [
[Directive::DEFAULT, Keyword::SELF],
[Directive::SCRIPT, Keyword::SELF],
[Directive::STYLE, Keyword::SELF],
];
「自サイトのものを基本に許可する」という方針がわかりやすい。
selfについて
CSP を見ると必ず出てくるのが 'self' の設定。
このページを配信しているサイト自身という意味。
たとえば、
script-src 'self'
なら、自サイトから配信された JavaScript だけを許可する、という意味になります。
Blade only で public/js/app.js のような構成なら、このselfとかなり相性がいいみたい。
<script src="/js/app.js"></script>
注意すること
- インライン script は別で考える必要がある点。
<script>
console.log('hello');
</script>
こういう HTML に直接書いたインライン script は、script-src 'self' だけではいけないみたい。'self' が許可するのは同一オリジンのスクリプトファイルであって、インライン script そのものではないため。
インライン script を許可したい場合は、unsafe-inline を付けるか、nonce や hash を使う必要がある点
- CSP を効かせたい場合は、
- できるだけ外部 JS に寄せる
- どうしても必要なら nonce を使う
という方向が良さそう
packageでは解決できないこと
-
spatie/laravel-cspを入れたからといって、アプリケーションのバグそのものが消えるわけではないので、そこは注意。
たとえば、
- SQLインジェクション
- 認可漏れ
- CSRF の設定ミス
- サーバーサイドのロジックバグ
- 危険な DOM 操作
- エスケープ漏れ
のような問題は、別で直す必要があるし、そもそも問題コード自体を直す方が良いと考えます。
まとめ
spatie/laravel-csp は、LaravelでCSP を運用するためのpackageとしては使い勝手が良さそうです。
このpackageを使うことで、
- 読み込める script や style を制限できる
- XSS の被害を小さくしやすい
- CSP の設定を Laravel のコードとして整理しやすい
といったメリットがあります。一方で、
- アプリケーションのバグそのものは直せない
- インライン script が多い既存システムでは導入が重くなりやすい
- きれいに効かせるにはコード側の整理が必要
という前提もあるのかなという理解です。