XSS対策:出力エンコーディングとCSP
反射型、蓄積型、DOMベースのXSSを理解し、ユーザーが制御する出力をエスケープして、信頼できないデータでinnerHTMLを使わず、Content Security Policyヘッダーを追加します。
「XSS対策:出力エンコーディングとCSP」はCoddyKit上の無料Frontend Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはFrontend Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Frontend Academyコースには全4レッスンが含まれています。
XSSとは
Cross-Site Scriptingは、攻撃者が実行可能なJavaScriptをページに注入することで発生します。ブラウザはそのスクリプトを自分のオリジンの権限で実行するため、Cookieの窃取、セッションの乗っ取り、ページの改ざん、マルウェアへのリダイレクトなどにつながります。
XSSの3つの種類
Stored:悪意のあるスクリプトがDBに保存され、すべての訪問者に配信されます。Reflected:入力値がレスポンスにそのまま反映されます(?q=<script>...)。DOM-based:クライアント側のJSが信頼できないデータをDOMに書き込みます。
根本原因:信頼できないデータでのinnerHTML使用
ユーザーが制御する文字列をinnerHTML(またはv-html、dangerouslySetInnerHTML)で扱うことが、最大のXSS攻撃経路です。
// BAD: user input rendered as HTML
el.innerHTML = userComment; // attacker submits <img onerror=alert(1)>
// Vue equivalent:
<div v-html="userComment"></div> // same bug
// React equivalent:
<div dangerouslySetInnerHTML={{ __html: userComment }} /> // same bug出力エンコーディング(安全なデフォルト)
信頼できない文字列はHTMLではなくテキストとして扱います。React、Vue、Angular、Svelteはすべて、{value}の補間でデフォルトでこの動作をします。
// SAFE: text content, not HTML
el.textContent = userComment; // <script> shows as literal text
// React (auto-escaped):
<div>{userComment}</div>
// Vue (auto-escaped):
<div>{{ userComment }}</div>HTMLを描画する必要がある場合のサニタイズ
ユーザーのHTMLを実際に描画する必要がある場合(リッチテキストエディターなど)は、DOMPurifyでサニタイズしてください。正規表現によるサニタイザーを自作してはいけません。
import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(userHtml);
el.innerHTML = clean; // strips <script>, on* handlers, dangerous URLsURLの検証
hrefやsrcに指定するユーザー制御のURLは、javascript:スキームによってXSSを引き起こす可能性があります。
// BAD:
<a href={userUrl}>Click</a>
// attacker submits: javascript:alert(1)
// GOOD: whitelist protocols:
function safeUrl(url) {
if (!/^https?:\/\//.test(url) && !url.startsWith('/')) return '#';
return url;
}Content Security Policy(CSP)
CSPは、許可されるスクリプト、スタイル、画像などの読み込み元をブラウザに伝えるHTTPレスポンスヘッダーです。攻撃者がスクリプトを注入しても、ブラウザはその実行を拒否します。
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.trusted.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:Nonceを使った厳格なCSP
制御下にあるインラインスクリプトには、リクエストごとに異なるNonceを使用します。攻撃者が注入したスクリプトには一致するNonceがないため、実行されません。
// Server generates a random nonce per request:
const nonce = crypto.randomBytes(16).toString('base64');
res.setHeader('Content-Security-Policy', `script-src 'nonce-${nonce}' 'strict-dynamic'`);
// Inject into the HTML:
<script nonce="abc123">/* trusted inline code */</script>HttpOnly + Secure Cookie
セッションCookieにはHttpOnlyを設定し、JavaScriptから読み取れないようにします。XSSが発生しても、攻撃者はセッショントークンを取得できません。
Set-Cookie: session=abc; HttpOnly; Secure; SameSite=StrictSubresource Integrity(SRI)
CDN経由でサードパーティスクリプトを読み込む場合は、SRIを使用してコンテンツがハッシュと一致することを検証します。CDNが侵害されても、ハッシュ検証を破らずに悪意のあるスクリプトを配信することはできません。
<script
src="https://cdn.example.com/lib.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"
></script>Trusted Types(実験的)
Trusted Typesは(Chromiumベースの)ブラウザ機能で、危険なシンク(innerHTML)にTrusted Typeオブジェクトを渡すことを強制します。これにより、文字列を直接挿入できなくなります。
XSSのテスト
再表示されるすべてのテキスト入力に、<img src=x onerror=alert(1)>を挿入してみます。アラートが表示されたら、XSSの脆弱性があります。自動スキャンにはOWASP ZAPなどのツールを使用します。
確認問題
Reactの{userInput}はデフォルトで安全なのに、dangerouslySetInnerHTMLは安全ではないのはなぜでしょうか。
まとめ:XSSの防止
テキストのレンダリングをデフォルトにします(Reactの {x}、Vueの {{ x }} は安全です)。HTMLをレンダリングする場合はDOMPurifyでサニタイズします。URLプロトコルは許可リストで制限します。CSPヘッダー(nonceまたは'strict-dynamic'を使用)により、挿入されたスクリプトをブロックします。HttpOnly CookieによりJavaScriptからの盗難を防ぎます。CDNスクリプトにはSRIハッシュを使用します。一般的なペイロードで入力をテストします。
AI チューターと学ぶ HTML — 無料
ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。
- コース
- 41
- レッスン
- 163
よくある質問
「XSS対策:出力エンコーディングとCSP」レッスンは無料ですか?
はい。「XSS対策:出力エンコーディングとCSP」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Frontend Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Frontend Academyコースには全4レッスンが含まれています。
「XSS対策:出力エンコーディングとCSP」で何を学びますか?
反射型、蓄積型、DOMベースのXSSを理解し、ユーザーが制御する出力をエスケープして、信頼できないデータでinnerHTMLを使わず、Content Security Policyヘッダーを追加します。 ブラウザで直接実行するハンズオンコードでFrontend Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Frontend Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのFrontend Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「XSS対策:出力エンコーディングとCSP」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このFrontend Academyレッスンでコードを書いて実行できますか?
はい。すべてのFrontend Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- XSS対策:出力エンコーディングとCSP
- CSRF:SameSite Cookieとトークン
- Content Security Policy:nonceとhash
- フロントエンドからのOAuthフロー