コンテンツセキュリティポリシー (CSP)

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

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

CSP を有効にするには、ウェブサーバーから 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 HTTP ヘッダーを返すようにし、その値にはユーザエージェントに読み込ませたいリソースの情報を指定します。例えば、画像のアップロード・表示を行うページの場合、画像の出元は任意の場所で構いませんが、フォームの action 属性値は特定のエンドポイントに制限する必要があります。コンテンツセキュリティポリシーを適切に設計すれば、クロスサイトスクリプティング攻撃に対する耐性を高めることができます。この記事では、適切なヘッダーの作成方法と記述例を紹介します。

ポリシーの設定

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

Content-Security-Policy: policy

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

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

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

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

例 5

サイト管理者がウェブメールサイトについて、メール内の 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
コンテンツセキュリティポリシーによって読み込みがブロックされたリソースの 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 の仕様書に 説明されています。手短に言うと、この挙動はクロスオリジンのリソースに関する機密情報の漏えいを防ぐために規定されています。

ブラウザーの対応

Update compatibility data on GitHub
デスクトップモバイル
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeAndroid 版 FirefoxAndroid 版 OperaiOSのSafariSamsung Internet
Content-Security-PolicyChrome 完全対応 25
完全対応 25
完全対応 14
代替名
代替名 非標準の名前 X-Webkit-CSP を使用しています。
Edge 完全対応 14Firefox 完全対応 23
完全対応 23
完全対応 4
代替名
代替名 非標準の名前 X-Content-Security-Policy を使用しています。
IE 完全対応 10
補足 代替名
完全対応 10
補足 代替名
補足 Only supporting 'sandbox' directive.
代替名 非標準の名前 X-Content-Security-Policy を使用しています。
Opera 完全対応 15Safari 完全対応 7
完全対応 7
完全対応 6
代替名
代替名 非標準の名前 X-Webkit-CSP を使用しています。
WebView Android 完全対応 ありChrome Android 完全対応 ありFirefox Android 完全対応 23Opera Android 完全対応 ありSafari iOS 完全対応 7.1
完全対応 7.1
完全対応 5.1
補足
補足 X-Webkit-CSP
Samsung Internet Android 完全対応 あり

凡例

完全対応  
完全対応
実装ノートを参照してください。
実装ノートを参照してください。
非標準の名前を使用しています。
非標準の名前を使用しています。

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

関連情報