【入門編】Cross-Site Request Forgery (CSRF) 対策としてのSameSite属性とトークン – アプリケーションセキュリティ & 安全な開発防御ガイド

CSRFという「勝手に鍵を開けられる」脅威から、あなたのWebサイトを守り抜く方法

こんにちは。現場で泥臭くインシデントと戦い続けているセキュリティエンジニアです。

今日は、Web開発を始めたばかりの方なら一度は耳にするであろう「CSRF(クロスサイト・リクエスト・フォージェリ)」についてお話しします。名前は難しそうですが、仕組みを理解すれば怖くありません。

「Webサイトにログインしている状態で、知らないうちに勝手に操作をさせられていた…」なんて事態を防ぐための、最も実戦的な防衛術を解説します。

—

1. CSRF(クロスサイト・リクエスト・フォージェリ)って何?

CSRFを一言で言うと、「あなたのふりをして、悪意ある第三者がWebサイトを操作する攻撃」です。

これを身近な例で例えてみましょう。
あなたは「オートロックのマンション」に住んでいて、鍵(Cookie)を持っています。あなたはいつも鍵を鍵穴に差し込んでいるので、マンションの管理人はあなたを「住人だ」と信頼してドアを開けてくれますよね。

ところが、もし泥棒があなたの背後に隠れていて、あなたがドアを開けた瞬間に、あなたに紛れてこっそり部屋に入り込んだらどうなるでしょう?管理人は「住人(あなた)と一緒にいるから大丈夫だろう」と油断して、泥棒まで通してしまいます。

これがCSRFの正体です。ブラウザは、たとえ悪意のあるサイトからの依頼であっても、あなたがそのサイトにログイン中なら「この人はログイン済みだから、この操作は本人の意思に違いない」と信じて、自動的に鍵(Cookie)を添えてリクエストを送ってしまうのです。

—

2. 第一の防壁:Cookieの「SameSite属性」

まず最初に行うべきは、ブラウザへの「指示」です。Cookieをセットするときに、SameSiteという属性を適切に設定するだけで、多くの攻撃を未然に防げます。

これは、「この鍵(Cookie)は、私のマンションのドアを開けるとき以外には絶対に使わないでね!」とブラウザに言い聞かせる設定です。

推奨設定:SameSite=Lax

現在はほとんどのブラウザでこれがデフォルトになっていますが、改めて確認しましょう。

// サーバーサイドでのCookie設定例(Node.js/Expressの例)
res.cookie(‘session_id’, ‘あなたの秘密のトークン’, {
httpOnly: true, // JavaScriptからCookieを盗まれないようにする
secure: true, // HTTPS通信でのみ送信する
sameSite: ‘Lax’ // ここが重要!外部サイトからのリンク遷移など「安全な」リクエストのみCookieを送信する
});

  • Strict: 自分のサイト内からのリンクでしかCookieを送りません。非常に安全ですが、外部サイトからのリンクでログイン状態が維持されず不便なことがあります。
  • Lax: 基本的に自分のサイト内でのみ送信しますが、ユーザーが直接リンクをクリックしてサイトに来た場合は特別に許可します。今のWebサイトのスタンダードはこれです。

—

3. 第二の防壁:Anti-CSRFトークンという「合言葉」

SameSite属性は強力ですが、万が一のすり抜けや古いブラウザへの対応を考え、もう一段階の防御を敷くのがプロの流儀です。それが「Anti-CSRFトークン」です。

先ほどのマンションの例で言えば、ドアを開けるたびに「合言葉」を要求するようなものです。

1. サイト側がフォームを表示する際、ランダムで複雑な合言葉(トークン)を隠しフィールドとして発行します。
2. ユーザーが「送信」ボタンを押すと、そのトークンも一緒にサーバーへ送られます。
3. サーバーは、届いたトークンが「さっき自分が発行したものと一致するか」を確認します。

攻撃者はあなたのサイトの「合言葉」を知ることはできないため、たとえ勝手にリクエストを送っても、サーバー側で「合言葉が違うな、怪しい!」と弾くことができるのです。

実装のイメージ(HTMLフォーム)




サーバー側では、このcsrf_tokenがセッション情報と一致しているかを必ずチェックするようにしてください。

—

最後に:完璧な防御なんて存在しない

セキュリティの世界では、「1つの対策だけで全てを守り切る」ことはできません。だからこそ、私たちは多重防御(Defense in Depth)を考えます。

1. SameSite属性でブラウザの自動的なCookie送信を制限する。
2. Anti-CSRFトークンで、リクエストの正当性を二重にチェックする。
3. HTTPSを必須にする(通信の盗聴や改ざんを防ぐ基本中の基本です)。

新人の皆さんがまず意識すべきは、「自分の書いたコードが、ブラウザにどういう挙動をさせているか」を想像することです。

セキュリティ対策は、面倒な作業ではなく、ユーザーの信頼を守るための「おもてなし」です。一歩ずつ、着実に実装していきましょう。何か不安なことがあれば、いつでも相談してくださいね。応援しています!

コメント

タイトルとURLをコピーしました