2015年2月25日水曜日

Content Security Policy

ApacheでContent Security Policyを設定したメモ。


httpd.confで設定する例。

Header set Content-Security-Policy "default-src 'self'; script-src 'self', 'unsafe-inline', www.example.com"


とりあえずレポートだけ見たい場合の例。
Header set Content-Security-Policy-Report-Only \
"default-src 'none';\
 script-src 'self';\
 object-src 'none';\
 img-src 'self';\
 media-src 'none';\
 frame-src 'none';\
 font-src 'none';\
 connect-src 'none';\
 style-src 'self';\
 report-uri /csp-report.php?v=1"

レポートでどのポリシーに違反したのか見やすくするため、xxxx-srcを全部書いた。
何がエラーになるか分かるように基本厳し目に、使わなそうなのはとりあえずnoneにしている。
report-uriのパラメータ(v=1)は後述。

右辺の書き方については下記参照。
CSP policy directives - Security | MDN

はまりそうなとこだけ書くと、

  • 'none'・'self'・'unsafe-inline'・'unsafe-eval'はシングルクォーテーションも含めて書く必要がある。
  • データスキーム(data:)はコロンも含めて書く。
    (mod_pagespeedを使っていると、気づかない間にデータスキームが使われていたりする。)
    ちなみに、スキームはデータに限らず、"https:"など特定のスキーム限定を指定できるみたい。
  • URLはスキームを省略可(例:www.example.com)。省略した場合、元のページと同じスキームと同じもののみ許可する。
    ポートも同様。
  • URLで別のスキームを許可したい場合、別途記載が必要。
    例:元のページがhttpで、読み込むCSSがhttpsの場合、httpsのURLも書く必要がある。
    ワイルドカードが使えるという説明もあったが、下記のどちらも駄目だった(ブラウザによる?)
  • *://www.example.com
  • *//www.example.com
  • URLのサブドメインはワイルドカード(*)が使える。
    サブドメインをワイルドカードにすると、サブサブ(...略)ドメインまでワイルドに適用される。
    ただしサブドメイン無しには適用されないらしい。


レポートをログに書き出すPHPの例。
<?php
if (!$_GET || $_GET['v'] < 1) {
        exit;
}
$report = json_decode(file_get_contents('php://input'), true);
$log = date('[Y-m-d H:i:s] ') . $_SERVER['HTTP_USER_AGENT'] . ' ';
$log .= var_export($report['csp-report'], true) . "\n";
error_log($log, 3, '/var/log/csp-report.log');

Content-Security-Policy-Report-Onlyの例でreport-uriにパラメータを付けたのは、このPHPの2行目で古いポリシーを無視するため。
ブラウザによってはキャッシュしてしまうようで、古いポリシーに基づき送信してくることがあり、ノイズになるので。
ポリシーを変えたら、パラメータの数字とPHPの2行目の数字を両方インクリメントする。

ログファイルはApacheが書き込めるように権限設定しておく。

(2015/3/2 追記)
logrotateも追加しておく。(phpのlogrotate設定をコピーして作成。)
/var/log/csp-report.log { missingok notifempty}

(追記終わり)

また、ModSecurityを使っている場合はレポートがModSecurityではじかれないように注意。

ログを見ていると、違反URLとして報告される"about"はabout:blankだと思うけど、"asset"って何だろう?



ちなみに、Gmailのポリシーはこんな感じだった。
script-src https://*.talkgadget.google.com 'self' 'unsafe-inline' 'unsafe-eval' https://talkgadget.google.com https://www.googleapis.com https://www-gm-opensocial.googleusercontent.com https://docs.google.com https://www.google.com https://s.ytimg.com https://www.youtube.com https://ssl.google-analytics.com https://apis.google.com https://clients1.google.com https://ssl.gstatic.com https://www.gstatic.com blob:;frame-src https://*.talkgadget.google.com https://www.gstatic.com 'self' https://accounts.google.com https://apis.google.com https://clients6.google.com https://content.googleapis.com https://mail-attachment.googleusercontent.com https://www.google.com https://docs.google.com https://drive.google.com https://*.googleusercontent.com https://feedback.googleusercontent.com https://talkgadget.google.com https://isolated.mail.google.com https://www-gm-opensocial.googleusercontent.com https://plus.google.com https://wallet.google.com https://www.youtube.com https://clients5.google.com https://ci3.googleusercontent.com;object-src https://mail-attachment.googleusercontent.com;report-uri /mail/cspreport

見やすく整形。
script-src
https://*.talkgadget.google.com
'self'
'unsafe-inline'
'unsafe-eval'
https://talkgadget.google.com
https://www.googleapis.com
https://www-gm-opensocial.googleusercontent.com
https://docs.google.com
https://www.google.com
https://s.ytimg.com
https://www.youtube.com
https://ssl.google-analytics.com
https://apis.google.com
https://clients1.google.com
https://ssl.gstatic.com
https://www.gstatic.com
blob:
frame-src
https://*.talkgadget.google.com
https://www.gstatic.com
'self'
https://accounts.google.com
https://apis.google.com
https://clients6.google.com
https://content.googleapis.com
https://mail-attachment.googleusercontent.com
https://www.google.com
https://docs.google.com
https://drive.google.com
https://*.googleusercontent.com
https://feedback.googleusercontent.com
https://talkgadget.google.com
https://isolated.mail.google.com
https://www-gm-opensocial.googleusercontent.com
https://plus.google.com
https://wallet.google.com
https://www.youtube.com
https://clients5.google.com
https://ci3.googleusercontent.com
object-src
https://mail-attachment.googleusercontent.com
report-uri
/mail/cspreport

scriptは'unsafe-inline'も'unsafe-eval'も許可してしまっているが、imgも含めて*を使っていないのは立派。
style等は(defaultも)指定していないが、不要という判断か、指定すると差し障りがあるのか、どちらだろう?

また、1バイトを削るのにもこだわるGoogleがわざわざこれだけの文字列を送信するのは、セキュリティの方が重要だからということだろう。
サブドメインをワイルドカードでまとめれば随分減りそうだが、Googleともなると使っているサブドメインも膨大なので、セキュリティが担保しづらくなるのだろう。
policy-uriを指定してポリシーをXMLでやりとりしてキャッシュを効かせれば総通信料は減りそうだが、柔軟性とのトレードオフか。
report-uriも送信料を増やすが、これ無しは運用的にきっと難しいだろう。

0 件のコメント:

ブログ アーカイブ

tags