CSP(content security policy)をためしてみる

CSP(Content Security Policy)を設定することでXSSやクリックジャッキング、パケットキャプチャなどの攻撃を軽減できるということなので、
どんなものなのか試してみた。

CSPを有効にすると、コンテンツの提供元を制限することで、制作者がリストに登録していない提供元からのコンテンツを読込ませないようにできます。
このため悪意のあるコードを実行させないなどの対策がきます。
特に設定してない、デフォルト状態では以下のことが制限されます。

  • data: URLでのコンテンツの埋込
  • href=’javascript:’のようなhtmlへのjavascriptの埋込
  • onclickなどのインラインのイベント属性
  • script要素内のインラインスクリプト
  • eval() での文字列コード new Function()コンストラクタ
  • setInterval()ないでの文字列コード setTimeout()ないでの文字列コード
  • style要素でのCSSの設定
  • インラインのstyle属性

という感じでデフォルトではかなり制限されます。

CSPでサービス開発者が任意に設定できる項目はMDNによると

項目 内容
default-src デフォルトで許可するURIを指定
inline-script インラインスクリプトを有効にする
eval-scriot evalを有効にする
script-src scriptの提供元を指定
style-src cssの提供元を指定
img-src 画像とfavicon の提供元を指定
font-src ウェブフォント@font-face で読込まれる提供元を指定
media-src audio,video で参照する提供元を指定
object-src object,embed,applet で参照する提供元を指定
frame-src frame,iframe で参照する提供元を指定
xhr-src XMLHttpRequestの提供元を指定
connect-src web socketの提供元を指定
form-action formの送信先を指定
sandbox sandbox属性の値を設定
plugin-type pdfなど application/octet-streamヘッダーで提供されるもの

の提供元を明示的に指定することができる。

CSPはレスポンスヘッダーに明示的に設定する必要があり、ブラウザはこの情報を見てコンテンツの読込みを決定します。

FirefoxとChromeで実装済み(IE10でも提供される)ですが、ブラウザに送るヘッダーの仕様が違います。
Firefoxは X-Content-Security-Policy、Chromeは X-WebKit-CSP、IE10では X-Content-Security-Policyの予定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#encoding: UTF-8
require 'rubygems'
require 'pp'
require 'bundler'
require 'sinatra/base'
require 'erb'

Bundler.require

before do
# コンテンツの提供元の特別なクラスを記述するためのキーワード
keyword = 'self'

# デフォルトで設定する提供元
default = 'default-src self;'

# 画像と favicon の読み込みに使用される可能性のある提供元を指定
img = 'img-src ;'

# JavaScirpt の正当な提供元を指定します
script = 'script-src http://ajax.googleapis.com;'

# <frame> 要素や <iframe> 要素を使用して読み込まれるフレームコンテンツの正当な提供元を指定
frame = 'frame-src ;'

# Firefox
headers 'X-Content-Security-Policy' => 'allow ' + keyword + default + script + style + img + frame
# Chrome
headers 'X-WebKit-CSP' => 'allow ' + keyword + default + script + style + img + frame

end

get '/' do
erb :index
end

また、ポリシーの違反があった場合は、指定したURIにレポートを送ることもできます。

1
2
3
4
5
6
7
8
9
10
11
12
13
# Content Security Policy 違反を報告するようにブラウザに指示
reporturi = 'report-uri/report;'

# Firefox
headers 'X-Content-Security-Policy' => 'allow ' + keyword + default + script + style + img + frame + reporturi
# Webkit
headers 'X-WebKit-CSP' => 'allow ' + keyword + default + script + style + img + frame + reporturi

# エラーレポート
# とりあえず出力してみる
post '/report' do
pp request.env['rack.input'].read.to_s
end

レポートはjson形式でpostされます。

1
'{'csp-report':{'request':'GET http://127.0.0.1:9393/ HTTP/1.1','blocked-uri':'self','violated-directive':'inline script base restriction','source-file':'http://127.0.0.1:9393/','script-sample':'\    $(function(){\      $('body').appen...','line-number':13}}'

という感じなんですが、これを使うとなると既に動いてるサービスとかは変更が大変だ。
現在読込んでる外部リソースをリスト化してそれぞれをホワイトリストとして登録するとか。。。

ただCSP自体は完全な後方互換らしいので、設定しておいてもいいかも。

参考にしたページ

ontent-security-policy.com

Comments