6

Forged POST requests can be constructed by untrusted websites by creating a form and posting it to the target site. However, the raw contents of this POST will be encoded by the browser to be in the format:

param1=value1&param2=value2

Is it possible for untrusted websites to construct forged POSTs which contain arbitrary raw content -- such as stringified JSON?

{param1: value1, param2: value2}

Put another way: Can websites cause the browser to POST arbitrary content to third-party domains?

JS_Riddler
  • 1,443
  • 2
  • 22
  • 32

5 Answers5

11

The POST body of an HTML form’s request is always either application/x-www-form-urlencoded, multipart/form-data, or text/plain as these reflect the valid values for the enctype attribute. Especially text/plain one can be used to form valid JSON data. So form-based CSRF can be used here, however, it requires the server to accept it as text/plain.

Additionally, XHR-based CSRF can be used as the XMLHttpRequest API allows so send arbitrary POST data. The only remaining obstacle with this is the Same-Origin Policy: Only if both have the same origin or your server supports Cross-Origin Request Sharing and allows resource sharing, such valid POST requests can be forged.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • @JS_Riddler The [server has a processing model](http://www.w3.org/TR/cors/#resource-processing-model), too. – Gumbo Feb 08 '13 at 18:44
  • 2
    I think this accepted answer is flat-out wrong for text/plain. See this example for forging XML: http://pentestmonkey.net/blog/csrf-xml-post-request . The same technique could be used for something like . –  Jun 02 '13 at 20:53
  • 1
    It still seems dangerous to me to rely on application/json never being added; I think the token/nonce standard defense is wise here. See http://security.stackexchange.com/questions/10227/csrf-with-json-post. –  Jun 03 '13 at 16:51
  • Will the browser refuse to send the form request if the content type is application/json ? – lud Apr 15 '20 at 17:47
1

Yes!, a POST request is nothing more than text with a specific format sent to a web server. You can use IE or Chrome developer tools to look at what each requests looks like.

So yes, you can create a forged POST request and change whatever you want, however if the request is not well-formed most web servers will reject it.

https://www.rfc-editor.org/rfc/rfc2616

Community
  • 1
  • 1
zad
  • 3,355
  • 2
  • 24
  • 25
  • Sorry -- I'm referring specifically to untrusted websites creating these posts, not clients. I've updated the question. – JS_Riddler May 28 '12 at 17:55
1

The client side code of a web site would have difficulties to forge a request like that, but the server side code could very easily do that.

As your web site can't tell if the request comes from a browser or a server that behaves just like a browser, the limitations in the browser is no protection.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • CSRF only works if the request also contains the identity of the user -- so I am not worried about non-browser clients forging the request. – JS_Riddler May 28 '12 at 18:06
  • By "difficulties" do you mean not possible? This is really the question: is it possible or not? – JS_Riddler May 28 '12 at 18:07
  • @JS_Riddler: A program could act as a browser in any respect, so a user identity is not a protection. Someone could even take any open source browser project and rewrite it to do anything, so even if any current browser can't send a post with arbitrary content, it's certainly possible to do. – Guffa May 28 '12 at 18:14
  • In that case, the requests would not be forged as they would be produced by the user. What I am really getting at: is it forbidden in HTML spec for browsers to send arbitrary POST content to other domains. I believe it is, but would like confirmation. – JS_Riddler May 28 '12 at 18:26
  • @JS_Riddler: The HTML specifications doesn't say anything about things like that. I don't know if there is anything in the HTTP specifications about that, but the security limitations in the browsers is usually much stricter than the standards specify. Anyhow, one could easily set up a web page that posts a request through a proxy server that sends it on to your server, so a visitor could post a form where the content could be replaced. – Guffa May 28 '12 at 18:42
  • @JS_Riddler CSRF does also with without credentials; they just make CSRF more effective as an attacking site can exploit the actions the victim is authorized to do. – Gumbo May 28 '12 at 18:49
  • @Guffa: Proxying would not work unless the proxy were on the same domain as the target website. The proxy will not be sent the user credentials (cookies). – JS_Riddler May 28 '12 at 18:55
  • @Gumbo: Fair point -- I meant specifically CSRF that requires cookies. – JS_Riddler May 28 '12 at 18:56
  • @JS_Riddler: The site would use the proxy to send the form once the user was logged in, so it would already have the cookies. – Guffa May 28 '12 at 19:14
  • @Guffa: The same origin policy forbids browsers from sending cookies to domains which did not originate them. If the user passed their credentials (username/password) directly to the proxy, however, that's another story... it's called phishing, and would render my question inconsequential. – JS_Riddler May 29 '12 at 03:33
  • @JS_Riddler: The server would not send the cookie to the proxy, it would send them to the original site, then the site would send them back through the proxy. – Guffa May 29 '12 at 05:18
1

You can create valid JSON via a regular form post. It's just a matter of creatively naming the form parameters. In particular, parameter names can contain quotes.

http://blog.opensecurityresearch.com/2012/02/json-csrf-with-parameter-padding.html

jkl
  • 11
  • 1
0

In the case of pure HTML forms, yes it will always be encoded according to the spec. But there are other encoding schemes such as MIME multipart. There is also the question of Javascript and XMLHttpRequest. Encoding is specifically mentioned in only one case. This strongly implies that there is no encoding applied in the other cases.

John Watts
  • 8,717
  • 1
  • 31
  • 35