二重送信による防御
この節では、前章で説明した csrf token を用いた防御方法の変化形と、その危険性を説明します。 これは、OWASP CHEETSHEET の Naive Double-Submit Cookie Patternに相当するものです。
1. cookie の二重送信
この防御手法は、攻撃者が cookie を盗聴することができない、という前提を用いたものです。 従来の csrf token を用いた防御手法は、サーバー側のアプリケーションと、クライアント側のフォームにランダムな文字列を埋め込み、フォーム送信時に両者を比較することで検証を行っていました。 これは、以下の前提から成り立っています。
- トークンが改ざんされていないか検証するために 2 つ以上の情報源が必要
- トークンの情報源のうち、少なくとも一つは攻撃者が偽造、改ざんできない
- トークンの一つはリクエストに紐づいて無ければならない
- トークンを攻撃者は盗み見ることができない
たとえば、クライアント側にトークンを送信するだけで、サーバー側に保存しないと、クライアントから送信されたトークンが本物かどうかを確かめることができません。 あるいは、トークンの情報を二つとも攻撃者が捏造できると、攻撃者が偽造したトークンと攻撃者が偽造したトークンを検証するようなことになってしまいます。 また、トークンを攻撃者が盗み見ることができると、攻撃者は正規のリクエストであるかのように偽装できてしまいます。
一方で、従来の方法では、csrf token をサーバー側にも保存しなければいけないことで、HTTP のステートレス性が壊されてしまいます。(ログイン認証でもやってるじゃん、ということは見ないふりをします) まあ、フォームを検証するためだけに DB の機能を追加するのは少しイヤです。
そこで、クライアント側に二つの情報源を保存しつつ、そのうち一つは攻撃者が偽造、改ざんできないことを保証しつつ、盗聴できないようにしつつ、クライアント側にすべてを保存する方法が提案されました。
2. フォームと cookie に保存する
この方法が成り立つ理由を、具体的にどこに保存するかという情報と一緒に説明していきます。
まず、「トークンが改ざんされていないか検証するために 2 つ以上の情報源が必要」という点は満たされています。
次に、「トークンの情報源のうち、少なくとも一つは攻撃者が偽造、改ざんできない」という点です。これは、cookie が満たしています。cookie の設定オプションにhttponlyという項目があり、これをtrueにすると、JavaScript で cookie を操作できなくなります。すなわち、改ざんできません。
また、cookie には domain 属性と呼ばれる、どのドメインに紐づけるのかを指定できるオプションがありますが、違うドメインに紐づけた cookie を設定することはできません。つまり、トークンを偽造することができません。
最後に「トークンを攻撃者は盗み見ることができない」という点についてです。まずは cookie に保存するトークンですが、先ほどいった通りhttponlyというオプションをつければ、JavaScript から操作できません。つまり、ブラウザのことだけを考えれば盗聴はされません。
次に、form に保存するトークンについてですが、こちらは SOP により JavaScript で取得することができません。
以上により、この方法はうまく動きそうです。
3. 危険性を理解する
ところが、この方法はいくつかリスクがあります。 そのうち、cookie のドメイン属性に紐づいたリスクについて説明します。ドメイン属性のリスクの他には、スキームの差異の挙動を利用した中間者攻撃によるものがあります。
攻撃者は、攻撃対象のサイトと後半部分が共通しているドメインをなんらかの方法で取得またはコードの埋め込み方法を確保し、そのドメインの共通部分に紐づけた CSRF トークンをセットします。
たとえば、aaa.vpc-service.comが攻撃対象のドメインだとすると、bbb.vpc-service.comのドメインを取得し、そのドメインに置いたサイトを使ってvpc-service.comの cookie にトークンをセットします。そうして、フォームにも同じトークンを埋め込めば、サーバー側でのトークンの検証をパスすることができます。
cookie の samesite 属性もドメイン部分に関しては eTLD + 1 で判断しているため、セッション情報も送られてしまいます。
3.1. __Host- prefix ヘッダ
なお、__Host- prefix という機能を使えば対策できるでしょう。これは、cookie の名前の先頭につけると、domain属性を無効化するものです。
https://datatracker.ietf.org/doc/html/draft-west-cookie-prefixes-05#section-3.2
MDN のサイトを見る限りブラウザでサポートされていて、少し探した限りでは github で使われているのを見つけたので、実用化されているのではないでしょうか。 https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Set-Cookie#%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%83%BC%E3%81%AE%E4%BA%92%E6%8F%9B%E6%80%A7

3.2. Signed Double-Submit Cookie
OWASP CHEETSHEET で推奨されているのは、サーバー側しか知りえない値を用いてトークンに対して署名を行うことです。