▶︎はじめに
株式会社iimonのフロントエンジニア川口と申します。
弊社ではプロダクトの一環として、不動産仲介業者向けの拡張機能開発を行っています。
今回開発中にCSPによるエラーにぶつかることがありましたので、調べたことをまとめたいと思います。
▶︎CSPとは
CSPとは、タイトルにもあるとおりContentSecurityPolicyの略で、XSSを代表とするブラウザに表示されるコンテンツを使用しての攻撃を防ぐためのセキュリティレイヤーのことです。悪意のあるscriptの注入を防ぐのではなく、注入されたものが効果を発揮しないようにすることができます。第一の目的は先程も挙げたXSSを防ぐことにあります。
※CSPはW3CにContent Security Policy Level3として記載されています。
▶︎CSPの設定
ポリシーの設定ではウェブサーバからContent-Security-Policy HTTPヘッダーを返すよう設定する必要があります。
Content-Security-Poricy: 〇〇
または、HTMLのタグで指定することも可能です。
<meta http-equiv="Content-Security-Policy" content="〇〇" />
〇〇には後述するポリシーをを記載します。
▶︎CSPのポリシーディレクティブ
デフォルトポリシー
- default-src
その他のディレクティブ
- connect-scr ‘self’;
- FetchApiなどによるネットワークリクエストがオリジンでのみ許可される
- font-scr ‘self’;
- フォントファイルの読み込みが同じオリジンでのみ許可される
- frame-src ‘self’;
- iframeなどのフレーム表示が同じオリジンでのみ許可される
- img-src ‘self’;
- 画像の読み込みが同じオリジンでのみ許可される
- manifest-src ‘self’;
- Webアプリケーションのマニフェストファイルの読み込みが同オリジンでのみ許可される
- media-src ‘self’;
- メディアファイルの再生が同じオリジン内でのみ許可される
- object-src ‘self’;
- objectやembedなどのオブジェクト表示が同じオリジンでのみ許可される
- script-str script ;
- 外部スクリプトの読み込みがscriptのオリジンからのみ許可される
- style-src ‘self’;
- スタイルシートの読み込みが同じオリジンでのみ許可される
- worker-src ‘self’;
- WebWorkerスクリプトの読み込みが同じオリジンでのみ許可される
ここに記載したもの以外にも、細かい設定が可能なようです。
▶︎今回、エラーが発生したサイトの設定
今回エラーが発生したサイトでは以下の様な設定になっていました。
Content-Security-poricy: frame-ancestors 'self'
これは、どのドメインが特定のwebページをframeやiframeなどのHTMLフレーム内で表示できるかを制御します。この設定により、指定されたドメインからのみ、設定されたウェブページをフレーム内で表示することができます。他のドメインからの埋め込みを防ぐことで、クリックジャッキングなどの攻撃を防ぐことができます。
今回拡張機能で、iframeを表示するscriptが記載されたアンカーをクリックする機能があったため、禁止事項に抵触したのではないかと考えられます。
▶︎Chrome拡張機能での対応
CSPによるChrome拡張機能の制限
現在、CSPが設定されているwebページは全体の約5%程度とのことですが、今回のように設定されているページに遭遇することはままあると思います。
本来、CSPをが設定されていることは、セキュリティーの観点から良いことではあるのですが、今回遭遇したエラーのように、CSPの制限により拡張機能でできることが制限されてしまうことがあります。
拡張機能でCSPを回避する
どうやら、拡張機能側からCSPを回避することが可能なようです。
「CSPの設定」でも記述した通り、CSPはHTTP headerで制御されています。そのため、拡張機能からヘッダーを書き換えることで無効にすることが可能です。
background.js(manifest.jsonで設定しているバックグラウンドファイル)に下記のように記載します。
chrome.webRequest.onHeadersReceived.addListener(function(detail){ const headers = detail.responseHeaders.filter(e => e.name !== "content-security-policy") return {responseHeaders: headers} }, {urls: ["<all_urls>"]}, ["blocking", "responseHeaders"])
このコードは、ヘッド内のcontent-security-policyを消して読み込むためのものです。
第二引数のurlsはCSPを無効化するURLを指定します。
▶︎おわりに
今回、「CSPとは何か?」というところから始まり、拡張機能での対応方法までまとめました。
先述した方法で、CSPを無効化することはできますが、CSPを無効化することで、XSS攻撃に対するセキュリティレベルが低下することを認識しなければなりません。
CSPを無効にする場合は、対象urlに<all_urls>などを使用せず、必要最低限のサイトを指定する必要があると感じました。また、CSPを無効にせずに対応する方法があるならば、そちらの方を優先して行うべきであると感じました。
最後までお読みいただき、ありがとうございます。少しでも有益な情報であると感じていただけたのであれば幸いです。