Buri Memo:

アイデアや気づきとかが雑に書き殴られる

CSRF攻撃の具体例と、SameSite(Cookie) での対策

Web アプリケーションの脆弱性、特に有名なものに3つあるが CSRF だけはピンと来なかった。色々調べて理解できたので具体的な例でまとめてみる。

  • XSS
  • SQL Injection
  • CSRF

CSRF の脆弱性

CSRF (Cross-Site Request Forgeries)脆弱性があると、利用しているサイトのユーザーに攻撃者が望む操作をさせることができる。

例えば、Aさんはあるショッピングサイトを利用しているとする。Aさんがパスワードを変更する場合はパスワード変更画面にアクセスしてそこで新しいパスワードを入力し変更ボタンを押す。

実際に行われることを細かく書くと以下のようになる。

  1. Aさんのブラウザでパスワード変更画面を開く(すでにログイン済み)
  2. 新しいパスワードを入力し、[変更する] を押す
  3. ショッピングサイトのサーバーに 新しいパスワード とAさんのリクエストであることを認証するため session token (cookie)が送られる
  4. session token が正しいことを確認した上で、DB に保存されているパスワードを cA3tB9FJSdZm に更新する 1

パスワード変更画面

攻撃例

CSRF攻撃の例

このパスワード変更画面に CSRF の脆弱性がある場合のことを考えてみる。
以下のような手順が成功すると、攻撃者がパスワードを任意の文字列に変更することができてしまう。

  1. 攻撃者は Aさんに攻撃用ページへのリンクと、クリックさせるような文章のメールを送る。
  2. 騙された Aさんがページを開く
  3. ページに設置されたスクリプトによって、ショッピングサイトへ「パスワードを "abc123" に変更する」リクエストが送信される。この時 Aさんのブラウザに保存された shop.jp の cookie が送信される。
  4. ショッピングサイトは session token を見て Aさんからの正規のリクエストだと判断しパスワード変更処理を行う

ここで [3] のスクリプトは以下のようなものである。ポイントはこのフォームが送信されるときに cookie (Aさんの持つ session token が含まれる)が勝手に送信されてしまうことだ。

ちなみに、Ajax(XMLHttpRequest)リクエストは行っていないので 同一オリジンポリシーによる制限は受けない

<form name="form1" action="https://shop.jp/me/password/change/" method="POST">
<input type="hidden" name="password" value="abc123">
</form>
<script>document.form1.submit()</script>

これにより、攻撃者は Aさんになりすましてリクエストを偽造することができる。攻撃者のサイト経由でショッピングサイトへのリクエストを偽造することから、Cross-Site Request Forgeries と呼ばれている。

対策

IPA では以下のような対策が紹介されている

  • リクエストは POST で行う(後述: SameSite=Lax にする場合は必須)
  • csrf トークンをフォームに含めて、サーバーでチェックする
  • リファラーが期待するドメインか(前述の例では shop.jp )をチェックする

安全なウェブサイトの作り方 - 1.6 CSRF(クロスサイト・リクエスト・フォージェリ) | 情報セキュリティ | IPA 独立行政法人 情報処理推進機構

サーバー側で行う対策だけでなく、補助的に cookie を利用したクライアントサイドの対策もある。(新しいフォームの実装時に CSRF 対策を忘れてしまった場合にリスクを減らせる)

cookie には SameSite という属性がある。Strict に設定すると cookie を発行したサイトからのリクエストでのみ送信される(それ以外では送信されない)。strict では Google の検索結果からアクセスする場合や、お気に入りからアクセスした最初のリクエスト時に cookie が送られないためログインされずユーザー的に不便になる。Lax では GET リクエストのみ送信するのでバランスがいい。

ちなみに、モダンなブラウザでは Lax がデフォルトで設定される。ただし、SSO 時などの認証フロー上で cookie 送信が必要になるケースがあるようで Chrome では cookie 発効後 2分間は設定されない。( Google Developers Japan: 2020 年 2 月の SameSite Cookie の変更: 知っておくべきこと

ただし、すべてのブラウザでデフォルトが Lax に設定されているわけではないので、明示的に設定するのが安全である。(MDN 情報では Firefox, Safari はデフォルトで設定しないらしい)

繰り返しになるがブラウザに依存した対策であり、クライアントの環境によっては使えないことがあり得る。さらに、session token を必要としない処理に関しては対策とならない(例えば匿名掲示板に爆破予告を書き込ませる)。そのため補助的に使うのが良さそう。

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Set-Cookie/SameSitedeveloper.mozilla.org



  1. 実際にはセキュリティ的な観点でパスワードをハッシュ化したものを保存する