本サイトは、快適にご利用いただくためにクッキー(Cookie)を使用しております。
Cookieの使用に同意いただける場合は「同意する」ボタンを押してください。
なお本サイトのCookie使用については、「個人情報保護方針」をご覧ください。

最新情報

2022.06.17

検出例から学ぶクロスサイトリクエストフォージェリ

はじめに

こんにちは。昨年度Web診断員デビューしました新人診断員の井餘田です。

突然ですが、みなさんの普段利用されているWebサイトはクロスサイトリクエストフォージェリ(以下CSRF)対策ができていますでしょうか。
CSRFについての話題だと、最近ではメジャーなブラウザで、CookieのSameSite属性がデフォルトでLaxに設定されるなど、ブラウザ側での対策も進んでいます。

しかし、ブラウザでの対策のみに頼り切るのは不適切です。というのもすべてのユーザがメジャーなブラウザを使用しているわけではないですし、ブラウザ側での対策のみではサーバ側に存在する脆弱性の根本的な解決になっていません。実際の被害は以前より少なくなると思われますが、サイト自体をセキュアなものにするためにはサーバ側での対策は依然として必須です。

筆者自身もWeb診断に携わるようになってから、いろいろなCSRFの検出パターンに遭遇してきました。筆者はまだまだ診断員歴が浅いですが、CSRFの検証には診断員の技量や引き出しが試されるような印象を受けています。

そこで今回は実際の検出例の中から、診断時や開発時に注意すべきCSRFの検出パターンを3つほど紹介したいと思います。
CSRFの名前ぐらいしか知らないという方や、CSRFについてある程度理解しているという方も、本記事を読めばより理解が深まり、新たな知見が得られるかもしれません。

CSRFとは

まずはおさらいです。
CSRFでは、まず攻撃者は罠サイトを用意します。ここで罠サイトには、アクセスすると脆弱なWebサイトへコミット機能(※)のHTTPリクエストが発生するように細工をしておきます。

脆弱なWebサイトのユーザである被害者が罠サイトにアクセスしてしまうと、被害者のブラウザから脆弱なWebサイトに対して、コミット機能のHTTPリクエストが送信されます。このとき送信されるHTTPリクエストにはブラウザに保存された脆弱なWebサイトで使用しているCookieの値も送信されます。その結果、被害者のアカウントで該当のコミット機能が実施されてしまいます。
slide1.png

これがCSRFの被害が発生する大まかな流れです。

(※)コミット機能
データの登録、変更、削除を伴う機能

対策

CSRFの一般的な対策は、コミット処理の前に、ユーザのセッションに紐づくトークンをWebアプリケーションが発行し、ユーザはコミット処理のリクエスト時に発行されたトークンを送信するようにします。このことで、サーバ側で正規のリクエストであるか検証を行うことが可能になります。

○対策済みのWebサイトでのリクエスト流れ図
slide2.png

○罠サイトにアクセスした場合のリクエスト流れ図(対策済み)

slide3.png

またこのほかにもHTTPヘッダを利用した対策や、前述のCookieの属性値を設定するといった緩和策もあります。

検出例

それでは、実際に弊社の診断で検出されたCSRFの事例について見ていきましょう。

・機能を示すパラメータを操作してトークン検証を回避するケース

Web サイトの構築方法や使用しているフレームワークによっては、Webサイトの機能を表すパラメータを送信しているサイトを見かけます。

例として商品の購入を行うような機能にて、商品選択後に確認画面が表示され、そこで確認を押した際に実際の購入が行われるようなWebサイトを想定します。

〇商品選択画面イメージ

window1.png

〇確認画面イメージ

window2.png

〇完了画面イメージ

window3.png

〇確認画面へのHTTPリクエスト


POST /purchase HTTP/1.1 Cookie: SESSION=4d2h58vpiqivu7tdumr8h2gepm ...(省略)... item_id=A&op=confirm

〇完了画面へのHTTPリクエスト(実際にコミットが行われるHTTPリクエスト)


POST /purchase HTTP/1.1 Cookie: SESSION=4d2h58vpiqivu7tdumr8h2gepm ...(省略)... token=L5iIEWYRifnXaMF2caQW6Ph4rx3cUHBWq6Irj1p5&op=complete

ここで確認画面へのHTTPリクエストに含まれるパラメータopを、完了画面へのHTTPリクエストで使用されている値である「complete」にして送信すると、購入が完了してしまうというケースがありました。

〇パラメータopを改変した確認画面へのHTTPリクエスト

POST /purchase HTTP/1.1 Cookie: SESSION=4d2h58vpiqivu7tdumr8h2gepm ...(省略)... item_id=A&op=complete

上記HTTPリクエストは通常の操作では発生することはありませんが、なぜかこのようなリクエストがサーバ側で処理されています。
完了画面へのHTTPリクエストにはCSRF対策トークンが付与されているため、一見対策していると思われましたが、この方法によってトークンの検証を回避されてしまいました。

Web診断は基本的にブラックボックスな環境で行われるため、このパラメータ操作によってコミット処理が実行されてしまう原因は明確ではありませんが、なんらかの実装不備でこのようにCSRFの攻撃が可能になってしまう場合があります。

筆者も診断員のトレーニング中にこのパターンの検出例をトレーナーの方から教えてもらった時はまさかと思いましたが、色々なWebサイトを診断するようになった後では、このようなケースは少なくないという印象をもっております。

・トークン不備のエラーが発生するもコミットが実行されるケース

診断時はCSRFトークンを完全に削除してリクエストを送信してみるというようなことも試します。先ほどと同じWebサイトを想定すると、以下のようにパラメータを削除してリクエストを送信してみる、というようなイメージです。

〇完了画面へのHTTPリクエスト

POST /purchase HTTP/1.1 Cookie: SESSION=gk4jp3tbdasrti5fkhblhpcilv ...(省略)... token=AeEHsWFCT1K8HTsyselMaoAT1ElHTz7Y4hpmnmpG&op=complete


〇トークンのパラメータを削除して送信するHTTPリクエスト

POST /purchase HTTP/1.1 Cookie: SESSION=gk4jp3tbdasrti5fkhblhpcilv ...(省略)... op=complete


このようなHTTPリクエストを送信した際、よくある挙動としてはトークンが不正であるためエラーページに遷移することが多いです。しかしここでエラーページが返されているから対策がされていると思いきや、購入履歴のページを参照すると商品が購入されているケースがあります。

上記の例はトークンの検証ロジック自体はあるけど、パラメータを完全に削除した場合に想定していない処理フローを通ってしまっている可能性や、トークンの検証前にデータのコミット処理が実行されてしまっていることなどが考えられます。

フレームワークを使用している場合はこのようなケースは発生しづらいと思われますが、CSRF対策トークンの生成、検証ロジックを独自実装している場合などは要注意です。

・リクエストボディ部がJSON形式のケース

CSRFはJSON形式のリクエストでも検出されることがあります。
例としてCSRF対策を実施していない、以下のような商品をお気に入り登録するリクエストを考えます。

〇CSRF対策を実施していないJSONを用いたHTTPリクエスト


POST /api/favorites/add Cookie: SESSION=0kj8pem1824iq21m6ge1edp96j Content-Type: application/json … { “item_id”:12 }



ここからは診断員目線(攻撃者目線)で、このリクエストで攻撃を行うことを考えます。

通常通り、上記リクエストの送信を行う罠サイトを作成すると一つ問題が発生します。
それはContent-Typeがapplication/jsonであるため、罠サイトからのリクエスト送信時にCORSプリフライトが発生してしまいます。CORSプリフライトが発生してしまうと、攻撃リクエストの送信にはサーバ側が適切なヘッダを返す必要があり、攻撃への障壁が一つ増えてしまいます。(この場合、サーバは適切なAccess-Control-Allow-Headersを返す必要があります)

ここで使えるテクニックとして、リクエストのContent-Typeをtext/plainとし、リクエストボディ部でJSONパラメータを送信するように罠サイトを作成します。

csrf.png

この罠サイトから送信されるリクエストは前述の通りContent-Typeがtext/plainで送信されます。サーバ側でContent-Typeを適切に検証している場合は、この攻撃リクエストは失敗しますが、この方法によって正常なリクエストと同様にボディ部JSONとして解釈されてしまい、コミット処理が完了してしまうケースがあります。この原因の一例としては、フレームワークの機能を利用せずに、HTTPリクエストのボディ部を直接JSONとしてパースするような処理を実施していることなどが考えられます。

ちなみに余談ですが、上記の罠サイト例ではJavaScriptのXMLHttpRequestを使用することによってボディ部にJSONパラメータを設定しましたが、通常のhtmlタグを使用してJSONパラメータを送信するテクニックも実はあります。こういう細かなところでも診断員の技量が図られるなあと日々痛感しております。

おわりに

本稿では実際に診断で検出されたCSRFの様々なパターンを紹介しました。

冒頭でも触れましたが、最近はブラウザ側での対策も進んでおり、もしかしたら数年後にはCSRFという脆弱性自体メジャーでなくなる日が来るかもしれません。しかし、Webサイトの機能によっては大きな被害に発展することも考えられるため、まだまだ対策必須な脆弱性であることは変わりありません。

本稿が皆様のCSRFへの理解の助けになれば幸いです。それでは~~