Webアプリケーションのセキュリティ:XSSとCSRF対策
Webアプリケーションのセキュリティは、ユーザーの信頼を得てビジネスを継続していく上で不可欠です。数ある脆弱性の中でも、クロスサイトスクリプティング(XSS)とクロスサイトリクエストフォージェリ(CSRF)は、比較的容易に悪用されやすく、深刻な被害をもたらす可能性があります。本稿では、これらの脆弱性のメカニズムを解説し、効果的な対策方法を網羅的に説明します。
クロスサイトスクリプティング(XSS)
XSSは、攻撃者が悪意のあるスクリプトをWebサイトに埋め込み、それを閲覧した他のユーザーのブラウザ上で実行させる攻撃です。これにより、ユーザーのセッション情報(Cookieなど)を盗んだり、偽のログインページを表示して認証情報を詐取したり、Webサイトのコンテンツを改ざんしたりするなどの被害が発生します。
XSSの種類
- Stored XSS(保存型XSS):攻撃者が入力したスクリプトが、Webサイトのデータベースなどに保存され、他のユーザーがそのページを閲覧した際に実行されるタイプです。掲示板やコメント欄など、ユーザーからの入力を保存する機能を持つWebサイトで発生しやすいです。
- Reflected XSS(反射型XSS):攻撃者が作成したURLに悪意のあるスクリプトを含ませ、ユーザーにそのURLをクリックさせることで、スクリプトがユーザーのブラウザ上で実行されるタイプです。検索結果ページやエラーメッセージなど、ユーザーからの入力をURLに含めて表示する機能を持つWebサイトで発生しやすいです。
- DOM-based XSS:サーバー側の処理ではなく、クライアント側のJavaScriptが不正に実行されることで発生するXSSです。JavaScriptがユーザーの入力を適切に処理せずにDOM(Document Object Model)を操作する際に脆弱性が生じます。
XSS対策
-
入力値のサニタイズ(無害化):ユーザーからの入力値に含まれる可能性のあるHTMLタグやJavaScriptコードを、そのまま表示せずに無害な文字列に置換または削除します。
-
HTMLエンティティへのエスケープ:
<を<、>を>のように変換します。 -
特定の危険な文字の除去:
"、'、`、(、)などを削除またはエスケープします。
-
HTMLエンティティへのエスケープ:
-
出力値のエスケープ:HTML、JavaScript、URLなど、表示されるコンテキストに応じて適切なエスケープ処理を行います。
- HTMLコンテキストでは、HTMLエンティティにエスケープします。
-
JavaScriptコンテキストでは、JavaScriptのエスケープシーケンス(例:
xHH、uHHHH)にエスケープします。 - URLコンテキストでは、URLエンコーディングを行います。
-
Content Security Policy (CSP) の導入:Webサイトが読み込むリソース(スクリプト、スタイルシート、画像など)のドメインを制限することで、不正なスクリプトの実行を防ぎます。
-
script-srcディレクティブで、実行を許可するスクリプトのソースを指定します。 -
default-srcディレクティブで、デフォルトのポリシーを設定します。
-
- HTTPOnly属性付きCookieの使用:JavaScriptからのCookieへのアクセスを禁止することで、XSSによるセッションハイジャックのリスクを軽減します。
- X-XSS-Protectionヘッダーの使用:一部のブラウザでは、XSS攻撃を検知してブロックする機能が提供されており、このヘッダーを有効にすることでその機能を利用できます。
クロスサイトリクエストフォージェリ(CSRF)
CSRFは、ユーザーが意図しないリクエストをWebサイトに送信させる攻撃です。攻撃者は、ユーザーがログインしている状態のWebサイトに対して、ユーザーの意思とは関係なく、例えば「パスワード変更」や「商品購入」などの操作を実行させます。
CSRFのメカニズム
Webサイトでは、ユーザー認証のためにセッションCookieを利用するのが一般的です。ユーザーがWebサイトにログインすると、ブラウザはセッションCookieを保持します。CSRF攻撃では、攻撃者は悪意のあるWebページやメールを作成し、その中にターゲットのWebサイトへのリクエストを仕込みます。ユーザーがそのページを閲覧したり、メール内のリンクをクリックしたりすると、ブラウザは自動的にセッションCookieを添付してリクエストを送信してしまうため、ユーザーが意図しない操作が実行されてしまいます。
CSRF対策
-
CSRFトークン(Synchronizer Token Pattern):
- サーバー側は、ユーザーごとにランダムな秘密のトークンを生成し、セッションに保存します。
- このトークンは、フォームのhiddenフィールドなどに埋め込まれて、クライアント(ブラウザ)に送信されます。
- ユーザーがフォームを送信する際、このトークンも一緒にサーバーに送信されます。
- サーバー側は、送信されてきたトークンがセッションに保存されているトークンと一致するかどうかを確認します。一致しない場合は、CSRF攻撃とみなし、リクエストを拒否します。
-
SameSite Cookie属性:
-
HTTPヘッダーの
Set-CookieにSameSite属性を指定することで、Cookieがクロスサイトリクエストで送信される際の挙動を制御できます。 -
SameSite=Strict:クロスサイトリクエストではCookieは一切送信されません。最も安全ですが、一部のナビゲーションが阻害される可能性があります。 -
SameSite=Lax:ナビゲーションGETリクエスト(リンククリックなど)ではCookieが送信されますが、POSTリクエストなどでは送信されません。一般的な設定として推奨されます。 -
SameSite=None:クロスサイトリクエストでもCookieが送信されます。この場合、Secure属性(HTTPS接続時のみCookieを送信)も併せて指定する必要があります。
-
HTTPヘッダーの
-
Refererヘッダーの検証(補助的):
-
リクエスト元のドメインが、本来のWebサイトのドメインと一致するかどうかを
Refererヘッダーで検証する方法もあります。 -
ただし、
Refererヘッダーはブラウザやネットワーク環境によって送信されない場合や、偽装される可能性があるため、これ単体での対策は不十分です。CSRFトークンなどの他の対策と組み合わせるべきです。
-
リクエスト元のドメインが、本来のWebサイトのドメインと一致するかどうかを
-
カスタムヘッダーの使用:
-
POSTリクエストに、サーバー側でしか生成できないカスタムヘッダー(例:
X-Requested-With: XMLHttpRequest)を付加し、そのヘッダーの存在を確認する方法もあります。 - これは、JavaScriptからのみ付与できるヘッダーであるため、CSRF攻撃による不正なリクエストを検知するのに役立ちます。
-
POSTリクエストに、サーバー側でしか生成できないカスタムヘッダー(例:
まとめ
Webアプリケーションのセキュリティにおいて、XSSとCSRFは代表的な脆弱性であり、その対策は開発者にとって必須の知識です。XSSに対しては、入力値・出力値の適切なエスケープ処理、CSPの導入、HTTPOnly属性付きCookieの使用などが有効です。CSRFに対しては、CSRFトークンの実装、SameSite Cookie属性の活用が強力な防御策となります。これらの対策を単独で適用するのではなく、複数組み合わせることで、より堅牢なセキュリティ体制を構築することが重要です。また、脆弱性診断ツールや定期的なコードレビューを実施し、常に最新のセキュリティ情報を把握することも、攻撃からWebアプリケーションを守る上で不可欠です。
