Ask HN: Why would anyone POST anything in AJAX?
30 comments
There are numerous implications of choosing POST or GET.
First off, the HTTP specification requires that GET (and HEAD) requests be idempotent^W EDIT: side effect free to enable caching. Clearly, violations of this abound; however, proxy servers and other infrastructure will often hold you to this rule, so make sure you know what you're doing. (proxies and clients are permitted to withhold or arbitrarily repeat GET requests without changing the outcome)
Second, security: although AJAX in the strictest sense falls under the same-origin policy, you can quite easily make GET requests to foreign hosts in JavaScript by creating SCRIPT, IMG or IFRAME elements with appropriate SRC attributes, whereas you'll struggle to create a foreign-host POST. Inappropriate use of GET is therefore the enabler of XSRF attacks. CAUTION: read petewarden's reply regarding XSRF attacks via POST forms.
Third, data size, as others have said. URLs are notoriously problematic for conveying any information other than short text.
Fourth, if web crawlers get hold of any URLs which exhibit side effects on GET, they will wreak havoc on your site. (though this can admittedly be alleviated by judicious use of robots.txt)
Finally, you seem to imply that POST requests will not or cannot generate a response similar to GET. This is not the case, responses to POST work in the same way. (except it must not be cached) The deciding factor is the nature of the request (side effect or no side effect), not the nature of the response.
First off, the HTTP specification requires that GET (and HEAD) requests be idempotent^W EDIT: side effect free to enable caching. Clearly, violations of this abound; however, proxy servers and other infrastructure will often hold you to this rule, so make sure you know what you're doing. (proxies and clients are permitted to withhold or arbitrarily repeat GET requests without changing the outcome)
Second, security: although AJAX in the strictest sense falls under the same-origin policy, you can quite easily make GET requests to foreign hosts in JavaScript by creating SCRIPT, IMG or IFRAME elements with appropriate SRC attributes, whereas you'll struggle to create a foreign-host POST. Inappropriate use of GET is therefore the enabler of XSRF attacks. CAUTION: read petewarden's reply regarding XSRF attacks via POST forms.
Third, data size, as others have said. URLs are notoriously problematic for conveying any information other than short text.
Fourth, if web crawlers get hold of any URLs which exhibit side effects on GET, they will wreak havoc on your site. (though this can admittedly be alleviated by judicious use of robots.txt)
Finally, you seem to imply that POST requests will not or cannot generate a response similar to GET. This is not the case, responses to POST work in the same way. (except it must not be cached) The deciding factor is the nature of the request (side effect or no side effect), not the nature of the response.
Awesome. 5 things I now know that I probably would have not known for years to come by making mistakes. Without a whole lot of experience with AJAX + that nagging feeling I'm implementing it wrong, it's practical rules like these that I can easily put into practice.
Finally, you seem to imply that POST requests will not or cannot generate a response similar to GET. This is not the case, responses to POST work in the same way. (except it must not be cached) The deciding factor is the nature of the request (side effect or no side effect), not the nature of the response.
Yah I actually found this out right after I posted and had I known the difference between an AJAX POST and an AJAX GET was literally like 5 to 10 lines of code I may have never asked such an ostentatious question.
Finally, you seem to imply that POST requests will not or cannot generate a response similar to GET. This is not the case, responses to POST work in the same way. (except it must not be cached) The deciding factor is the nature of the request (side effect or no side effect), not the nature of the response.
Yah I actually found this out right after I posted and had I known the difference between an AJAX POST and an AJAX GET was literally like 5 to 10 lines of code I may have never asked such an ostentatious question.
With regards to point #2, it's definitely inconvenient to cross-site POST from the client side, but not hard: Create a form with a target pointing to the external destination and submit it via Javascript, wrap it inside an invisible frame for neatness.
Don't let POST give you a false sense of security; checking the referrer can help in this particular case (it's tricky to forge the referrer from the client side) but you really need a robust check like a generated token to avoid malicious cross-site requests.
Don't let POST give you a false sense of security; checking the referrer can help in this particular case (it's tricky to forge the referrer from the client side) but you really need a robust check like a generated token to avoid malicious cross-site requests.
for what it might be worth to others:
i've generally found that the client already has a cookie-session established in situations where cross-site ajax calls are a concern. so, my approach is to require a hash of <request text>+<session id cookie> as a per-call signature. javascript on another domain can't access the session id cookie and so won't be able to generate this signature.
i've generally found that the client already has a cookie-session established in situations where cross-site ajax calls are a concern. so, my approach is to require a hash of <request text>+<session id cookie> as a per-call signature. javascript on another domain can't access the session id cookie and so won't be able to generate this signature.
> so, my approach is to require a hash of <request text>+<session id cookie> as a per-call signature. javascript on another domain can't access the session id cookie and so won't be able to generate this signature.
If the security relies on other javascript not being able to access the session cookie, why is it insecure to use said session cookie by itself as the per-call signature?
Who can see the signature but not the session id cookie?
If the security relies on other javascript not being able to access the session cookie, why is it insecure to use said session cookie by itself as the per-call signature?
Who can see the signature but not the session id cookie?
The cookie will be sent even with a form submit. JavaScript from another domain can't see it directly, however.
you're right, hashing is overkill.
No, it isn't, as the cookie is sent with any request to your domain, regardless of the source. The hashing uses the fact that the cookie is inaccessible to JavaScript running in other domain contexts.
the sid is inaccessible to js running in another domain context, so anamax is pointing that it suffices to just retransmit the sid as one of the request parameters, rather than generating and including sig=hash(request+sid).
you're right that the remotely invoked request will include the sid as part of the http cookies header - it's what goes into the get/post request parameters which differentiates the domain context of the invoker. and if someone can't generate and include a sig because they can't access the sid, then the challenge might as well just be including the sid.
the only draw back i see is that i wouldn't have had an excuse to learn how to implement sha ;)
*edit: jim_lawless points out below that you might not want a sid showing up in web server logs. my system frequently rotates the clients sid, so it's not a concern to me - but if you do use less transient sid cookies you might want to implement the hash signature approach after all?
you're right that the remotely invoked request will include the sid as part of the http cookies header - it's what goes into the get/post request parameters which differentiates the domain context of the invoker. and if someone can't generate and include a sig because they can't access the sid, then the challenge might as well just be including the sid.
the only draw back i see is that i wouldn't have had an excuse to learn how to implement sha ;)
*edit: jim_lawless points out below that you might not want a sid showing up in web server logs. my system frequently rotates the clients sid, so it's not a concern to me - but if you do use less transient sid cookies you might want to implement the hash signature approach after all?
This is also known as Cross Site Request Forgery or CSRF: http://en.wikipedia.org/wiki/Cross-site_request_forgery
That's a pretty clever and elegant way to handle it, and seems to be pretty universally applicable, thanks!
Thanks for raising the form issue. Presumably this can be done surreptitiously in a hidden iframe? (submitting a form normally displays the response)
> Fourth, if web crawlers get hold of any URLs which exhibit side effects on GET, they will wreak havoc on your site.
Web accelerators, too, and those will not be controlled by robots.txt. I would definitely advise the OP to read the HTTP spec about the differences between POST and GET, or perhaps an introduction to RESTful web development.
Web accelerators, too, and those will not be controlled by robots.txt. I would definitely advise the OP to read the HTTP spec about the differences between POST and GET, or perhaps an introduction to RESTful web development.
First off, the HTTP specification requires that GET (and HEAD) requests be idempotent to enable caching.
Technically, PUT request are supposed to be idempotent, while GET and HEAD are supposed to be side-effect free (which is strictly stronger than idempotency).
Technically, PUT request are supposed to be idempotent, while GET and HEAD are supposed to be side-effect free (which is strictly stronger than idempotency).
PUT is supposed to be idempotent? So an "increment" or "reverse" request should technically be a POST?
Or does the idempoten-cy apply only to the response from the server, and not the state of the data on the server?
Or does the idempoten-cy apply only to the response from the server, and not the state of the data on the server?
PUT is supposed to be idempotent? So an "increment" or "reverse" request should technically be a POST?
Absolutely. User-agents are allowed to retry PUTs transparently -- it's only for POSTs that they're supposed to put up a "are you sure you want to re-submit this form? Bad stuff might happen" dialog.
Absolutely. User-agents are allowed to retry PUTs transparently -- it's only for POSTs that they're supposed to put up a "are you sure you want to re-submit this form? Bad stuff might happen" dialog.
That's certainly my understanding of it. PUT has semantics of resource creation or updating, like writing a file: whatever you upload replaces what is already there, if anything. You can process the data of course, but the outcome should depend only on the request data itself, not state.
Thanks for correcting the definition of idempotence in my brain! (edited original post)
Not at all. Imagine a document editor. There are limits to the amount of data that can be passed via GET URLs. Without POST you could only have 2KB documents. In Archivd we use POST via Ajax anywhere the user mutates data. It avoids the data length problem and makes it simpler to defend against CSRF attacks.
Imagine a document editor.
For the web? Passing the entire document asynchronously?
In Archivd we use POST via Ajax anywhere the user mutates data.
See, I'm still new to AJAX and from the type of apps that I use and experiment with are generally broken down as independent events who pass values and who perform an xhr as each event is triggered. I guess as your app grows and the data your handling using this methodology (as GET) is suddenly just too complex to carry out on the client. Thanks for the input though.
For the web? Passing the entire document asynchronously?
In Archivd we use POST via Ajax anywhere the user mutates data.
See, I'm still new to AJAX and from the type of apps that I use and experiment with are generally broken down as independent events who pass values and who perform an xhr as each event is triggered. I guess as your app grows and the data your handling using this methodology (as GET) is suddenly just too complex to carry out on the client. Thanks for the input though.
280 Slides uses an asynchronous POST (or PUT) request for saving documents.
Just because the mechanism for generating requests has changed, that doesn't mean the mechanics of REST should be thrown out the window.
REST is useful, and its how most of the infrastructure of the web works. It's useful to understand this, and try to build your applications appropriately.
Just because the mechanism for generating requests has changed, that doesn't mean the mechanics of REST should be thrown out the window.
REST is useful, and its how most of the infrastructure of the web works. It's useful to understand this, and try to build your applications appropriately.
Ok even if you do independent events eventually you want to upload an image or a file which is not going to fit in GET very well, the url path is limited to 2k.
POST you can pass much more information, also it is more secure in that is does not log the params and path in logs.
Or maybe you POST to a REST url that has some params such as an api_key, then you post the data structure. Or you want to post a large JSON object of all data on a page. Again limits to GET, so people choose POST then. It depends on the situation.
POST you can pass much more information, also it is more secure in that is does not log the params and path in logs.
Or maybe you POST to a REST url that has some params such as an api_key, then you post the data structure. Or you want to post a large JSON object of all data on a page. Again limits to GET, so people choose POST then. It depends on the situation.
> For the web? Passing the entire document asynchronously?
See Google Docs as an example of this.
See Google Docs as an example of this.
Using POST doesn't necessarily make it simpler to defend against CSRF. You still need to use some kind of exclusive token shared between the client and server (e.g. a session id stored in a cookie). Imagine a poorly implemented site that doesn't prevent users from uploading js script blocks into the comments. A user could upload a script that creates a form and submits it via POST to your POST restricted endpoint, thus circumventing POST only protection. I'm assuming I've misread your comment as you use POST only and you're also doing proper CSRF protection right?
Many systems have limits on the maximum length of a GET query string, since said strings form part of a URL. In most cases these limits are quite large (4kB or more) but I've seen systems which can't even handle 1kB URLs.
If you want to send a large amount of form data and not have things randomly break, it's a good idea to use POST instead of GET.
If you want to send a large amount of form data and not have things randomly break, it's a good idea to use POST instead of GET.
Internet Explorer has problems with URLs over 2047 characters in length - if you are needing to handle large amounts of text (say from a textarea), POST is the way to go.
In addition to request size limits, using the HTTP methods on server side code can simplify code. If I GET a person record then send it down, if I POST a person record then process the passed parameters. With that separation I may find that POST requests do not require sending any data to the client (other than a success indicator). That reduces bandwidth and improves client response time.
I have really grown to appreciate this simplification while working with webpy on AppEngine. I think that my request handlers are about the cleanest they have ever been.
I have really grown to appreciate this simplification while working with webpy on AppEngine. I think that my request handlers are about the cleanest they have ever been.
I use ajax POSTs for autosaves, creating and deleting 'child' objects (when the UI for the sub-object should be added to/removed from the page without a reload). Basically any mutation where I don't want a reload.
GET parameters can ( and often do ) show up in web-server logs. Transmitting sensitive data via a GET ( even over SSL ) may ultimately cause security / privacy concerns.
POST easier to protect from XSS attacks when using the Django middleware.
If anything AJAX seems like it was made especially for GET to cut-down on how much and what was being passed with POST...I might be way off, but does it not seem contradictory to POST something in AJAX without returning a response?