GET vs POST in terms of security
stackoverflow.com
stackoverflow.com
People conflate CSRF-ability with destructive GET operations because a lot of apps that are pervasively CSRF-able also happen to have lots of inadvertant destructive GET's, but the bad GET endpoints are a reliability flaw more than a security flaw.
Besides, don't use GET for non-idempotent requests (those which change state). That's just webapp development 101.
Edited for clarity.
In the http case, GET and HEAD should not change any state (be safe and idempotent), PUT and DELETE should change state but be idempotent, and POST can do whatever it wants. http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
In fact, idempotency is irrelevant for GET, as GET requests should be safe, which trivially implies that they are idempotent. So requiring idempotency in addition to safety does nothing except making the prose harder to read.
> GET and HEAD should not change any state
> (be safe and idempotent)
> But of course it changes something, as
> 0 * x is clearly not x in the general case.
If 0 * x is idempotent, but it changes things then how can 'should not change state' be equivalent to idempotent? If I use a GET request to submit a shopping cart (for example), as long as submitting that URL a second time doesn't placee a second order for a copy of the original shopping cart (maybe it has a unique identifier so the backend can tell that it's already been submitted), then that should be idempotent, right?However, just to play devil's advocate, there is a class of attacks based around injecting code into logfiles since they'll log the query string of a GET request. If you can then get the server to say include that logfile as a php file, it will execute the embedded PHP.
Of course the real vuln isn't logging GET params (it's convincing the server to include the logfile as .php), but I thought it was worth pointing out.
<img src="http://example.com/do.php?action=delete&id=3 />
But anyway... today I learned that even though GET and POST are no different security-wise... always use a secret token when security is an issue... and it's best to use POST because it allows MUCH more data than GET.
I was working at a social networking startup and I created a Groups feature which allowed users to create their own groups with a forum and a photo gallery and a member list, news feed and so on.
Then one day a user sent us an email claiming her group was displaying erratic behavior (users randomly banned, posts randomly deleted, etc). It took us weeks to figure it out, but our ops guy eventually helped us track it down to Google Web Accelerator, which was pre-fetching URLs displayed on the page via GET (links labeled "Ban" and "Delete").
This unintentionally effected a similar "Confused Agent" exploit since the app was misusing HTTP in precisely the manor described in this post.
Google Web Accelerator has since been discontinued for precisely this reason.
However, this is a defense which works just as well for GET requests. Just put a nonce in the URL. /do.php?action=delete&id=3&nonce=88e3a6fe57854f2ed18c. Solves it just as well. (Another common solution is to duplicate the session cookie in the URL.) It is not bad form to have a get request which changes state so long as there is a nonce in the URL.
Edit: URL was being truncated.
Why do people insist on hammering in the screws, and screwing in the nails?
If you want to send data from the browser back to the server, use a post. It isn't difficult!
Is the motivation behind this secretly that there is some retarded 3rd party framework in play here that doesn't support post? Something like Ruby on Rails or Django or some weird ass Java REST library???
Edit:
Now that I think about it, why would you want to bookmark a link which modified state? The only time to use a nonce is to make it secure against CSRF attacks. You can't bookmark them when they're a post anyways, so you don't lose anything. Am I wrong somewhere?
The people most likely screwing this up are the PHP-without-a-framework people.
1: http://martinfowler.com/articles/richardsonMaturityModel.htm...
Please don't do that. If you inadvertently paste the URL into an IM window, post in a forum, etc., it becomes trivial for me to steal your session.
If the attacker cannot add a form and script directly to the forum, then the attacker can try to trick the victim into following a link to a page where the attacker can add these elements.
Switching from GET to POST makes the attack more difficult because social engineering is required, but it does not eliminate the problem.
Another way (or in addition to using tokens) is to not expose hard delete functionality to the front-end period.
One thing I've done is to create a 'recycle' table in the database with a unique ID.
Also give every table in your database a deleted column.
If something gets deleted, create a new row in the 'recycle' table and use that ID to populate the 'deleted' column of all the rows that were deleted. This way each delete associates itself to multiple rows.
This offers you the ability to "undo" any delete + all associated rows with the delete from an admin interface that is not exposed publicly to web users.
This way, you have 3 tiers of protection:
- tokens
- a soft delete that you can easily undo
- backup copy of the db if all else fails
In the API we've implemented recently in our company (e-commerce search-as-a-service) we use request signing exactly according to Amazon's AWS specs.
1- POSTs cannot be forwarded
2- some browsers (webkit only I believe) require a client to interact with a domain before they can POST to it-- this means iframes cannot POST.
When it comes to XSRF, they are equally (in)secure.