コンテンツセキュリティポリシー
コンテンツセキュリティポリシーとは?
XSS 攻撃に対する最良の保護策の 1 つは、サイトにコンテンツセキュリティポリシー(CSP)を実装することです。これには、画像、スタイルシート、JavaScript ファイルなど、サイトの HTML に含まれるコンテンツの各ソースを指定および承認する必要があります。ブラウザは、明示的に承認されていないソースからのコンテンツを拒否します。この承認は、レスポンスの Content-Security-Policy
ヘッダー内で定義され、さまざまな設定オプションを提供します。
これは複雑に聞こえるかもしれませんが、一部のサイトでは確かに難しい場合があります。ただし、すべてのコンテンツが同じドメイン(例:http://example.com)から提供される多くの単純なサイトでは、統合が非常に簡単です。
これは複雑な主題であるため、このユーザーガイドではすべての詳細について説明しません。詳細については、次のサイトをご覧ください。
CSP の有効化
重要
デバッグツールバー は、インラインスクリプトを出力する Kint を使用する場合があります。そのため、CSP がオンの場合、CSP nonce がデバッグツールバーに自動的に出力されます。ただし、CSP nonce を使用していない場合、これにより CSP ヘッダーが意図しないものに変更され、本番環境とは異なる動作をします。CSP の動作を確認する場合は、デバッグツールバーをオフにしてください。
デフォルトでは、このサポートはオフになっています。アプリケーションでサポートを有効にするには、app/Config/App.php の CSPEnabled
値を編集します。
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class App extends BaseConfig
{
// ...
public bool $CSPEnabled = true;
}
有効にすると、レスポンスオブジェクトには CodeIgniter\HTTP\ContentSecurityPolicy
のインスタンスが含まれます。app/Config/ContentSecurityPolicy.php で設定された値がそのインスタンスに適用され、ランタイム中に変更が必要ない場合は、正しくフォーマットされたヘッダーが送信され、完了です。
CSP を有効にすると、HTTP レスポンスに 2 つのヘッダー行が追加されます。1 つは Content-Security-Policy ヘッダーで、さまざまなコンテキストで明示的に許可されているコンテンツタイプまたはオリジンを識別するポリシーがあり、もう 1 つは Content-Security-Policy-Report-Only ヘッダーで、許可されるコンテンツタイプまたはオリジンを識別しますが、選択した宛先に報告もされます。
私たちの実装では、reportOnly()
メソッドを通じて変更可能なデフォルトの処理が提供されています。以下に示すように、CSP ディレクティブに追加のエントリが追加されると、ブロックまたは防止のために適切な CSP ヘッダーに追加されます。これは、追加メソッド呼び出しにオプションの 2 番目のパラメーターを提供することで、呼び出しごとにオーバーライドできます。
ランタイム設定
アプリケーションで実行時に変更を加える必要がある場合は、コントローラーの $this->response->getCSP()
でインスタンスにアクセスできます。クラスには、設定する必要がある適切なヘッダー値に非常に明確に対応する多数のメソッドがあります。次に、さまざまなパラメーターの組み合わせで例を示しますが、すべてディレクティブ名またはディレクティブの配列のいずれかを受け入れます。
<?php
// get the CSP instance
$csp = $this->response->getCSP();
// specify the default directive treatment
$csp->reportOnly(false);
// specify the origin to use if none provided for a directive
$csp->setDefaultSrc('cdn.example.com');
// specify the URL that "report-only" reports get sent to
$csp->setReportURI('http://example.com/csp/reports');
// specify that HTTP requests be upgraded to HTTPS
$csp->upgradeInsecureRequests(true);
// add types or origins to CSP directives
// assuming that the default treatment is to block rather than just report
$csp->addBaseURI('example.com', true); // report only
$csp->addChildSrc('https://youtube.com'); // blocked
$csp->addConnectSrc('https://*.facebook.com', false); // blocked
$csp->addFontSrc('fonts.example.com');
$csp->addFormAction('self');
$csp->addFrameAncestor('none', true); // report this one
$csp->addImageSrc('cdn.example.com');
$csp->addMediaSrc('cdn.example.com');
$csp->addManifestSrc('cdn.example.com');
$csp->addObjectSrc('cdn.example.com', false); // reject from here
$csp->addPluginType('application/pdf', false); // reject this media type
$csp->addScriptSrc('scripts.example.com', true); // allow but report requests from here
$csp->addStyleSrc('css.example.com');
$csp->addSandbox(['allow-forms', 'allow-scripts']);
各「add」メソッドの最初のパラメーターは、適切な文字列値、または文字列の配列です。
reportOnly()
メソッドを使用すると、オーバーライドされない限り、後続のソースのデフォルトのレポート処理を指定できます。たとえば、youtube.com を許可し、許可されているが報告されるソースをいくつか提供できます。
<?php
// get the CSP instance
$csp = $this->response->getCSP();
$csp->addChildSrc('https://youtube.com'); // allowed
$csp->reportOnly(true);
$csp->addChildSrc('https://metube.com'); // allowed but reported
$csp->addChildSrc('https://ourtube.com', false); // allowed
インラインコンテンツ
Web サイトが独自のページのインラインスクリプトやスタイルさえも保護しないように設定することは可能です。これはユーザーが生成したコンテンツの結果である可能性があるためです。これを保護するために、CSP では、<style>
および <script>
タグ内で nonce を指定し、それらの値をレスポンスのヘッダーに追加することができます。
プレースホルダーの使用
これは現実の世界で処理するのが面倒で、その場で生成されるときに最も安全です。これを簡単にするために、タグに {csp-style-nonce}
または {csp-script-nonce}
プレースホルダーを含めることができ、自動的に処理されます。
// Original
<script {csp-script-nonce}>
console.log("Script won't run as it doesn't contain a nonce attribute");
</script>
// Becomes
<script nonce="Eskdikejidojdk978Ad8jf">
console.log("Script won't run as it doesn't contain a nonce attribute");
</script>
// OR
<style {csp-style-nonce}>
. . .
</style>
警告
攻撃者が <script {csp-script-nonce}>
のような文字列を挿入すると、この機能によって実際の nonce 属性になる可能性があります。プレースホルダ文字列は、app/Config/ContentSecurityPolicy.php の $scriptNonceTag
および $styleNonceTag
プロパティでカスタマイズできます。
関数の使用
上記の自動置換機能が気に入らない場合は、app/Config/ContentSecurityPolicy.php で $autoNonce = false
を設定してオフにできます。
この場合、関数、csp_script_nonce()
および csp_style_nonce()
を使用できます。
// Original
<script <?= csp_script_nonce() ?>>
console.log("Script won't run as it doesn't contain a nonce attribute");
</script>
// Becomes
<script nonce="Eskdikejidojdk978Ad8jf">
console.log("Script won't run as it doesn't contain a nonce attribute");
</script>
// OR
<style <?= csp_style_nonce() ?>>
. . .
</style>