Content Security Policy (CSP) とは、クロスサイトスクリプティング (XSS) やデータを差し込む攻撃などといった、特定の種類の攻撃を検知し、影響を軽減するために追加できるセキュリティレイヤーです。これらの攻撃はデータの窃取からサイトの改ざん、マルウェアの拡散に至るまで、様々な目的に用いられます。

CSP は完全な後方互換性を保って設計されています(ただし、CSP 2 については後方互換性が無い点もあり、明示的に記述されています。詳細は こちら の 1.1 章を参照してください)。そのため、CSP 未対応のブラウザーでも CSP 実装済のサーバと通信でき、逆もまた同様です。CSP 未対応のブラウザーは単に CSP を無視し、web コンテンツにはこれまで通り標準の同一オリジンポリシーを適用します。CSP ヘッダーを送信しないサーバに対しても、ブラウザーは同様に標準の 同一オリジンポリシー を適用します。

CSP を有効にするには、web サーバから Content-Security-Policy HTTP ヘッダーを返すように設定する必要があります(X-Content-Security-Policy ヘッダーに関する記述が時々ありますが、これは古いバージョンのものであり、今日このヘッダーを指定する必要はありません)。

他にも、 <meta> 要素を用いてポリシーを指定することも可能です。 例えば: <meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

脅威

クロスサイトスクリプティングの軽減

CSP の第一の目的は XSS 攻撃の軽減と報告です。XSS 攻撃とは、サーバから取得したコンテンツをブラウザーが信頼する性質を悪用した攻撃です。ブラウザーはコンテンツの送信元を信頼するため、たとえ実際の送信元が見かけ上とは異なっていたとしても、悪意あるスクリプトが被害者のブラウザー上で実行されてしまいます。

サーバ管理者が CSP を利用する場合、実行を許可するスクリプトの正しいドメインをブラウザーに向けて指定することにより、XSS の発生する箇所を削減・根絶することができます。CSP をサポートするブラウザーは、サーバから指定されたホワイトリストに載っているドメインのスクリプトのみ実行し、他のスクリプトはすべて無視します(インラインスクリプトや HTML 属性値のイベントハンドラも無視する対象に含まれます)。

究極的な防衛策として、スクリプトを決して実行させたくないサイトは、スクリプトの実行を全面的に拒否することも可能です。

パケット盗聴攻撃の軽減

取得するコンテンツのドメインを制限することに加えて、サーバは通信に使うプロトコルを指定することも可能です。例えば、(セキュリティの観点からはこれが理想的ですが)すべてのコンテンツを HTTPS で取得されるようにサーバから指定することが出来ます。データ通信におけるセキュリティ戦略を完全なものとするには、HTTPS 通信を強制するだけではなく、すべての Cookie に secure フラグ を付けたり、HTTP ページから対応する HTTPS ページへの自動リダイレクトを整備することも必要です。また、ブラウザーが暗号化された通信路のみを用いてサイトに接続することを保証するため、Strict-Transport-Security HTTP ヘッダーを利用することも可能です。

CSP の適用

Content Security Policy を適用するには、該当する web ページについて Content-Security-Policy HTTP ヘッダーを返すようにし、その値にはユーザエージェントに読み込ませたいリソースの情報を指定します。例えば、画像のアップロード・表示を行うページの場合、画像の出元は任意の場所で構いませんが、フォームの action 属性値は特定のエンドポイントに制限する必要があります。Content Security Policy を適切に設計すれば、クロスサイトスクリプティング攻撃に対する耐性を高めることができます。この記事では、適切なヘッダーの作成方法と記述例を紹介します。

ポリシーの設定

ポリシーの設定には Content-Security-Policy HTTP ヘッダーを以下のように用います。

Content-Security-Policy: policy

policy の箇所には、適用したい Content Security Policy を表すディレクティブから構成される文字列が入ります。

ポリシーの記述

ポリシーはポリシーディレクティブを列挙することで表現します。このポリシーディレクティブは、特定の種類のリソースや、ポリシーの適用範囲をそれぞれ表すものです。ポリシーには default-src ディレクティブを指定するべきでしょう。このディレクティブは、ポリシーについて特に指定のないリソースに対するフォールバックの役目を果たします(一覧については default-src の説明を参照してください)。また、インラインスクリプトや eval() の実行を防ぐには default-srcscript-src を指定する必要があります。さらに、<style> 要素や style 属性によるインラインスタイルの適用を防ぐには default-srcstyle-src の指定が必要となります。

一般的な適用例

この章では、一般的なセキュリティポリシーの適用例を示します。

例 1

サイト管理者が、すべてのコンテンツをサイト自身のドメイン(サブドメインを除く)から取得させたい場合。

Content-Security-Policy: default-src 'self'

例 2

サイト管理者が、信頼されたドメインとそのすべてのサブドメインからのコンテンツを許可したい場合(CSPがセットされたドメインと同一とは限らない)。

Content-Security-Policy: default-src 'self' *.trusted.com

例 3

サイト管理者がウェブアプリのユーザーに、任意のドメインからの画像読み込みを許可したい場合。ただし、音声や動画は信頼された配信元からのものだけに制限し、すべてのスクリプトは、信頼されたコードをホストする特定のサーバのみに制限する。

Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com

この例では、コンテンツのデフォルト設定としてドキュメント自身のホストのみを許可していますが、以下の例外を認めています。

  • 画像は任意の場所から読み込まれます(ワイルドカード "*" による指定に注意)。
  • メディアは media1.com と media2.com のものだけが許可されます(ただしサブドメインは許可されません)。
  • 実行可能なスクリプトは userscripts.example.com のものだけ許可されます。

例 4

サイト管理者がオンラインバンキングの web サイトについて、リクエスト時の盗聴攻撃を防ぐため、すべてのコンテンツを SSL で読み込むようにしたい場合。

Content-Security-Policy: default-src https://onlinebanking.jumbobank.com

この例では、ドメインを単一オリジン onlinebanking.jumbobank.com のみに制限し、かつドキュメントへのアクセスを HTTPS のみに制限しています。

例 5

サイト管理者が web メールサイトについて、メール内の HTML を許可し、任意のドメインから画像の読み込みを許可するが、JavaScript や他に危険性のあるコンテンツは許可したくない場合。

Content-Security-Policy: default-src 'self' *.mailsite.com; img-src *

この例では、script-src を指定していないことに注意してください。この CSP を適用したサイトは、スクリプトに関して default-src ディレクティブの設定を適用します。つまり、スクリプトは元のサーバのものだけ読み込まれます。

ポリシーのテスト

本番環境への適用をスムーズに行うため、CSP は report-only モードで動作させることが可能です。このモードの場合、ポリシーによるブロックは行われず、指定した URI へポリシー違反の内容が報告されます。また、新しいポリシーを本番環境に適用する前に試験運用する際にも report-only モードは利用できます。

ポリシーを report-only モードで動作させるには、以下のようにポリシーを Content-Security-Policy-Report-Only HTTP ヘッダーに指定します。

Content-Security-Policy-Report-Only: policy 

同じレスポンス中に Content-Security-Policy-Report-Only ヘッダーと Content-Security-Policy ヘッダーが存在した場合、どちらのポリシーも考慮されます。Content-Security-Policy ヘッダーに指定したポリシーについてはブロックが行われ、Content-Security-Policy-Report-Only ヘッダーに指定したポリシーは報告のみが行われます。

報告機能の利用

デフォルト設定では違反内容は報告されません。違反内容の報告機能を有効にするには report-uri ポリシーディレクティブを指定し、報告先の URI を 1 つ以上指定する必要があります。

Content-Security-Policy: default-src 'self'; report-uri http://reportcollector.example.com/collector.cgi

URI を指定したら報告を受け取るサーバを立ち上げます。受信した内容は適切に感じるどんな方法でも保存・処理することができます。

違反報告の構文

違反内容は以下のデータを含んだ JSON オブジェクトで送信されます。

blocked-uri
Content Security Policy によって読み込みがブロックされたリソースの URI。blocked-uridocument-uri とは異なるオリジンだった場合、blocked-uri はスキーム・ホスト・ポートのみを含むように切り詰められます。
disposition
"enforce""reporting" のいずれかで、Content-Security-Policy-Report-Only ヘッダーか Content-Security-Policy ヘッダーのどちらが使われているかで決まる。
document-uri
違反が生じたドキュメントの URI。
effective-directive
施行して違反を起こしたディレクティブ
original-policy
Content-Security-Policy HTTP ヘッダーに元々指定されていたポリシー。
referrer
違反が生じたドキュメントのリファラー。
script-sample
違反を起こしたインラインスクリプト、イベントハンドラー、スタイルの最初の 40 文字、
status-code
グローバルオブジェクトが初期化されたリソースの HTTP ステータスコード。
violated-directive
違反したポリシーセクションの名前。

違反報告の例

http://example.com/signup.html というページを例に考えます。ここでは次のようなポリシーを指定しており、cdn.example.com のスタイルシートのみを許可しています。

Content-Security-Policy: default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports

signup.html の内容は次の通りです。

<!DOCTYPE html>
<html>
  <head>
    <title>Sign Up</title>
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    ... Content ...
  </body>
</html>

間違いがあることにお気付きでしょうか?スタイルシートの読み込みは cdn.example.com からのみに制限されていますが、実際には自身のドメイン(http://example.com)から読み込もうとしています。このドキュメントを閲覧した際には、次のような違反内容が http://example.com/_/csp-reports へ POST リクエストで送信されます。

{
  "csp-report": {
    "document-uri": "http://example.com/signup.html",
    "referrer": "",
    "blocked-uri": "http://example.com/css/style.css",
    "violated-directive": "style-src cdn.example.com",
    "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports"
  }
}

ご覧の通り、blocked-uri には違反の原因となったリソースのフルパスが記録されています。ただし、必ずフルパスが記録されるとは限りません。例えば、signup.htmlhttp://anothercdn.example.com/stylesheet.css から CSS を読み込もうとした場合、blocked-uri にはフルパスではなくオリジンのみ(http://anothercdn.example.com)が記録されます。この一見不思議な挙動は CSP の仕様書に 説明されています。手短に言うと、この挙動はクロスオリジンのリソースに関する機密情報の漏えいを防ぐために規定されています。

ブラウザー実装状況

機能ChromeEdgeFirefoxInternet ExplorerOperaSafari
Content-Security-Policy251142321031574
base-uri40 無し35 無し2710
block-all-mixed-content 有り ?48 無し 有り ?
child-src401545 無し2710
connect-src2514236 無し157
default-src251423 無し157
disown-opener 無し 無し 無し 無し 無し 無し
font-src251423 無し157
form-action401536 無し2710
frame-ancestors4015337 無し2610
frame-src251423 無し157
img-src251423 無し157
manifest-src 有り 無し41 無し 有り 無し
media-src251423 無し157
navigation-to 無し 無し 無し 無し 無し 無し
object-src251423 無し157
plugin-types4015 無し9 無し2710
referrer33 — 56 無し3710 無し 有り — 43 無し
report-sample59 ? ? ?46 ?
report-to 無し 無し 無し 無し 無し 無し
report-uri251423 無し157
require-sri-for54 無し4911 無し41 無し
sandbox25145010157
script-src251423 無し157
strict-dynamic52 無し52 無し39 無し
style-src251423 無し157
upgrade-insecure-requests43 無し1242 無し30 無し
worker-src59 無し58 無し48 無し
機能Android webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
Content-Security-Policy 有り 有り 有り23 ?7.15 ?
base-uri 有り 有り 無し35 ?9.3 ?
block-all-mixed-content 有り 有り ?48 ? ? ?
child-src 有り 有り 無し45 ?9.3 ?
connect-src 有り 有り ?23 ?7.1 ?
default-src 有り 有り ?23 ?7.1 ?
disown-opener 無し 無し 無し 無し 無し 無し ?
font-src 有り 有り ?23 ?7.1 ?
form-action 有り 有り 無し36 ?9.3 ?
frame-ancestors ? 有り 無し338 ?9.3 ?
frame-src 有り 有り ?23 ?7.1 ?
img-src 有り 有り ?23 ?7.1 ?
manifest-src 有り 有り 無し41 ? 無し ?
media-src 有り 有り ?23 ?7.1 ?
navigation-to 無し 無し 無し 無し 無し 無し ?
object-src 有り 有り ?23 ?7.1 ?
plugin-types 有り 有り 無し 無し ?9.3 ?
referrer33 — 5633 — 56 無し3710 有り — 43 無し ?
report-sample5959 ? ?46 ? ?
report-to 無し 無し 無し 無し 無し 無し ?
report-uri 有り 有り ?23 ?7.1 ?
require-sri-for5454 無し491141 無し ?
sandbox 有り 有り ?50 ?7.1 ?
script-src 有り 有り ?23 ?7.1 ?
strict-dynamic5252 無し 無し39 無し ?
style-src 有り 有り ?23 ?7.1 ?
upgrade-insecure-requests4343 無し4230 無し ?
worker-src5959 無し5848 無し ?

1. Implemented as X-Webkit-CSP header in Chrome 14.

2. Implemented as X-Content-Security-Policy header in Firefox 4.

3. Implemented as X-Content-Security-Policy header, only supporting 'sandbox' directive.

4. Implemented as X-Webkit-CSP header in Safari 6.

5. Implemented as X-Webkit-CSP header in iOS 5.1.

6. Prior to Firefox 50, ping attributes of <a> elements weren't covered by connect-src.

7. Before Firefox 58, frame-ancestors is ignored in Content-Security-Policy-Report-Only.

8. Before Firefox for Android 58, frame-ancestors is ignored in Content-Security-Policy-Report-Only.

9. See Bugzilla bug 1045899.

10. Will be removed, see Bugzilla bug 1302449.

11. From version 49: this feature is behind the security.csp.experimentalEnabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.

12. Under consideration for future release.

一部のバージョンの Safari には、 Content Security Policy ヘッダーが設定されていて Same Origin ヘッダーがないと、ブラウザーが自分自身でホストされたコンテンツやオフサイトコンテンツをブロックし、 Content Security Policy がそのコンテンツを許可していないという誤った報告をするという顕著な非互換があります。

関連情報

ドキュメントのタグと貢献者

 このページの貢献者: Uemmra3, jwhitlock, hashedhyphen, hamasaki, yyss, Marsf
 最終更新者: Uemmra3,