flawopen.com/クロスサイトスクリプティング
クロスサイトスクリプティング
クロスサイトスクリプティングは、あるユーザーの文章をブラウザーが HTML や JavaScript として解析してしまう形でページに入れたとき、その文章がサイト自身の権限で他のユーザーのもとで実行されることで起こります。修正方法はどこでも同じで、値を書き込む場所に合わせて正確にエンコードし、HTML を許す必要があるまれな項目はサニタイズし、両方を Content Security Policy で補強することです。下で言語を選ぶと、正確な API、脆弱なコードと修正後のコード、CI で検出するルールを確認できます。
わかりやすい解説 (ELI5)
新聞は読者からの投書を自分の紙面に載せます。ある読者が、編集部からのお知らせとまったく同じ体裁の投書を送ってきました。「購読者の皆様、更新のためこの番号に電話してカード情報をお伝えください」。新聞と同じ書体で印刷されているので、読者は編集部が書いたものと同じように信じてしまいます。XSS とは、Web サイトが訪問者の文章を自分のページに刷り込み、ブラウザーがそれをサイト自身のコードとして、サイトがあなたのアカウントに持つ権限のまま実行してしまうことです。エスケープとは、すべての投書をはっきり区切られた引用枠の中に印刷し、どの投書も編集部のお知らせになりすませないようにすることです。
主要な概念と専門用語
- Cross-site scripting (CWE-79)
- Web ページが信頼できないデータをブラウザー向けに無害化せずに含めるため、そのデータ内のマークアップやスクリプトがページのオリジンで解析・実行され、DOM、cookie、API にアクセスできてしまいます。
- Reflected, stored and DOM-based XSS
- 反射型 XSS はリクエストのデータをそのままレスポンスに返し、多くの場合は細工したリンク経由で起こります。格納型 XSS は値を保存してすべての閲覧者に配信します。DOM ベースの XSS はサーバーを通らず、クライアント側の JavaScript が URL やストレージのデータを
innerHTMLなどのシンクにコピーします。 - Contextual output encoding
- 出力の文脈ごとに別のエンコードが必要です。要素のテキストと引用符付き属性には HTML エンティティ、スクリプト内では JavaScript の文字列エスケープ、URL パラメータにはパーセントエンコード、
hrefとsrcにはスキームの確認を使います。スクリプト内に置く値を HTML エンコードするだけでは不十分です。 - Sanitizing vs encoding
- エンコードはマークアップを文字として表示します。ユーザーが書式を送る必要がある場合は、許可リスト型のサニタイザー(DOMPurify、bleach の後継である nh3、OWASP Java HTML Sanitizer、HtmlSanitizer、ammonia)に HTML を通し、許可したタグを残してスクリプト、イベントハンドラー、
javascript:URL を取り除きます。 - Content Security Policy (CSP)
- どのスクリプトの実行を許すかをブラウザーに伝えるレスポンスヘッダーです。nonce ベースで
'unsafe-inline'を含まないscript-srcは、エンコードの不具合が紛れ込んでも注入されたスクリプトの大半を止め、require-trusted-types-for 'script'は DOM のシンクを固めます。
ステップ・バイ・ステップの攻撃フロー
信頼できない文字列がページに届く
検索語、プロフィールの項目、コメント、URL のフラグメント、API のレスポンスが、サーバーでのページ生成時やブラウザーでの更新時に取り込まれます。
正しいエンコードなしで書き込まれる
テンプレートのエスケープが無効になっている、値が HTML エスケープではカバーできないスクリプトや URL の文脈に入る、またはクライアントのコードがそれを innerHTML に代入します。無害なテスト値 <img src=x onerror=alert(1)> がそのまま残ります。
ブラウザーがそれをコードとして解析する
被害者のブラウザーが本物の <img> 要素を作って onerror を発火させるか、クリック時に javascript: のリンクを実行します。
スクリプトがサイトとして振る舞う
サイトのオリジンで実行されるため、ページを読み、被害者の cookie やトークンでサイトの API を呼び、ユーザーに見える内容を書き換え、本人になりすましてフォームを送信できます。
言語別の XSS 対策ガイド
エンジニアリング&システム堅牢化チェックリスト
- すべてのページを自動エスケープが有効なテンプレートエンジンでレンダリングし、例外(
|safe、Html.Raw、dangerouslySetInnerHTML、raw、unsafe { }、{!! !!})はすべてレビューする。 - 正確な文脈に合わせてエンコードする。HTML のテキストと引用符付き属性、JavaScript の文字列、URL パラメータを区別し、文字列連結で HTML や JavaScript を組み立てない。
- ユーザーが提供する HTML は、描画する箇所で保守されている許可リスト型サニタイザーに通す。
- ユーザーが提供する URL は、
href、src、ページ遷移に届く前にhttpとhttpsだけを許可する。 - nonce ベースで
'unsafe-inline'を含まない Content-Security-Policy とX-Content-Type-Options: nosniffを送る。 - セッショントークンは
localStorageではなく、HttpOnly、Secure、SameSite=Laxの cookie に保存する。