従来の Web サイトと異なり、特権・認定アプリ には初期設定で CSP (Content Security Policy) が適用されます。これは、既存のコードを移植する際、その大半に影響を及ぼし、開発者が CSP の存在に気付いていない場合、相当な混乱をもたらす可能性があります。この記事では、アプリに適用される CSP の制約がどのようなものかを説明します。
CSP が アプリマニフェスト 内で指定されている場合、その CSP と、そのアプリの種類に適用される既定の CSP がマージされます。指定された CSP が既定 CSP の制約を緩和することはありません。Firefox Marketplace のバリデータは、アプリの登録時に CSP 違反を判別するようになっています。このバリデータは開発中にあらかじめ問題を発見するのにも役立ちます。
独自の CSP をアプリに適用するには
方法は アプリマニフェストの CSP の項目 を参照してください。何を含められるかについては CSP ポリシーディレクティブ のページを参考にしてください。
適用される CSP の制約
- リモートスクリプトの禁止
<script>
でリモートの JavaScript ファイルを指すことはできません。参照するすべての JS ファイルをアプリのパッケージ内に含めなければいけないということです。- インラインスクリプトの禁止
- HTML 内にスクリプトをインラインで含めることはできません。すべての
<script>
タグにsrc=""
属性を付ける必要があります。onclick=""
やonload=""
といったスクリプト属性を使うことはできません。<script>
タグを動的に生成したり、innerHTML
プロパティにコンテンツを指定するといったこともできません。 javascript:
URI の禁止<a href="javascript:alert('foo')">
のような URI は実行できません。eval
の禁止eval()
関数やeval
演算子は使えません。いずれもセキュリティエラーを投げます。- 関数コンストラクタの禁止
Function()
コンストラクタは使えません。使った場合セキュリティエラーを投げます。setTimeout
やsetInterval
による動的コード実行の禁止setTimeout
やsetInterval
関数には、呼び出し可能なオブジェクト (関数など) を渡さなければいけません。文字列を渡した場合、タイマーは生成されず、関数は0
を返します。- リモート Web ワーカーの禁止
- リモート URL を指す
Worker
やSharedWorker
が生成された場合、リモートサーバが400
エラーで応答したような挙動となります。 - リモート URL を指すスクリプトタグ生成の禁止
<script>
タグがdocument.createElement()
で生成され、そのsrc
属性にリモート URL を設定すると、リモートサーバが400
エラーで応答したような挙動となります。- プラグインの禁止
<object>
や<embed>
タグの使用は認められません。Java、Unity、Silverlight、Flash、Shockwave などは使用できません。- リモートスタイルの禁止
<link rel="stylesheet" href="...">
タグはすべてアプリのパッケージ内のファイルにリンクする必要があります。ただし、インラインのスタイルタグや属性 (<style>
andstyle=""
) は、特権アプリでは認められています。
認定アプリの制約
認定アプリには追加の制約が課されます。
- インラインスタイルの禁止
<style>
もstyle=""
も使えません。
既定ポリシー
アプリの既定ポリシーは以下の通りです。
- 特権アプリの CSP
-
default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'
- 認定アプリの CSP
-
default-src *; script-src 'self'; object-src 'none'; style-src 'self'
一般的な問題とよくある質問
- 特権付きアプリが jQuery を使おうとしたときにエラーを出します。
- アプリが jQuery CDN へリンクしている場合、そのコードは CSP に違反しています。jQuery のコピーをパッケージ内に含めた上で、
script
タグのsrc=""
属性でそれにリンクするようにしてください。 - 特権付きパッケージ型アプリ内でテンプレートが出力されません。
- クライアントサイドのテンプレートライブラリ (Mustache、Nunjucks など) を使用している場合、テンプレートを事前にコンパイルしておく必要があります。つまり、アプリをパッケージする前にスクリプトを実行して、HTML から JavaScript へテンプレートをコンパイルしなくてはなりません。特権付きアプリは、即席でテンプレートをダウンロード、コンパイルするリモートのローダーは使えません。なぜならコンパイラは
eval()
やnew Function()
を使うからです。 - マニフェスト内で CSP を設定し、ある機能の使用を許可しましたが、反映されません。
- 特権付き、あるいは公認のパッケージ型アプリでは既定の制約を緩和することはできません。アプリマニフェスト内の CSP 項目 は、CSP の制約を緩めるのではなく、厳しくすることしかできません。
- 特定の jQuery メソッドを使ったときに期待通りに動作しません。なぜでしょう?
- JSON-P やリモートの HTML を読み込むような一部の jQuery メソッドは CSP に違反する可能性があります。JSON-P を通じて読み込まれたコードは現在のページ内に
script
タグを注入しますが、これは CSP 違反です。JSON-P の代わりに CORS が有効になっている API を使ってください。また、jQuery はload()
andhtml()
といったメソッドの使用時にリモートのスクリプトをダウンロードし実行しようとしますが、これも<script>
タグを生成するため CSP 違反となります。 - 外部ドメインから読み込まれたコードを実行する必要がありますが、CSP によってブロックされるためできません。
- 代わりにそのコードをリモートもしくは
data:
URI の<iframe>
内で読み込み、postMessage()
を使ってそのスクリプトとメッセージを送受信してみてください。アプリの配信元が異なるiframe
は CSP の対象となりません。 - クリックやマウスオーバー時のイベントが呼び出されないのですが?
- クリックイベントやマウスイベントのハンドラを
onclick=""
もしくはonmouseover=""
で設定している場合、そのコードは CSP に違反しています。特権付きパッケージ型アプリではイベント属性を設定できません。代わりにaddEventListener()
を使ってください。 - パッケージ型アプリを Marketplace へ登録する際、CSP の警告が多数出力されます。なぜでしょう?
- Marketplace のバリデータは CSP に違反しかねないコードを判別しようと試みます。アプリが特権付きかどうかによって、それらの警告は出力される場合とされない場合があります。これは、開発者や Marketplace の審査担当者が潜在的な CSP 違反をより簡単に見つけられるようにすることを意図したものです。多くの場合 CSP の警告は誤判定ですが、アプリのコードを改善するための有益なフィードバックにもなるでしょう。CSP 違反は時として厳格でないコーディングスタイルを指摘してくれるので、仕事の質を確認する手段としても使うことができます。
バリデータで出力される CSP 警告は、Marketplace でアプリが受け入れられるかどうかの判断基準とはなりません。しかし、アプリが特権付きで実際に CSP に違反している場合は、アプリの受け入れ前にこの問題を修正するよう審査担当者から指摘されるでしょう。