うつろい EC — 商品ページにはカスタマーレビュー機能がある。投稿されたレビューは保存され、その商品ページを開く全ユーザに表示される。
しかし、レビュー本文はエスケープされずにそのまま HTML に展開されている。Stored XSS の脆弱性。Reflected XSS と違って、一度投稿すれば永続的に、その商品ページを見る全ユーザのブラウザでペイロードが実行される。
うつろい EC — 商品ページにはカスタマーレビュー機能がある。投稿されたレビューは保存され、その商品ページを開く全ユーザに表示される。
しかし、レビュー本文はエスケープされずにそのまま HTML に展開されている。Stored XSS の脆弱性。Reflected XSS と違って、一度投稿すれば永続的に、その商品ページを見る全ユーザのブラウザでペイロードが実行される。
左の「攻撃者ビュー」でレビューを投稿し、右の「被害者ビュー」(別ユーザがこの商品ページを開いたときの挙動)で alert を発火させてください。
// レビュー保存(POST 時)
$reviews[] = [
'author' => $_POST['author'],
'body' => $_POST['body'] // ← エスケープなしで保存
];
save_to_db($reviews);
// レビュー表示(GET 時)
foreach ($reviews as $r) {
echo '<div class="review-body">' . $r['body'] . '</div>';
// ↑ DBの値をそのまま innerHTML
}
Reflected XSS と違い、ペイロードが永続化されるため、攻撃者が一度投稿するだけで以降この商品ページを開く全ユーザの環境で実行されます。被害範囲が桁違いに大きい。
レビュー本文は HTML 本文として展開されるので、Lab 01 と同じく <script> タグや <img onerror> が使えます。
左で投稿したレビューは右にも自動的に反映されます(同じデータベースを参照しているため)。被害者ビューは投稿フォームが見えないだけで、レビュー一覧の表示処理は同じです。
左の攻撃者ビューのレビュー本文に以下を投稿:
<script>alert('Stored XSS')</script>
「投稿」ボタンを押すと、両方の iframe にレビューが追加されます。被害者ビュー側でも HTML として展開されて alert が発火 → 「✓ Stored XSS 成立」が表示されます。
これは「攻撃者が一度投稿すれば、以降この商品ページを開く全ユーザのブラウザで実行される」ことの再現です。実際の事案では Cookie 窃取など、より深刻な攻撃が行われます(Lab 04 で詳述予定)。