SaaS Product Team セキュアコーディングの啓蒙 第1回 (CSRF編)

はじめに

こんにちは!

株式会社ユーザベース BtoB SaaS Product Team(以下 Product Team)の下川・山室です。


ユーザベースの Product Team には、全社のセキュリティを担うチームとは別に、プロダクトセキュリティの底上げを担うセキュリティチーム、通称 Blue Team というチームがあります。

私たちはそのチームの一員として、日頃の開発業務に加えてユーザベースのプロダクトのセキュリティを横断的に向上するための活動を行なっています。

最近行なった取り組みとして、Product Team の全メンバーを対象に、やられアプリ(Bad Todo List)を用いたハンズオンセミナーを 7 月に開催しました。

そのときの様子をまとめたブログが以下になります。

徳丸さん作 Bad Todo List を使ったハンズオンを開催したよ(ご本人登場)


ハンズオンセミナーでは、様々な脆弱性の中から XSS にフォーカスを当てて解説を行いました。

しかしながら、セキュリティリスクの高い脆弱性は他にもたくさん存在します。

そこで、Blue Team では新たな取り組みとして、脆弱性のリスクや対策方法について継続的に記事にまとめ、Product Team 内の各開発チームで読み合わせを行なってもらう施策を実施することにしました。

チーム内でセキュリティについて詳しい人が知見を共有しながら読み合わせを行なうことで、チーム内のコミュニケーションの促進を図ったり、プロジェクトへ反映するための具体的な方法について議論してもらいたい、という狙いがあります。

また、Product Team で行なっている活動の様子を社外の方にご紹介する一環として、それらの記事をテックブログにも掲載していくことにしました!

このテックブログが ユーザベースに興味を持っていただくきっかけになればと思っています!


第 1 回目である今回は、CSRF の脆弱性について取り上げます!

CSRF とは?

概要

CSRF(Cross-Site Request Forgeries:クロスサイトリクエストフォージェリ) は、直訳すると「サイトを横断してリクエストを偽装する」となり、その名前の通り、罠サイト等から攻撃対象のサイトに偽装されたリクエストが送信され、そのリクエストが成功してしまうウェブアプリケーションの脆弱性です。

そして、その脆弱性を利用した攻撃を CSRF 攻撃といいます。

サーバ側で、飛んできたリクエストが正規のサイトから発行されたリクエストであるかを検証せずに処理してしまうことによって CSRF 攻撃が成立します。

発生件数は?

調べたところ、件数に関して明記されているものを見つけることはできなかったものの、IPA の資料によると CSRF による攻撃の届出は全体の 1% 未満(届出総数は18,198件 *)であるようで、多く発生しているわけではありません。

2023 年 4 ~ 6 月の 3ヶ月の脆弱性の届出件数の総数が 171 件なので、単純計算ではありますが直近 3 ヶ月で見ると CSRF による攻撃は発生しているかしていないか、くらいになると思われます。

※ 届出の受付開始の 2004 年 7 月 8 日から 2023 年 6 月の累計です。

発生時の影響範囲は?

攻撃成功時の影響範囲は多岐に渡ります。

共通して言えることは、悪意を持った人が正規のユーザーになりすまして、認証後のユーザーのみが利用可能な機能を利用するということです。

例えば、金銭処理が発生するようなサイト(インターネットバンキング)で攻撃が成立すると、攻撃を受けたユーザーの口座から別の口座に送金をされてしまったり、ユーザー情報から個人情報を盗まれたり、パスワードを変更されてしまったりと多くの被害を受ける可能性があります。

また、攻撃されたユーザーが管理者ユーザーだった場合、その管理者ユーザーの権限を悪用して他のユーザーに影響を及ぼすような影響範囲の広い攻撃を受ける可能性もあります。

CSRF 攻撃の具体的な方法

CSRF 攻撃の具体的な流れを説明します。

  1. 悪意を持った人が罠サイトを作成します。もしくは XSS 脆弱性のある攻撃対象のサイトに悪意のあるスクリプトを埋め込みます。

    罠ページの作成

  2. ユーザーは正規の方法(普段利用している方法)でウェブサイトにアクセスします。

    正規のログイン

  3. ログインに成功すると、ユーザーが利用しているブラウザの Cookie などにセッション情報等が保持されます。

    ※ CSRF 脆弱性においては、セッション情報がブラウザで保持される事自体が悪いわけではありません。

    セッションID等の保持

  4. メールや XSS 攻撃など何らかの手を使って、ユーザーを罠サイトに誘導します。

  5. ユーザーがセッション情報等を保持した状態でリンクをクリックしたりページを開いたりすると、ブラウザに保存されたセッション情報が使われて正規サイトのサーバに悪意のあるリクエストが送信されます。

    リクエストが成立してしまうと、CSRF 攻撃が成功となってしまいユーザーの意図しない操作(パスワード変更や送金 etc…)をされてしまいます。

    意図しないリクエスト

対策

CSRF は、偽装されたリクエストを通常どおり処理してしまうことによって生じる脆弱性であるため、サーバに送信されたリクエストが正規のものなのかどうかを識別できる仕組みを導入することによって対策できます。

それでは、具体的な対策方法を紹介します!

フォームにトークンを埋め込む

サーバがフォームの HTML を返す際、トークンとして、推測が不可能な値を value に持つ type 属性を「hidden」にした input タグを埋め込みます。

<form method="post" action="https://example.com/post">
  <input type="text" name="title"><br>
  <input type="text" name="body"><br>
  <input type="hidden" name="csrf_token" value="da39a3ee5e6b4b0d3255bfef95601890afd80709">
</form>

そして、このフォームからのリクエストを受け取ったサーバは、埋め込まれているトークンの値を検証し、リクエストが正規のものであるかどうかを判定します。

このトークンは、フォームの HTML を返却されたクライアントしか知り得ない情報であるため、偽装したリクエストを作成することはできなくなります。

パスワードの再入力を求める

重要な操作を実行する前にパスワードの再入力を求めることで、リクエストがユーザーの意図しているものかどうかを判別することができるようになります。

パスワードの再確認を実施することでよりセキュアにすることができますが、その一方で、たくさんの操作にパスワードの再入力を求めるようにしてしまうと、ユーザビリティを損なってしまう可能性があります。

Referer ヘッダを検証する

Referer ヘッダは、現在のページに遷移する直前に表示していたページの URL が記載されているヘッダです。

Referer: https://example.com

そのため、送られてきたリクエストに含まれる Referer ヘッダをサーバ側で検証することで、リクエストが正しい送信元から送られてきているかどうかを識別することができます。

ただし、ユーザーが Referer ヘッダを送信しないように設定していたり、プロキシサーバで Referer ヘッダを削除するようにしていたりする場合があるため、この対策は社内のシステムなど環境が特定できる場合に適しています。

カスタムヘッダを付与する

ブラウザは JavaScript の XMLHttpRequest や fetch を実行する際、リクエストの内容が一定の条件に該当すると、実際のリクエストを送信する前に、プリフライトリクエストをサーバに送信します。

プリフライトリクエストとは、リクエストが安全かどうかを確認するためにブラウザが自動的に送信する OPTIONS メソッドのリクエストです。

具体的には、プリフライトリクエストではリクエストに関する様々な情報がヘッダにセットされて送信されます。

Origin: https://example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header

このプリフライトリクエストに対して、サーバ側ではどういったリクエストであれば許可するかについての情報を返すようにします。

Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-allow-Headers: X-Custom-Header

ブラウザはこれらの情報を照合し、実際のリクエストが許可されているかどうかを判定します。

許可されていないと判定された場合、実際のリクエストが投げられることはありません。

カスタムヘッダを付与したリクエストは一定の条件に該当するため、プリフライトリクエストが送信されるようになります。

Origin ヘッダにはリクエスト元のオリジン(スキーム、ホスト名、ポート番号)が含まれるため、許可されていないオリジンからのリクエストは拒否されることになります。

保険的な対策

操作を通知する

CSRF への保険的な対策として、パスワードの変更など何か重要な操作が行われた際に、ユーザーに対してその操作が行われたことをSMSやメールで通知する方法もあります。

ただ、この場合は攻撃に対する対策というよりは攻撃されたことを検知できる仕組みなので CSRF の根本的対策にはなりません。

CSRF は、正規ではないリクエストにも関わらず Cookie に保存されている SessionId などの秘密情報が送信され、それによってサーバが正規のリクエストだと判断してしまうことによって生じる脆弱性です。

Cookie には SameSite 属性という Cookie の送信を制御するための属性があります。

これを Lax に設定することで、リクエストが同一サイトからの場合のみ Cookie が送信されるようになります。

Chrome ではデフォルトで Lax がセットされるようになっていますが、ブラウザによっては挙動が異なるため、明示的に指定しておくほうが良いです。

注意点として、SameSite 属性を Lax にした場合でも、GET メソッドの場合は Cookie が送信されるようになっています。

したがって、副作用を伴う処理では GET メソッドではなく処理に適したメソッドを使うようにしましょう。

まとめ

今回は CSRF について取り上げました!

CSRF はユーザー側の意識によって自身の被害を防ぐこともできますが、開発の時点で意識して対応していくべきことだと思います。

また、 XSS 脆弱性とも関わってくる部分もあるので、ウェブアプリケーション開発の際には意識をしていただけたらと思います。

We are Hiring!!

現在、ユーザベースの Product Team では、積極的に採用を行なっています!

私たちの会社やプロダクト、取り組みなどが少しでも気になった方は、ぜひ以下のリンクからチェックしてみてください!

Uzabase 採用情報

参考資料

Page top