結論(CSPでunsafe-evalを許可していない)
CSPでunsafe-evalを許可していないとは、Content Security Policyのスクリプト用ディレクティブ(script-src、なければdefault-src)に 'unsafe-eval' がない状態です。このとき、eval() や new Function()、文字列を渡した setTimeout() などの「文字列をコードとして実行する処理」がブロックされます。'unsafe-eval' を許可すると、注入された文字列がライブラリの評価処理を経由して実行される経路が残ります。nonceや 'strict-dynamic' では打ち消せないため、削除が必要です。
この記事のポイント
- 'unsafe-eval' は eval()、Function() コンストラクター、文字列を渡した setTimeout()/setInterval()/setImmediate() を許可します。
- eval系の判定には script-src、なければ default-src が使われ、script-src-elem は使われません。
- 'unsafe-inline' と違い、nonce・hash・'strict-dynamic' があっても 'unsafe-eval' は無効化されません。
- WebAssemblyだけが必要なら、より限定的な 'wasm-unsafe-eval' を使うのが最小権限です。
- セキュリティAIチェッカーはevalが許可されていれば×、どこかのポリシーで禁止されていれば○と判定し、△は使いません。
| 診断項目名 | CSPでunsafe-evalを許可していない |
|---|---|
| 項目ID | headers.csp-eval |
| 分類 | コンテンツセキュリティポリシー(CSP) |
| 重大度・配点の重み | 重要(high) 重み 3 |
| 関連する標準・ガイドライン | OWASP ASVS 5.0.0 V3.4.3(L2)、OWASP WSTG-CONF-12、IPA「安全なウェブサイトの作り方」1.5 XSS(保険的対策)、CWE-95(動的に評価されるコードの不適切な無害化)、CWE-79 |
CSPでunsafe-evalを許可していないとは
CSPでunsafe-evalを許可していないとは、Content Security Policy(CSP)のスクリプトに適用されるディレクティブで、'unsafe-eval' が許可されておらず、文字列をJavaScriptのコードとして実行する処理(eval系)がブロックされている状態のことです。
'unsafe-eval' は、次のような機能をCSPの下で許可するキーワードです。
eval()new Function()(Function() コンストラクター)- 文字列を渡した
setTimeout()/setInterval()など
CSPが有効でも 'unsafe-eval' があると、攻撃者がDOMに注入した文字列やURLのパラメーターが、ライブラリの評価処理を経由してコードとして実行される経路が残ります。
# 危険:eval 系の実行が許可されている
Content-Security-Policy: default-src 'self' 'unsafe-inline' 'unsafe-eval' https:
セキュリティAIチェッカーのこの項目は、スクリプトに適用される有効なディレクティブでeval系の実行が許可されていないかを確認します。インラインスクリプトの許可は「CSPでunsafe-inlineを許可していない」、CSPそのものの有無は「Content Security Policy」で確認します。
unsafe-evalは何を許可するのか(仕組み)
unsafe-evalが制御する処理
MDN(script-src)によれば、CSPがあり script-src に 'unsafe-eval' がない場合、次の処理はブロックされます。
| ブロックされる処理 | 例 |
|---|---|
eval() | eval('(' + text + ')') |
Function() コンストラクター | new Function('a', 'return a') |
文字列を渡した setTimeout()/setInterval()/setImmediate() | setTimeout("refreshNews()", 5000) |
WebAssemblyのコンパイル・実行は、別のキーワード 'wasm-unsafe-eval' で制御されます。'unsafe-eval' を指定すると、それも包含して許可されます。WebAssemblyだけが必要なら 'wasm-unsafe-eval' を使うのが最小権限です。
eval判定に使われるディレクティブ
eval系の判定には script-src が使われ、なければ default-src にフォールバックします。script-src-elem はeval判定には使われないと、CSP3に明記されています。したがって次のような違いがあります。
| CSP | evalの扱い |
|---|---|
default-src 'self' 'unsafe-eval' | 許可(default-srcにフォールバック) |
default-src 'self' 'unsafe-eval'; script-src 'self' | 不許可(script-srcが優先) |
frame-ancestors 'self' のみ | 許可(スクリプト無制限) |
nonceや 'strict-dynamic' では打ち消されない
'unsafe-inline' と違い、'unsafe-eval' はnonce・hash・'strict-dynamic' があっても無効化されません。strict CSPに移行したつもりでも、'unsafe-eval' が残っていればeval系の実行は許可されたままです。
Next.js公式ガイドでも、開発時(React開発版のデバッグ機能)だけ 'unsafe-eval' が必要で、本番では不要と説明されています。
unsafe-evalについてよくある誤解
- 「evalを使っていないから
'unsafe-eval'があっても無害」:自前のコードで使っていなくても、古いテンプレートライブラリやjQueryプラグインの一部は、文字列評価を内部で行います。許可しておくと、それらがDOM XSSの踏み台になります。 - 「
'unsafe-eval'を消すと必ず壊れる」:近年の主要フレームワークの本番ビルドはevalを必要としないものが多く、実際に何が使っているかはReport-Onlyで確認できます。
CSPでunsafe-evalを許可していないの診断基準(セキュリティAIチェッカー)
取得対象
- トップページの最終応答の
Content-Security-Policyヘッダー(カンマ区切りの複数ポリシーを個別に評価)を取得します。 - HTML内のmeta CSPも対象にします。
判定ロジック
- 各ポリシーのスクリプト用リストを、
script-src、なければdefault-srcとします。 - リストが存在しない(無制限)、または
'unsafe-eval'を含むポリシーは「evalを許可」とします。 - 複数のポリシーは全ポリシーの許可が必要なため、すべてのポリシーが許可している場合に×とします(1つでも禁止するポリシーがあれば、ブラウザはブロックします)。
'wasm-unsafe-eval'は'unsafe-eval'とは別のキーワードとして扱い、この項目では問題にしません。
判定条件
| 判定 | 条件 | 得点への影響 |
|---|---|---|
| × 要改善(fail) | 有効なスクリプト用リストに 'unsafe-eval' がある、または script-src・default-src がなくeval等が制限されていない | 0点 |
| ○ 問題なし(pass) | どこかのポリシーでeval系が禁止されている | 3点 |
| 対象外(na) | CSPがヘッダーにもmetaにもない | 採点に計上しない |
△(warn)は使いません。evalの許可は有無の二択であり、部分的な許可という状態がないためです。
判定の限界
- この項目は、ヘッダーとmetaに書かれた宣言だけを評価します。サイトのJavaScriptが実際にevalを使っているか、どのライブラリが文字列評価を行うかは、ソースコードの確認やReport-Onlyでの実測が必要です。
- 診断するのはトップページ1ページです。申請フォームや地図ページなど、ページ単位で別のCSPを送っている場合は、それらのページも個別に確認してください。
- Report-Only ヘッダーの
'unsafe-eval'は遮断に影響しないため評価しません。
自治体サイトでの判定例
| CSP | 判定 |
|---|---|
default-src 'self' 'unsafe-inline' 'unsafe-eval' https:(CMSの初期例をそのまま採用) | × |
upgrade-insecure-requests のみ | ×(スクリプト無制限) |
script-src 'self' 'wasm-unsafe-eval' | ○ |
script-src 'nonce-abc' 'strict-dynamic' | ○ |
unsafe-evalを許可しているとどんなリスクがあるか
- DOM XSSの成立:URLのハッシュやクエリの値を、テンプレート処理や
setTimeout(文字列)に渡す実装があると、攻撃者は細工したリンクで任意のコードを実行できます。CSPが'unsafe-eval'を許可していると、この経路をブラウザが止めません。 - CSPバイパスの足がかり:許可済みドメインにあるライブラリ(テンプレートエンジン系)を読み込ませ、そのライブラリが内部で文字列評価を行う「スクリプトガジェット」型のバイパスは、evalを禁止することで成立しにくくなります。
- 想定される被害:入力フォームの内容の窃取、偽画面の表示、管理画面を開いた職員のセッションでの不正操作など。
CSPを入れていても 'unsafe-eval' が残っていれば、文字列評価を行うライブラリが読み込まれている限り、これらの経路はブラウザ側で止まりません。
unsafe-evalを削除する方法(コード修正・Apache・nginx・IIS・Next.js)
削除までの手順
- Report-Onlyで使用箇所を特定:
'unsafe-eval'を外したポリシーをReport-Onlyで配信し、違反(effective-directive がscript-src、blocked-uri がeval)を収集します。CSP3では、evalのブロックは"eval"として報告されます。 - コード修正:
eval(json文字列)→JSON.parse()setTimeout("処理()", 1000)→setTimeout(処理, 1000)new Function(...)によるテンプレート → 事前コンパイル型のテンプレートやDOM APIに置き換え
- ライブラリ更新:古いjQueryプラグイン、テンプレートライブラリ、地図・グラフ部品を、CSP対応版へ更新します。
- WebAssemblyのみ必要なら
'wasm-unsafe-eval'に置き換えます。 - 強制ヘッダーから
'unsafe-eval'を削除します。
JavaScriptの修正例
// 変更前
var data = eval('(' + text + ')');
setTimeout("refreshNews()", 5000);
// 変更後
var data = JSON.parse(text);
setTimeout(refreshNews, 5000);
Apache(.htaccess)
移行期間は、現行の強制ポリシー('unsafe-eval' あり)を維持したまま、'unsafe-eval' を外した案をReport-Onlyで併走させると、表示を壊さずに影響を測れます。
<IfModule mod_headers.c>
# 現行(強制)
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-eval' https://www.googletagmanager.com; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
# 改善案(報告のみ)
Header always set Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' https://www.googletagmanager.com; object-src 'none'; base-uri 'self'; report-uri https://www.example.lg.jp/csp-report.php"
</IfModule>
違反がなくなったことを確認したら、強制側から 'unsafe-eval' を削除します。
<IfModule mod_headers.c>
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' https://www.googletagmanager.com; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
</IfModule>
既存の値に 'unsafe-eval' が含まれていないか、配下のディレクトリの .htaccess で上書きしていないかも確認してください。
nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always;
IIS
<add name="Content-Security-Policy" value="default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" />
Next.js(Vercel)
公式ガイドのとおり、'unsafe-eval' は process.env.NODE_ENV === 'development' のときだけ付与します。
const isDev = process.env.NODE_ENV === 'development';
const scriptSrc = `script-src 'self' 'nonce-${nonce}' 'strict-dynamic'${isDev ? " 'unsafe-eval'" : ''}`;
本番ビルドで 'unsafe-eval' が残っていないか、デプロイ後のレスポンスヘッダーで確認します。
CMS・外部サービスが要求する場合
CMSのテーマや外部ウィジェット(地図、チャット、アンケート)が 'unsafe-eval' を要求する場合は、ベンダーにCSP対応状況を確認します。どうしても必要な場合は、そのウィジェットを使うページだけに限定したポリシーにし、サイト全体には付けないようにします。
設定後の確認方法
curl -sI https://www.example.lg.jp/ | grep -i '^content-security-policy' | grep -io "'unsafe-eval'"
何も表示されなければ、強制ヘッダーに 'unsafe-eval' はありません。ブラウザでは、開発者ツールのコンソールに「Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source」が出ないことを主要ページで確認します。
よくある質問(FAQ)
CSPのunsafe-evalはなぜ危険なのですか?
文字列をJavaScriptのコードとして実行する機能を許可するためです。URLのハッシュやクエリの値をテンプレート処理や setTimeout(文字列) に渡す実装があると、細工したリンクで任意のコードが実行されるDOM XSSの経路が残ります。
自分のコードでevalを使っていなければ、'unsafe-eval' があっても無害ですか?
無害とは言えません。古いテンプレートライブラリやjQueryプラグインの一部は、内部で文字列評価を行います。許可しておくと、それらがDOM XSSやCSPバイパスの踏み台になります。
nonceや 'strict-dynamic' を使えば 'unsafe-eval' は無視されますか?
無視されません。nonce・hash・'strict-dynamic' で無効化されるのは 'unsafe-inline' であり、'unsafe-eval' はそれらがあっても有効なままです。削除する必要があります。
'unsafe-eval' を削除するとサイトが壊れませんか?
近年の主要フレームワークの本番ビルドはevalを必要としないものが多くあります。まず 'unsafe-eval' を外したポリシーをReport-Onlyで配信し、違反が出る箇所を特定して修正してから強制側を変えれば、表示を壊さずに移行できます。
WebAssemblyを使う場合も 'unsafe-eval' が必要ですか?
WebAssemblyのコンパイル・実行は別キーワードの 'wasm-unsafe-eval' で制御されます。WebAssemblyだけが必要なら 'wasm-unsafe-eval' を使います。セキュリティAIチェッカーは 'wasm-unsafe-eval' を問題にしません。
Next.jsで 'unsafe-eval' が必要と言われるのはなぜですか?
Next.js公式ガイドでは、開発時(React開発版のデバッグ機能)だけ 'unsafe-eval' が必要で、本番では不要と説明されています。process.env.NODE_ENV が development のときだけ付与するようにします。
この項目を含む127項目を、URLを入れるだけで無料診断します。