タイトルなし
たまにはネットランナーらしい話題でも…
反射型はよく見る
XSSとはCross Site Scriptingの略称で、ウェブサイト上で第三者の用意したスクリプトを実行することです。これは3つに大別され、それぞれスクリプトが正規のサーバーのデータベースなどに保存される格納型、javascriptでDOMを書き換える際に実行されるDOM-Based、urlのパラメータに不正な文字列を仕込む反射型と呼ばれます。
格納型は多くのユーザーに対してスクリプトがロードされやすいため行われると厄介ですが、バックエンドはほとんどの場合フレームワークによって作られる(≒脆弱性の有無がすでにある程度検証されている)ため、格納型を機械的に検知できる場合は極めて少ないです。
DOM-Basedと反射型のXSS脆弱性は共にフロントエンド(しばしばフレームワーク準拠ではなくスクラッチされる)の実装の不備によって生まれますが、DOM-Basedはなぜかあまり見かけません。反射型をしばしば見かけます。最近はあまりよくないことをしているサイトと某大学のホームページで発見しました。あたいはこの脆弱性を大学に報告するつもりです。
反射型で何をされるの?
javascriptでできることは何でもできますし、Same originなので第三者ではなくそのサイトのスクリプトとして扱われてしまいます。 javascriptでドキュメント全体を書き換えて、フィッシング詐欺の画面を構築できます。スパムメールから不正なスクリプト付きのurlを踏ませるパターンが多いかと思われます。金融機関からのメールを装って、金融機関のサイトをコピーしたフィッシングサイトに誘導し、ログイン情報やカード情報を抜き取るといったことができます。ブラウザやパスワード管理ツールの自動入力があるとスムーズに入力できてしまいます。
反射型XSS脆弱性が生まれる原因
たとえばurlに検索用のパラメータが使われていて、そこのバリデーションが不十分だったりすると、その検索文字列をサイトに表示するときにHTML要素を挿入されてしまいます。これが反射型XSSです。scriptタグなどは簡単に思いついて対策できるかと思いますが、javascriptを実行できるタグはscriptタグだけではありません。某大学のホームページでは、ログインセッションが切れたことを知らせるメッセージをurlのパラメータに載せており、それをリクエストする際にバックエンドでiframeタグを除去できていなかったために反射型XSSを実行できるようになっていました。
対策
スクラッチしない
全てを把握して自力で以下の対策をするのは骨が折れるため、フレームワークに付随しているバリデーターなどを使って対策するといいです。場合分けが多岐にわたるので、その労力はこうして外注しましょう。
ここから先は書く楽しみのない手続き的な文章であるため、見出しを除きGeminiに書いてもらいました。
nonceを使う
Content Security Policy (CSP) の script-src ディレクティブで nonce を使用する方法も有効な対策です。これは、サーバーが生成したランダムな文字列(nonce)をHTMLのscriptタグに付与し、同じ値をレスポンスヘッダーにも含めることで、信頼できるスクリプトのみを実行させる仕組みです。
nonceを利用した対策の流れ
サーバーサイドでのnonce生成: ユーザーからのリクエストごとに、暗号学的に安全なランダムな文字列を生成します。この文字列が「nonce」となります。
レスポンスヘッダーへの設定: 生成したnonceを
Content-Security-Policyヘッダーに含めてクライアントに送信します。 (例:Content-Security-Policy: script-src 'nonce-xxxxxxxxxxxx')HTMLへの埋め込み: サーバーサイドでHTMLを生成する際に、許可したいscriptタグに同じnonce値を
nonce属性として追加します。 (例:<script nonce="xxxxxxxxxxxx"> ... </script>)
なぜ有効なのか
この設定により、ブラウザはContent-Security-Policyヘッダーで指定されたnonce値を持つscriptタグのみを実行します。攻撃者がURLパラメータなどを通じて不正なscriptタグ(例: <script>alert('XSS')</script>)を挿入しようとしても、そのスクリプトには正しいnonce値が含まれていないため、ブラウザによって実行がブロックされます。
nonceはリクエストごとに変化するため、攻撃者が事前に値を予測することは極めて困難です。これにより、たとえHTML内にスクリプトを注入できる脆弱性が存在したとしても、その実行を防ぐことができます。
入力値のサニタイズと出力値のエスケープ
根本的な対策として、ユーザーからの入力値を適切に処理することが重要です。
サニタイズ: サーバーサイドで受け取った入力値から、スクリプトとして解釈されうる危険な文字列(
<,>,",'など)を無害な文字列に置き換えるか、除去します。エスケープ: データベースなどから取得した文字列をHTMLに出力する際に、HTMLタグとして解釈されないよう、特殊文字をHTMLエンティティ(例:
<を<に変換)に変換します。
これらの処理を徹底することで、仮に不正な文字列が入力されても、単なる文字列として表示されるだけで、スクリプトとして実行されることを防ぎます。多くのウェブフレームワークには、これらの処理を自動的に行う機能(例:テンプレートエンジンの自動エスケープ)が備わっているため、積極的に活用することが推奨されます。 ↑ あたいと同じこと言ってる! 楽しくないことはフレームワークに任せようね!