SSRでXSS対策が重要になる理由とエスケープ

SSRでXSS対策がより重要になる理由とテンプレートエスケープの関係

SSR(Server Side Rendering)を採用すると、パフォーマンスやSEOは改善しやすくなります。しかし同時に、セキュリティ面では注意すべき点が増えます。特にXSS(クロスサイトスクリプティング)対策は、SPAより重要度が上がります。

理由は単純です。SSRではサーバがHTMLを直接生成し、そのままブラウザに送るからです。つまり、サーバが一度でも危険な文字列をHTMLとして出力すれば、その瞬間に攻撃コードが実行されます。

XSSとは何が起きている攻撃なのか

XSSは「ユーザー入力がHTMLとして解釈される」ことで成立します。たとえば、掲示板のコメント欄に次のような内容が投稿されたとします。

<script>alert('XSS')</script>

これをそのまま表示すると、ブラウザは文字列ではなくJavaScriptとして実行します。ポップアップ程度なら軽微ですが、実際にはCookieの送信やログイン情報の窃取に使われます。

重要なのは、XSSは特別なハッキング技術ではないという点です。「表示処理のミス」そのものが攻撃になります。

なぜSSRの方が危険度が上がるのか

SPAでもXSSは発生しますが、SSRでは被害範囲が広がります。

SSRでは、サーバが次のような処理をします。

  • DBからデータ取得
  • テンプレートに埋め込み
  • HTMLとして返却

このときテンプレートが安全でなければ、全ユーザーに対して攻撃コードを配信する状態になります。いわゆる「永続型XSS」です。

一度DBに攻撃コードが保存されると、ページを開いた全員のブラウザで実行されます。検索エンジンのクローラも例外ではありません。

テンプレートエスケープとは何か

XSS対策の基本は「エスケープ」です。エスケープとは、HTMLとして意味を持つ文字を単なる文字列に変換することです。

文字 エスケープ後
< <
> >
" "
& &

これにより、ブラウザはスクリプトではなくテキストとして扱います。

たとえば次の表示処理を考えます。

<p>{{ comment }}</p>

ここでテンプレートエンジンが自動エスケープを行えば安全ですが、無効化すると危険になります。

危険なパターン:エスケープ無効化

多くのテンプレートエンジンには「生HTML出力」の機能があります。

<p>{{{ comment }}}</p>

これは便利ですが、ユーザー入力に対して使うとXSSになります。実務では「改行を反映したい」「リンクを有効にしたい」といった理由で使われがちです。

ここが典型的な侵入口です。

JavaScript埋め込み時の落とし穴

SSRでは、サーバから取得したデータをJavaScript変数として埋め込むことがあります。

<script>
  const userName = "{{ user.name }}";
</script>

このとき、次の入力があると問題が起きます。

"; alert(1); //

結果のHTMLはこうなります。

<script>
  const userName = ""; alert(1); //";
</script>

これはエスケープしていても発生することがあります。HTMLエスケープとJavaScriptエスケープは別物だからです。

なぜテンプレートエンジン任せでは不十分か

多くのフレームワークは自動エスケープを備えています。しかしそれは「HTML本文として出力する場合」に限られます。

次の場所では別の対策が必要です。

  • JavaScript内
  • URLパラメータ
  • 属性値
  • JSON埋め込み

つまり、出力コンテキストごとに対策が変わります。ここを誤解すると、エスケープしているのにXSSが発生します。

実務で起きやすい事故

実際によくあるケースがあります。

  • 管理画面だから安全と思い込む
  • Markdownレンダラを信頼する
  • WYSIWYGエディタの出力をそのまま表示

特に「管理者しか触れないページ」でのXSSは深刻です。管理者の権限で外部スクリプトを読み込まれると、全ユーザーへの攻撃に発展します。

追加対策:CSP(Content Security Policy)

エスケープに加え、CSPの導入が有効です。

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

これにより、外部スクリプトの読み込みやインラインスクリプト実行を制限できます。完全防御ではありませんが、被害を大きく減らせます。

まとめ

SSRでXSS対策が重要になるのは、HTML生成の責任がサーバに集中するためです。ユーザー入力が一度でもHTMLとして出力されると、攻撃コードを配布する形になります。

重要なのは「エスケープする」ではなく、どこに出力するかで対策を変えることです。HTML本文、属性、JavaScript、URLでは安全な方法が異なります。

SSRは高速で扱いやすい仕組みですが、表示処理がそのままセキュリティ境界になります。テンプレートの1行が防御線になることを意識して設計すると、後からの修正が大幅に減ります。