26
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

コンテンツセキュリティポリシー(CSP)ディレクティブまとめ

Last updated at Posted at 2021-09-18

Qiita 10周年記念イベント - 10年後のために今勉強しておきたい技術に参加しました!

はじめに

久しぶりのQiita投稿です。最近、Webサイトのセキュリティ、特にコンテンツセキュリティポリシー(CSP)に触れる機会がありました。今まで理解が曖昧だった、フェッチディレクティブのフォールバックルールや設定可能な値などをはっきりさせることができたので、調べたことを記事としてまとめることにしました。内容は、基本的にReactなどのWebアプリケーション制作時の経験に基づいています。

0. Webアプリケーション

csp-0.png

Webアプリケーションは通常、複数のアプリケーションから成り立っています。それらのアプリケーションは各々サーバー上に存在し、ブラウザーがインターネットを経由してやり取りします。ブラウザーは、現在アクセス中のWebアプリケーション自身(オリジン)と異なるサーバーにアクセスする際にHTTPリクエストを送信し、HTTPレスポンスを受け取ります。それらのリクエストやレスポンスはボディーとよばれる中身と、ヘッダーとよばれるメタデータで構成されています。

1. CSPとは

Content-Secuirty-Policy(CSP)とはHTTPレスポンスヘッダーの一つで、セキュリティ強化のために設定することが推奨されています。ブラウザーは、Webアプリケーションを構成している画像やフォント、JavaScriptのスクリプトなどのコンテンツを取得する際に通信を行います。CSPはブラウザーに対して、信用できるコンテンツの出どころを明示するためのセキュリティレイヤーです。目的は、クロスサイトスクリプティング(XSS)やクリックジャッキングなどを防止し、Webアプリケーションとそのユーザーを守ることです。

HTTPレスポンスヘッダーに設定したCSPは、ブラウザーがWebアプリケーション内の特定のDOMの特定の属性をチェックするために使用されます。ポリシーに違反する予期しないソース(URL)が見つかった場合、ブラウザーがそのコンテンツの表示をブロックしてくれます。またContent-Security-Policy-Report-Onlyヘッダーを設定することで、コンテンツをブロックすることなくポリシーを検証することができます。

ちなみにCSPと目的が似ているヘッダーに、オリジン間リソース共有(CORS)があります。どちらもブラウザーがHTTPレスポンスヘッダーをみて判断する点では同じですが、CSPはコンテンツを取得する側が読み込むコンテンツを制限するために設定するのに対し、CORSはコンテンツを提供する側がアクセス権を与える先を制限するために設定するものです。

2. ディレクティブ一覧

csp-1.png

Content-Security-Policyのディレクティブは、大きく5種類に分けられます。重要なものからそれぞれフェッチディレクティブ、文書ディレクティブ、ナビゲーションディレクティブ、報告ディレクティブ、その他のディレクティブと呼ばれています。(本記事のディレクティブは、ブラウザーによってはまだサポートされていないものもあります。)

2-1. フェッチディレクティブ

csp-2.png

フェッチディレクティブには、親子関係が存在します。特定のディレクティブを指定しない場合、フォールバック先のディレクティブの値が適用されるものがあります。図の右側のディレクティブの値が指定されていないまたは対応していない場合、左側のディレクティブの値が使用されます。default-srcがすべてのフェッチディレクティブのフォールバック先です。

ディレクティブ 説明
default-src ソースリスト すべてのフェッチディレクティブのフォールバック先。
child-src ソースリスト frame-srcworker-srcのフォールバック先。
connect-src ソースリスト APIリクエストURLの値を制限。HTTPリクエストやWebSocketなど。
script-src ソースリスト JavaScriptのソースを制限。script-src-elemscript-src-attrのフォールバック先。
script-src-elem ソースリスト <script>のsrcに指定するソースを制限。
script-src-attr ソースリスト JavaScriptのonclickなどのイベントハンドラーに指定するソースを制限。
worker-src ソースリスト WorkerやSharedWorker、ServiceWorkerなどのスクリプトソースを制限。
font-src ソースリスト @font-faceで読み込む値を制限。
frame-src ソースリスト <iframe>のsrc の値を制限。
img-src ソースリスト <img><picture>のsrcやファビコンなどの画像のソースを制限。
manifest-src ソースリスト アプリケーションマニフェストファイルのソースを制限。
media-src ソースリスト <audio><video><track>のsrcに指定する音声や動画ソースを制限。
object-src ソースリスト <object>のdataや<embed>のsrcのソースを制限。古い可能性が高いため、可能であれば'none'を指定すること。
style-src ソースリスト スタイルシート(CSS)のソースを制限。style-src-elemstyle-src-attrのフォールバック先。
style-src-elem ソースリスト style内で読み込むソースや、linkのsrcに指定するスタイルシート(CSS)のソースを制限。
style-src-attr ソースリスト DOMにstyle={...}と直接適用するインラインスタイルのソースを制限。
prefetch-src ソースリスト Resource Hintsのprefetchまたはprerender段階で読み込むソースを制限。

2-2. 文書ディレクティブ

csp-3.png

ディレクティブ 説明
base-uri ソースリスト <base>のurl(document.baseURI)に指定する、相対URLの基点となる値を制限。
plugin-types メディア(MIME)タイプ <object><embed>のtypeに許可するコンテンツ形式を制限。image/pngなど。
sandbox sandboxの値 <iframe>のsandboxの値を指定でき、sandboxような環境を適用する。

2-3. ナビゲーションディレクティブ

csp-4.png

ディレクティブ 説明
form-action ソースリスト <form>のactionで送信先として使用されるURLを制限。
frame-ancestors ソースリスト <iframe>のsrcや<embed>のsrc、<object>のdataを使って、このアプリケーションを埋め込むことができるURLを制限。
navigate-to ソースリスト <form>のactionや<a>のhrefwindow.openなどのページを遷移するURLを制限。form-actionのフォールバック先。

2-4. 報告ディレクティブ

csp-5.png

ディレクティブ 説明
report-to URL 違反しているCSPが見つかった場合、指定先URIにJSONをPOSTする。未対応のブラウザーがある場合、非推奨だがreport-urlを併用する。

2-5. その他のディレクティブ

csp-6.png

ディレクティブ 説明
upgrade-insecure-requests - <a>のhrefや<iframe>のsrcのスキーマ名がhttpでも、httpsとみなしてリクエストを送信する。応急処置用。
require-sri-for トークン <link><script>のintegrityのハッシュ値を制限できる。改ざんされたCDNのソースのダウンロードを防ぐ。
require-trusted-types-for 'script'など element.innerHTMLなどによる、DOM-based XSSを防ぐ。
trusted-types カスタムタイプ TrustedTypes.createPolicyで作成したタイプを制限。

3. ソースリスト型のディレクティブに指定可能な値一覧

csp-3.png

値を必要とするディレクティブのほとんどはソースリスト型なため、これらの値を指定することができます。主にキーワードやURL、スキーマを組み合わせてポリシーを作成します。

3-1. キーワード

'self'を代表する文字列系の値。シングルクォーテーションで囲う必要があります。'unsafe-inline''unsafe-eval'を使用する場合もあります。

  • 'self'
  • 'none'
  • 'unsafe-inline'
  • 'unsafe-eval'
  • 'unsafe-hashed'
  • 'unsafe-allow-redirects'
  • 'strict-dynamic'
  • 'report-sample'

3-2. ホスト名やURL

スキーマ名やホスト名、ポート番号、パスを組み合わせた値で、*も使用可能です。

3-3. スキーマ名

例えばbase64でエンコードされた画像が使用されている場合、data:が必要です。

  • https:
  • data:
  • blob:
  • filesystem:

上記の他にも、Nonceやトークンもサポートされています。

4. CSPの管理方法

CSPなどのHTTPヘッダーは、サーバーで設定する方法が主流です。サードパーティのサービスなども利用していると大量のポリシーを設定する必要があるため、ディレクティブの値はkey-valueペアで定義し、使うときに関数で文字列化すると管理しやすいです。もっと良い方法があればぜひ教えて下さい。

// 定数の定義
const hostname = '*.example.com';
const self = "'self'";
const https = 'https:';
const data = 'data:';
const blob = 'blob:';
const google = 'https://www.google.com';

// CSPの値を配列で管理
const directiveValueMap = {
  'default-src': [https, self, blob],
  'img-src': [https, self, data],
  'script-src': [https, self, self],
  'style-src': [https, self],
  'object-src': [https, self],
  'frame-src': [https, self, hostname, google, blob],
};
// オブジェクトで定義したCSPの値を文字列化する関数
function toStringCSP(valueMap) {
  return Object.entries(valueMap)
    .map(([directive, values]) => `${directive} ${values.join(' ')};`)
    .join(' ');
}
// 使い方の例 - Node.js Expressの場合
  ...
  res.setHeader(
    'Content-Security-Policy',
    toStringCSP(directiveValueMap),
  );
  ...

GoogleやAdobe、Paypal、Stripeなどをはじめとしたサードパーティサービスを使用している場合、下記のサイトが便利です。最低限設定しなければならないCSPがまとめられています。

おわりに

CSPの仕組みを学び、フェッチディレクティブとナビゲーションディレクティブを一通り理解すると、追加対応やエラーに問題なく対処できるようになりました!Content-Security-Policy-Report-Onlyを併用して、なるべく厳しいポリシーを設定したいですね。default-src *;は良くないという理由が、この記事を通して伝われば嬉しいです。

ちなみにURLからWebサイトをスキャンし、安全性の評価および改善点のアドバイスをしてくれるサービスもあります。CSPが評価対象に含まれています。

参考URL

26
14
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?