When comparing an HTTP GET to an HTTP POST, what are the differences from a security perspective? Is one of the choices inherently more secure than the other? If so, why?
Consider this situation: A sloppy API accepts GET requests like:
http://www.example.com/api?apikey=abcdef123456&action=deleteCategory&id=1
In some settings, when you request this URL and if there is an error/warning regarding the request, this whole line gets logged in the log file. Worse yet: if you forget to disable error messages in the production server, this information is just displayed in plain in the browser! Now you've just given your API key away to everyone.
Unfortunately, there are real API's working this way.
I wouldn't like the idea of having some sensitive info in the logs or displaying them in the browser. POST and GET is not the same. Use each where appropriate.
Many people adopt a convention (alluded to by Ross) that GET requests only retrieve data, and do not modify any data on the server, and POST requests are used for all data modification. While one is not more inherently secure than the other, if you do follow this convention, you can apply cross-cutting security logic (e.g. only people with accounts can modify data, so unauthenticated POSTs are rejected).
One reason POST is worse for security is that GET is logged by default, parameters and all data is almost universally logged by your webserver.
POST is the opposite, it's almost universally not logged, leading to very difficult to spot attacker activity.
I don't buy the argument "it's too big", that's no reason to not log anything, at least 1KB, would go a long way for people to identify attackers working away at a weak entry-point until it pop's, then POST does a double dis-service, by enabling any HTTP based back-door to silently pass unlimited amounts of data.
Even if POST
gives no real security benefit versus GET
, for login forms or any other form with relatively sensitive information, make sure you are using POST
as:
POST
ed will not be saved in the user's history.GET
, it will be visible in the history and the URL bar).Also, GET
has a theorical limit of data. POST
doesn't.
For real sensitive info, make sure to use SSL
(HTTPS
)
RFC7231:
" URIs are intended to be shared, not secured, even when they identify secure resources. URIs are often shown on displays, added to templates when a page is printed, and stored in a variety of unprotected bookmark lists. It is therefore unwise to include information within a URI that is sensitive, personally identifiable, or a risk to disclose.
Authors of services ought to avoid GET-based forms for the submission of sensitive data because that data will be placed in the request-target. Many existing servers, proxies, and user agents log or display the request-target in places where it might be visible to third parties. Such services ought to use POST-based form submission instead."
This RFC clearly states that sensitive data should not be submitted using GET. Because of this remark, some implementors might not handle data obtained from the query portion of a GET request with the same care. I'm working on a protocol myself that ensures integrity of data. According to this spec I shouldn't have to guarantee integrity of the GET data (which I will because nobody adheres to these specs)
As far as security, they are inherently the same. While it is true that POST doesn't expose information via the URL, it exposes just as much information as a GET in the actual network communication between the client and server. If you need to pass information that is sensitive, your first line of defense would be to pass it using Secure HTTP.
GET or query string posts are really good for information required for either bookmarking a particular item, or for assisting in search engine optimization and indexing items.
POST is good for standard forms used to submit one time data. I wouldn't use GET for posting actual forms, unless maybe in a search form where you want to allow the user to save the query in a bookmark, or something along those lines.