CSPとは
CSPはブラウザに実装されている、主にXSSを緩和するためセキュリティ機構です。
以前SOP(Same-Origin Policy)について解説しました。
CORSとは。CORSの検証環境を構築して一から理解する。SOPは異なるオリジン間のリソースのアクセスを制限することでセキュリティを確保する機能でしたが、逆に言うとSOPは同一オリジン内のリソースのアクセスには何も制限をかけません。
クロスサイトスクリプティング(XSS)は同一オリジンから攻撃が行われるため、SOPでは防ぐことができません。
CSPを適切に導入することで、SOPでは防ぐことができないXSSの影響を軽減することができます。
CSPの設定方法
CSPを利用したい場合、典型的には以下のHTTPヘッダを追加するだけで利用できます。
Content-Security-Policy: default-src 'self'
実際にCSPの挙動を見てみます。
以下のコードではCDNのjQueryを使ってテキストを書き換えています。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>example.com</title>
<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js"></script>
</head>
<body>
<p id="main">hogehoge</p>
<script>
$('#main').text('ReWrite!!!')
</script>
</body>
</html>
特に問題なくテキストは変更されます。
次にCSPを設定した場合です。
以下のようにContent-Security-Policyヘッダを追加しています。
<?php
header("Content-Security-Policy: default-src 'self'");
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>example.com</title>
<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js"></script>
</head>
<body>
<p id="main">hogehoge</p>
<script>
$('#main').text('ReWrite!!!')
</script>
</body>
</html>
上図のように、CSPによってjQueryの読み込みが拒否されていることがわかります。
Content-Security-Policyで指定している「default-src ‘self’」は、自身のオリジンからのみ読み込むことを許可するディレクティブなので、このように外部のjsの読み込みに失敗します。
次に、jQueryをローカルに用意して読み込んでみます。
<?php
header("Content-Security-Policy: default-src 'self'");
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>example.com</title>
<script src="./jquery.js"></script>
</head>
<body>
<p id="main">hogehoge</p>
<script>
$('#main').text('ReWrite!!!')
</script>
</body>
</html>
jQueryの読み込みには成功しますが、CSPによってテキストの書き換えが止められてしまいます。
このように、CSPではインラインスクリプトも禁止される点に注意が必要です。
しかし、インラインスクリプトの禁止はXSSの被害を大きく軽減する可能性があります。
一方、インラインスクリプトをまったく使わないでWebシステムを開発するのは手間がかかるという点が、CSPがあまり普及していない理由の一つだと思われます。
インラインスクリプトを許可する場合、ディレクティブに’unsafe-inline’を追加します。
<?php
header("Content-Security-Policy: default-src 'self' 'unsafe-inline'");
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>example.com</title>
<script src="./jquery.js"></script>
</head>
<body>
<p id="main">hogehoge</p>
<script>
$('#main').text('ReWrite!!!')
</script>
</body>
</html>
CSPが防ぐのはJavaScriptだけじゃない
CSPは、JavaScriptの読み込みや実行だけを制御する仕組みではなく、画像やCSSなどのすべてのメディアを制御することができます。
default-src と script-src の違い
先ほどのコードを修正して、以下のように外部サイトの画像を表示するようなタグを追加しました。
<?php
header("Content-Security-Policy: default-src 'self' 'unsafe-inline'");
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>example.com</title>
<script src="./jquery.js"></script>
</head>
<body>
<p id="main">hogehoge</p>
<script>
$('#main').text('ReWrite!!!')
</script>
<img src="https://www.ipa.go.jp/files/000083715.png">
</body>
</html>
「default-src ‘self’」は画像にも影響するため、読み込みに失敗して画像は表示されません。
default-srcはコンテンツ全体に影響するため、JavaScriptのみ制御したい場合はscript-srcディレクティブを指定します。
<?php
header("Content-Security-Policy: script-src 'self' 'unsafe-inline'");
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>example.com</title>
<script src="./jquery.js"></script>
</head>
<body>
<p id="main">hogehoge</p>
<script>
$('#main').text('ReWrite!!!')
</script>
<img src="https://www.ipa.go.jp/files/000083715.png">
</body>
</html>
X-XSS-Protection
最後に、X-XSS-Protectionヘッダについて触れておきます。
このヘッダはCSPより歴史が古く、ブラウザが持つ(持っていた)XSSフィルタという機能の設定を強制的に上書きするヘッダです。
モダンなブラウザの多くにはXSSフィルタと呼ばれるセキュリティ機能が実装されています(ただしFirefoxは例外でXSSフィルタが実装されていません)。X-XSS-Protectionヘッダは下記の2点の役割があります。
・利用者がXSSフィルタの有効化・無効化設定をしていても、当該ページについてXSSフィルタの設定を上書きする
・XSSフィルタの動作モードを指定する
通常は以下を決め打ちで出力するようにすればよいでしょう。
> X-XSS-Protection: 1; mode=block
体系的に学ぶ 安全なWebアプリケーションの作り方 第2版
徳丸本では決め打ちでX-XSS-Protectionを出力するように記載されていますが、MDN Web Docsによると、少なくともChrome、EdgeはXSSフィルタが削除されています(引用に記載されているように、FirefoxはそもそもXSSフィルタを実装していません)。
これはXSSフィルタをバイパスする方法が多数存在し、XSSフィルタ自体が別のセキュリティ上の問題を引き起すことすらあるからです。
結論としては、X-XSS-ProtectionはCSPに対応していない古いブラウザでは一部有効なものの、あえて指定するメリットは薄そうです。
このような議論の結果、本書執筆時点においては、多くのWebブラウザでXSSフィルタ機能を削除するかデフォルト設定を無効とするかのどちらかの対応が取られています。
Webブラウザセキュリティ Webアプリケーションの安全性を支える仕組みを整理する
筆者個人の意見を述べると、「根本的な対策であるアプリケーション側でのXSS対策を十全にした上で、XSSフィルタをオフにするという選択」が理想であると思います。オフにすることで、フィルタがもたらすUXSSや情報窃取、あるいは単純な誤検出(False Positive)といった不確実性から自由になることができます。
ブラウザのXSSフィルタを利用した情報窃取攻撃 | www.mbsd.jp
Facebook、Microsoft(login.live.comのみ?)のように、少数ながらも「オフ」を実践している著名なサイトもあります。Facebookは単純な誤検出を嫌ってオフにしたわけではないようです。Homakov氏の記事によると、Facebookはフィルタ自体がもたらすセキュリティ上の問題を回避するために「オフ」の選択を行ったようです。