脆弱性が蔓延し、絶えず増え続ける今日、ユーザーのセキュリティとプライバシーの保護は、これまで以上に重要視されています。脆弱性を見過ごせば、評価が失墜したり、高額な制裁金を科されたり、顧客や訪問者からの信頼を失ったりする可能性が高まります。

ウェブサイトやウェブアプリケーションは、常にマルウェアやスパムなどの攻撃の危険に晒されています。今回は、そんな攻撃の1つであるCSRF(クロスサイトリクエストフォージェリ)に焦点を当てます。CSRF攻撃は、気づかない間に発生する可能性があり、特に問題視されています。また悪意のある要求は正しい要求と区別が難しく、開発者やサイト運営者が発見しづらいというのも厄介です。

この記事で、CSRF攻撃の概要と仕組み、そして対策について学びましょう。

CSRF攻撃について動画での解説もご用意しています。

CSRF攻撃とは

クロスサイトリクエストフォージェリは、略してCSRFと呼ばれ、認証されたユーザーを騙し、知らぬ間に悪意のあるリクエストを送信して、意図しない処理が行われる実行させられてしまう攻撃です。

CSRF攻撃の仕組み(画像出典: Okta)
CSRF攻撃の仕組み(画像出典: Okta

通常、CSRF攻撃は、攻撃者が応答を受け取らないため、状態を変更するリクエストを工作します。例えば、レコードの削除、パスワードの変更、商品の購入、メッセージの送信などがその一例です。このような状態変更は、ユーザーが気づかない間に引き起こされる可能性があります。

悪意のあるユーザーのほとんどは、ソーシャルエンジニアリングを利用し、疑いを持たないユーザーにチャットやメールを通じてリンクを送信します。

そして、ユーザーがそのリンクをクリックすると、設定したコマンドが実行されてしまうという仕組みです。

例えば、これによってユーザーのアカウントから資金を移動することもできてしまいます。あるいは、ユーザーのメールアドレスを変更し、アカウントにアクセスできない状態にすることも可能です。

CSRF攻撃の仕組み

CSRF攻撃の最初の、そして肝となるステップは、アカウントにログイン中のユーザーに状態変更のリクエストを送信させることです。CSRF攻撃は、認証されたユーザーが、知らず知らずのうちにサイトやウェブアプリケーションに悪意のある要求を送信するように仕向けることが目的です。このリクエストは、CookieやURLパラメータ、一見正常なデータ型で構成されていることがあります。

CSRF攻撃の実行には、以下が必要になります。

  • セッション管理にCookieを使用するアプリに認証されたユーザーがログインしている状態
  • 状態を変更する偽造リクエストの作成
  • ターゲットサーバーが処理する正しいリクエストに予測不可能なパラメータが含まれていないこと(例えば、状態変更のリクエストを処理する際に検証のためにパスワードを求めないもの)

CSRF攻撃の最も一般的な手口は、適切なSameSite CookieポリシーのないアプリケーションでCookieを使用するものです。ウェブブラウザでは自動的にCookieを保存し(多くの場合は匿名)、ユーザーがドメインに送信するあらゆる要求にそのドメインで使用されたCookieを保存します。

SameSite Cookieポリシーは、複数のサイトにまたがるブラウジングコンテキストで、ブラウザがCookieをどのように扱うかを定義するものです。「Strict」設定すれば、Cookieが複数のサイトで共有されることがなくなり、CSRF攻撃を回避することができます。「None」に設定すれば、Cookieは共有されるため、アプリケーションはCSRF攻撃に対して脆弱なままになります。

ユーザーが気づかずにブラウザから悪意のあるリクエストを送信すると、保存されたCookieによって、サーバーが正当なリクエストとして認識します。この結果、サーバーがユーザーのアカウントやセッション状態を変更したり、要求されたデータを返したりなど、リクエストに応答してしまいます。

次に、CSRFの攻撃経路として、GETリクエストとPOSTリクエストの2つの例を詳しく見てみましょう。

GETリクエストの場合

まず、銀行のウェブアプリケーションで使用されるGETリクエストとハイパーリンクの配信を悪用した攻撃を見ていきます。

以下は、お金を振り込むためのGETリクエスト例です。

GET https://xymbank.com/online/transfer?amount=1000&accountNumber=547895 HTTP/1.1

この正しいリクエストは、購入した商品の支払いとして、547895の口座に1,000ドルを送金するものです。

このような要求は明示的で、シンプルかつ実用的ですが、悪意のあるユーザーが知らないような情報が含まれておらず、アカウント保持者がCSRF攻撃に晒されることになります。つまり、このリクエストのパラメータ(金額と口座番号)を変更するだけで、簡単に実行可能な偽造リクエストを作成できてしまいます。

また、偽造リクエストは、Cookieで管理されたセッションが継続している限り、銀行のどのユーザーに対しても有効です。

攻撃者のアカウント(この例では口座番号654585)に500ドルを送金するための偽造リクエストは、以下のようになります。なお、この例は高度なCSRF攻撃の仕組みを説明するために簡略化しています。

GET https://xymbank.com/online/transfer?amount=500&accountNumber=654585 HTTP/1.1

偽造リクエストを作成した後は、ユーザーを騙して、銀行のアプリにログインした状態でこの要求を送信させる方法を考えます。例えば、ユーザーの注意を引くような無害なハイパーリンクを作成して送信するのはよくある手法です。

<a
href="https://xymbank.com/online/transfer?amount=500&accountNumber=654585">Click here to get more information</a>.

攻撃者が標的となるユーザーのメールアドレスを特定すれば、多くの銀行の顧客にメールでこれを送信することができます。そして、ログイン状態でこのリンクをクリックしてしまうと、ログインしているアカウントから攻撃者に500ドルを送る要求が誘発されます。

POSTリクエストの場合

では、同じ銀行のアプリケーションがPOSTリクエストのみを受け付けている場合はどうでしょうか。この場合は、上の例で示したハイパーリンクの配信は通用しません。そのため、悪意あるユーザーはHTMLフォームを作成します。以下は、購入した商品に対して1,000ドルを送信するリクエストの例です。

POST /online/transfer HTTP/1.1
Host: xymbank.com
Content-Type: application/x-www-form-urlencoded
Cookie: session=FRyhityeQkAPzeQ5gHgTvlyxHJYhg
amount=1000
account=547895

上記のリクエストは、ユーザーID、送金額、送金先のアカウントを定義するためにCookieが必要になります。攻撃者はこのリクエストを改変して、CSRF攻撃を仕掛けることができます。

操作は、サーバーに転送を処理させるために偽造リクエストにCookieを付与するだけ。これには、無害に見えるハイパーリンクを作成し、以下のようなトリガーとなるページにユーザーを誘導します。

<html>
<body>
<form action="https://xymbank.com/online/transfer" method="POST">
<input type="hidden" name="amount" value="500"/>
<input type="hidden" name="account" value="654585" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>

上記のフォームには、金額と口座番号のパラメータがすでに設定されており、認証されたユーザーがこのページにアクセスすると、ブラウザが要求をサーバーに転送する前にセッションCookieを付与します。これで、サーバーは攻撃者のアカウントに500ドルを転送します。

3つのCSRF対策

ウェブサイトやウェブアプリケーションでCSRF攻撃を回避し、セキュリティを最大限に高めるには、以下のような対策が有効です。

  • CSRFトークンの使用
  • Refererヘッダーの検証
  • Kinstaなどの安全なホスティングサービスの利用

CSRFトークンの使用

CSRFに対して安全なウェブサイトは、各セッションに固有のトークンを割り当て、サーバー側とクライアントのブラウザで共有します。ブラウザが機密性の高いリクエストを送信する場合、サーバーはそのリクエストに割り当てられたトークンを求めます。異なるトークンが含まれている場合は、処理が拒否されます。またCSRFトークンは、セキュリティの観点から、ブラウザのセッションCookieには保存されません。

CSRFトークンの潜在的な脆弱性

CSRFトークンは、優れたセキュリティ強化策となりますが、攻撃を完全に防げるものではありません。この方法には、以下のような懸念点があります。

  • 検証のバイパス─アプリケーションによっては、トークンが見つからない場合、検証をスキップするものがあります。これによって、悪意のあるユーザーがトークンを含むコードにアクセスした場合、トークンを削除しCSRF攻撃を仕掛けることができます。つまり、サーバーへの有効なリクエストが以下のようなものだとします。
POST /change_password
POST body:
password=pass123&csrf_token=93j9d8eckke20d433

つまり、トークン削除して以下のように送信するだけで、攻撃を行えるということです。

POST /change_password
POST body:
password=pass123
  • プールされたトークン─アプリケーションによっては、セッションに一意のトークンを実装する代わりに、ユーザーセッションの検証にトークンのプールを維持するものがあります。これによって、攻撃者はトークンのプールから1つを取得するだけで、ユーザーになりすますことが可能です。

その後、自分のアカウントを使ってアプリケーションにログインし、以下のようなトークンを取得します。

[application_url].com?csrf_token=93j9d8eckke20d433

また、トークンはプールされているため、攻撃者は同じトークンをコピーし、別のユーザーアカウントにログインするために、再利用することができます。

  • CSRFはトークンをCookieにコピーすることができる─また、トークンに関連するパラメータをユーザーのCookieにコピーするアプリケーションもあります。攻撃者がそのようなCookieにアクセスすることができてしまえば、簡単に別のCookieを生成し、ブラウザに配置して、CSRF攻撃を仕掛けることができます。

そのため、攻撃者が自分のアカウントを使ってアプリケーションにログインし、Cookieファイルを開くと、以下のように表示されます。

Csrf_token:93j9d8eckke20d433

この情報を使えば、攻撃に必要な別のCookieを作成することができます。

  • 無効なトークン─中には、CSRFトークンをユーザセッションと一致させないアプリケーションも。この場合、攻撃者はただセッションにログインし、上記のようなトークンを取得して、標的となるユーザーにCSRF攻撃を実行することができます。

Refererヘッダーの検証

もう1つのCSRF対策は、Refererヘッダーを使用することです。HTTPでは、Refererヘッダーはリクエストの送信元を示し、分析、最適化、ログなどに使用されるのが一般的です。

CSRF攻撃を防止するために、サーバー側でRefererヘッダーのチェックを行うことができます。サーバー側でリクエストのソースを確認し、ターゲットを決定します。一致する場合にはリクエストが許可され、不一致の場合はサーバーがリクエストを拒否します。

Refererヘッダーは、個々のユーザーを識別する必要がないため、トークンよりもはるかに簡単な対策です。

Refererヘッダーの潜在的な脆弱性

CSRFトークン同様、Refererヘッダーにもいくつか見逃せない重要な脆弱性があります。

まず、Refererヘッダーは必須ではなく、サイトによってはRefererヘッダーのないリクエストを送信してきます。CSRFがヘッダーのないリクエストを処理するポリシーを持たない場合は、ヘッダーのないリクエストで状態変更の要求を仕向けることができてしまいます。

さらにこの対策は、最近導入されたReferrer-Policyによって、あまり効果的ではなくなってきています。このポリシーは、他ドメインへのURL漏洩を防ぐもので、ユーザーはRefererヘッダーの情報を柔軟に管理できるようになっています。以下のように、HTMLページにメタデータタグを貼り付けることで、ヘッダーの情報の一部を公開したり、逆に非公開にしたりすることが可能です。

<meta name="referrer" content="no-referrer">

このコードは、このページからのすべての要求に対して、Refererヘッダーを削除するものです。これによって、Refererヘッダーに依存するアプリケーションで、このようなページからのCSRF攻撃を防ぐことが困難になります。

KinstaのCSRF対策

ウェブサイトやウェブアプリケーションをKinstaのような安全なホスティングサービスで運用することで、悪意あるユーザーに対して、高度なセキュリティ対策を講じることができます。

Kinstaでは、自動バックアップ二要素認証SSHプロトコルによるSFTPなどの高度なセキュリティ機能に加え、Cloudflare統合により、IPベースおよびファイアウォールによるエンタープライズレベルの保護を保証しています。

具体的には、悪意のある攻撃を防ぎ、プラグインやテーマの深刻な未検出の脆弱性への対策として、CSRF脆弱性を見つけ出す特定のものを含め、約60の独自ファイアウォールルールを設けています。

まとめ

クロスサイトリクエストフォージェリ(CSRF)は、認証されたユーザーを騙して、意図しない状態変更の要求を送信させる攻撃です。正しい状態変更のリクエストと偽造リクエストの区別がつかないアプリケーションが標的になっています。

CSRFは、ログインしたユーザーを識別するためにセッションCookieに依存し、適切なSameSite Cookieポリシーを持たないアプリケーションのみに仕掛けることができる攻撃です。また、パスワードなどの知ることができないパラメータが含まれないリクエストを処理するサーバーも必要条件になります。そして、GETまたはPOSTリクエストのいずれかを使って攻撃を仕掛けます。

CSRFトークンの使用やRefererヘッダーの検証は、CSRF攻撃をある程度防ぐことができますが、いずれの対策にも潜在的な脆弱性があり、完璧な対策とは言えません。

Kinstaのような安全性の高いホスティングサービスに移行することで、CSRF攻撃からウェブサイトやウェブアプリを保護することができます。Kinstaでは、Cloudflare統合により、特定のCSRF攻撃を回避することも可能です。

Salman Ravoof

Salman Ravoof is a self-taught web developer, writer, creator, and a huge admirer of Free and Open Source Software (FOSS). Besides tech, he's excited by science, philosophy, photography, arts, cats, and food. Learn more about him on his website, and connect with Salman on Twitter.