21
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

0から学ぶセキュリティの基礎 ~XSS編~

21
Posted at

はじめに

前回はCSRFについて学んだが、その特徴として攻撃者は「ユーザーの認証情報を知らない」「ブラウザとサーバーの通信の中身も読めない」という点があった。
攻撃者にできるのは、ログイン済みのブラウザに、本人の意図しないリクエストを送らせることまでだった。

もちろんOWASPtop10に掲載されている攻撃方法は多彩であり、その中には
より直接的にデータを書き換えたりユーザーのブラウザの中で動く攻撃がある

今回はそのうちの一つXSSについてまとめ基本的なサイバーセキュリティの基礎知識を固めていきたい。

能動的攻撃・受動的攻撃

XSSの説明に移る前に二つの違いを明確にしておきたい。

受動的攻撃とは

攻撃者が罠を仕掛けユーザーがそれを踏むのを待つ攻撃だ
前回学んだCSRFもこれに分類される

例えば
攻撃者が自分のサイトにリクエストを送るコードを置いておく罠が挙げられる

<form action="https://example.com/password/change" method="POST">
  <input type="hidden" name="newPassword" value="attacker123">
</form>
<script>document.forms[0].submit()</script>

ユーザーがこのスクリプトの埋め込まれたページを開くだけでCookieをつけたリクエストなどが送られる。
認証情報を攻撃者は知らないまま本人の意図しないリクエストを遅らせることができる。

XSSはこちらに分類され後述する。

能動的攻撃とは

攻撃者がサーバーに直接リクエストを送る攻撃であり、そこにユーザー操作は介在しない。
入力欄やURLに細工した値を送り込み、サーバーがその値をコマンドの一部として実行してしまうことで成立してしまう攻撃だ。

SQLインジェクションはこちらに分類される。

能動的・受動的と分類できるがどちらも
データと命令が混ざると言い換えることでイメージが掴みやすいだろう。

XSSの概要

XSSとは悪意あるスクリプトを他のユーザーのブラウザで実行させる攻撃だ

昨今サイバー攻撃で頻繁に見る機会が増えているフィッシングメールを入り口に
ユーザーに罠のURLを踏ませるもしくは汚染されたページにアクセスさせることで成立する。

攻撃の流れ

  1. 攻撃者が、スクリプトを含むURLを作る、またはサイトの入力欄にスクリプトを書き込む
  2. ユーザーが、罠のURLを開く、または汚染されたページを見る
  3. サイトが、入力値をエスケープせずに画面へ出す
  4. ブラウザは、サイト本来のスクリプトと攻撃者のスクリプトを区別できず、どちらも実行する
  5. 攻撃者のスクリプトが、そのユーザーの権限で動く

※エスケープとは画面内で描画される<、>、 &、 "などの特別な意味を持つ文字を無害な文字列へ変換すること。
例えば<script>と画面に出してしまうとそのままスクリプトが動いてしまう。

XSS攻撃の種類

XSSのスクリプトを実行させる手法も多岐にわたる

反射型

攻撃者がスクリプトを含むURLを作りメールやSNSでユーザーが踏むことで成立する。

例

https://example.com/search?q=<script>悪意のあるコード</script>

格納型

コメント欄やプロフィール欄などで攻撃者が入力した内容がDBに保存される。
サイトがそれをエスケープしないまま描画しユーザーがアクセスした場合、ブラウザがスクリプトを実行し攻撃が成立する

例

<li>いい記事ですね<script>alert('XSS')</script></li>

DOM型

サイトのJavaScriptがURLなどから値を読み込みHTMLとして画面に挿入することで成立する

特に注意が必要だと感じる特徴があり、サーバーを通らずブラウザの中で完結するため、サーバー側のエスケープでは防げない。

例

https://example.com/#<img src=x onerror=alert('XSS')>

※このURLを開くとサイト側のコードが#以降の値を画面に挿入しonerrorが実行される。

反射型と格納型はサーバーが危険なHTMLを作って返すのに対し、DOM型はサーバーは普通のHTMLを作って返すだけ。

サーバー側のログにも残らないエスケープでも防げないDOM型が一番厄介だと感じた。

XSSに対する防御法

防御策は二点ある
原因を取り除くか、被害を抑えるかだ。
順に見ていこう

原因を取り除く方法

出力時のエスケープを徹底する

反射型や格納型では画面に描画されなければいいのでエスケープによる変換を徹底するだけで対応できる。

初めて知ったがそもそもReactなどのフレームワークは通常の書き方で自動エスケープが働くそうだ。

工夫が必要なのはDOM型で、JavaScriptが値を画面に入れる処理の経路を

データと命令で分けて書くことを意識しなければならない

例えばinnerHTMLをtextContentに書き換えて画面に入れる

// NG: 値をHTMLとして解釈する
element.innerHTML = name;
// OK: 値をただの文字として扱う
element.textContent = name;

name が <img src=x onerror=alert('XSS')> の場合、innerHTML ではタグが作られてスクリプトが動く。
textContent では、この文字列がそのまま画面に表示されるだけで、実行されない。

innerHTMLを例にとったがevalやdocument.writeのように値をコードとして解釈する処理いずれにおいても工夫が必要だ

Sanitizer API

同じく原因を除去するのがブラウザに標準で入っているサニタイズ機能だ

innerHTMLの代わりにsetHTML()を使うことで、スクリプトを実行できる部分を取り除き、残りのHTMLを挿入することができる

例として

// NG: 値をHTMLとして解釈する
element.innerHTML = userHtml;
// OK: 危険な部分を取り除いてから挿入する
element.setHTML(userHtml);

太字や画像タグなどを残し「HTMLを生かしたい」場合に使用できる。

※2026年10月末時点の各ブラウザの対応状況を把握しておく必要がある

Firefox: 148(2026年2月)から使える
Chrome、Edge: web.dev は146から対応
Safari: 未対応

対応していない場合ライブラリのDOMPurifyで代用できる。

被害を抑える方法

セキュリティに無知な自分も含めて、上記の防ぎ方を知らないないし設定し忘れることもあるだろう。
だからこそ多層的に防御して被害を抑える方法を組み込み攻撃者にできることを減らさなければならない。

HttpOnly Cookieを使う

CookieにHttpOnlyをつけると、JavaScriptからCookieを読み取れなくなる。XSSが成立しても、セッションIDなどのCookieを盗まれにくくなる。

Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax

ただし、スクリプト自体は動くため、画面の読み取りや、ユーザーの権限での操作は防げない。
前回のCSRFでの対策はあくまで「別サイトから来たリクエスト」に対する防御策だった。

CSPで実行できるスクリプトを制限する

CSP(Content Security Policy)は、実行を許可するスクリプトの出どころをサーバーが指定する仕組みだ。
セキュリティヘッダーにこう記述しよう

Content-Security-Policy: script-src 'self'

この設定では、自分のサイトから配信されたスクリプトだけが実行される。HTMLに直接書かれたスクリプトやイベント属性(onerror など)は、ブラウザが実行しない。エスケープ漏れがあっても、攻撃のスクリプトが動かない可能性がある。

HttpOnlyはCookieの窃取を防ぐがスクリプト操作自体は防げないという欠点があったり
CSPでの制限も厳しくすればするほど堅牢になるが、
外部サービス連携ごとの設定の手間や画面が壊れやすくなることとのトレードオフになっている。

あくまでこれらの対策は保険として考え、
原因を取り除くエスケープとサニタイズを本筋として捉えるのが重要だろう。

防御策のまとめ

分類 防御策 役割 注意点
原因 出力時のエスケープ 反射型・格納型で、値を無害な文字列に変換する Reactなどのフレームワークは、通常の書き方なら自動で行う
原因 安全な書き方(textContent など) DOM型で、値をただの文字として画面に入れる eval や document.write など、値をコードとして解釈する処理にも工夫が必要
原因 Sanitizer API(setHTML()) HTMLを生かしたいときに、スクリプトを実行できる部分を取り除いて挿入する 対応ブラウザが限られる。未対応ならDOMPurifyで代用する
被害を抑える HttpOnly Cookie Cookieの窃取を防ぐ スクリプトは動くため、画面の読み取りや、ユーザーの権限での操作は防げない
被害を抑える CSP 許可していないスクリプトの実行を止める 厳しくするほど堅牢だが、外部サービス連携ごとの設定の手間と、画面の壊れやすさとのトレードオフになる

重要なのは原因をサニタイズや安全な書き方およびエスケープで取り除くこと!
HttpOnlyとCSPは、取り除けなかったときのための多層防御として使う。

終わりに

セキュリティ対策は有名なところから少しずつ味見して学ぼう
次はSQLインジェクションを中心にまとめたい

参考文献

小林恭平・坂本陽 著、佐々木拓郎 監修『イラスト図解式 この一冊で全部わかるWeb技術の基本』SBクリエイティブ
平野昌士 著、はせがわようすけ・後藤つぐみ 監修『フロントエンド開発のためのセキュリティ入門 知らなかったでは済まされない脆弱性対策の必須知識』翔泳社

株式会社シンシア

株式会社xincereでは、実務未経験のエンジニアの方や学生エンジニアインターンを採用し一緒に働いています。
※ シンシアにおける働き方の様子はこちら

シンシアでは、年間100人程度の実務未経験の方が応募し技術面接を受けます。

21
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?