Create Branch

CSRF攻撃について

Published on 2025年1月16日

セキュリティ

どういうもの?

通常はログイン実行後、認証されているユーザー削除を実行することができる。
削除の実行処理は https://hirotobeat.vercel.app/blog/delete/1 でようなエンドポイントを実行されます。
何らかの方法で認証情報を第三者が取得して、削除実行時のリクエストに認証情報を加えることで第三者が不正なリクエストを実行することが可能です。

どのような仕組み不正にリクエストされるか?

  1. ブログ投稿画面にログインする。
  2. ログインしたら、セッションIDがブラウザ上のcookieに保存される。
  3. 攻撃の準備した不正なサイトにユーザーはアクセスする。
    • フィッシングメールなどでユーザーに悪意のあるリンクが送付されてくる。
  4. CooKieに保存されている認証情報をユーザーは保持しており、悪意のあるサイトに訪れると、
    削除実行のエンドポイントに対して認証情報が付与された状態でリクエスウトされて、削除処理の不正リクエストが成立する。

どのような条件かで行われる?

  1. 被害者が正規サイトで認証済みである
// 例:ブログサイトにログイン済み
// ブラウザには以下のようなCookieが保存されている
Cookie: sessionId=abc123;
  1. 攻撃者は正規サイトの実行したい処理のエンドポイントを知っている
// 攻撃サイトのコード例
<form action="<https://target-bank.com/transfer>" method="POST">
  <input type="hidden" name="to" value="attacker-account" />
  <input type="hidden" name="amount" value="1000000" />
</form>
<script>document.forms[0].submit();</script>

実行するためのエンドポイントが攻撃サイトに実装されており、リンクにアクセスした時点で、Javascriptが送信処理が実行されてリクエストが送信される。
1にもあるように、攻撃したいサービスの認証されている状態である必要があり、認証されいなければ不正リクエストは実行されるが、処理自体は失敗に終わる。

対策

Cookie SameSite属性にLaxを付与する

画面遷移する処理かつGETメソッドの実行する場合は、Cross Originからのリクエストは可能です。
Cross OrijinからのPOSTメソッドを実行することはできないです。

ただし、これはブラウザ上だけ保護されている状態です。
ターミナルからcurlを用いて、認証情報を付与していれば、POSTメソッドを実行することは可能であるため完全な対策とはならない。

CSRFTokenを用いた認証

1.初期アクセス/ログイン時

  • クライアントがログインリクエストを送信
  • サーバーがセッションを作成
  • サーバーが初期CSRFトークンを生成
  • トークンをセッションに保存
  • レスポンスヘッダー(X-CSRF-Token)でクライアントに返却

2. API リクエスト時

  • クライアントが保持しているトークンをX-CSRF-Tokenヘッダーに付与してリクエスト
  • サーバーがセッションに保存されているトークンと比較検証
  • 検証OK → 新しいトークンを生成
  • 新トークンをセッションに保存
  • レスポンスヘッダーで新トークンを返却

1リクエストごとにセッションには、ランダムに生成されてcsrfTokenが保持されている。
また、生成されるTokenはリクエストごとに更新されるため、csrfTokenを一致した値をしゅとくすることが不正アクセスすることが極めて難しい。

リポジトリ

repository :https://github.com/hirayamahiroto/front-security

ブランチ:https://github.com/hirayamahiroto/front-security/pull/3

実践 : 挙動を確認してみる。

Laxの指定しただけの場合

  1. 悪意のあるサイト(Cross Origin)での実行はLaxとなっているため、POSTメソッドは実行されない。
  2. ターミナル上で認証情報を付与したリクエスト送ることで送金が実行される。
curl 'http://localhost:3000/csrf/remit' \
  -X POST \
  -b 'connect.sid={※認証情報を付与する。}' \
  -d 'amount=500&message=これは偽サイトからのリクエストです'

SameSite=Lax設定だけでは完全な防御は難しいため、以下の追加対策が推奨されています。

  • CSRFトークンを用いた認証
    • リクエストごとにランダムな文字列を生成
    • サーバー側でトークンを検証
    • 正規のリクエストのみを許可

この方法により、認証情報を持っているだけでは不正リクエストを実行できなくなり、よりセキュアな実装が可能になります。

hirotobeat