Is either GET or POST more secure than the other?

173,648

Solution 1

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.

Solution 2

The GET request is marginally less secure than the POST request. Neither offers true "security" by itself; using POST requests will not magically make your website secure against malicious attacks by a noticeable amount. However, using GET requests can make an otherwise secure application insecure.

The mantra that you "must not use GET requests to make changes" is still very much valid, but this has little to do with malicious behaviour. Login forms are the ones most sensitive to being sent using the wrong request type.

Search spiders and web accelerators

This is the real reason you should use POST requests for changing data. Search spiders will follow every link on your website, but will not submit random forms they find.

Web accelerators are worse than search spiders, because they run on the client’s machine, and "click" all links in the context of the logged in user. Thus, an application that uses a GET request to delete stuff, even if it requires an administrator, will happily obey the orders of the (non-malicious!) web accelerator and delete everything it sees.

Confused deputy attack

A confused deputy attack (where the deputy is the browser) is possible regardless of whether you use a GET or a POST request.

On attacker-controlled websites GET and POST are equally easy to submit without user interaction.

The only scenario in which POST is slightly less susceptible is that many websites that aren’t under the attacker’s control (say, a third-party forum) allow embedding arbitrary images (allowing the attacker to inject an arbitrary GET request), but prevent all ways of injecting an arbitary POST request, whether automatic or manual.

One might argue that web accelerators are an example of confused deputy attack, but that’s just a matter of definition. If anything, a malicious attacker has no control over this, so it’s hardly an attack, even if the deputy is confused.

Proxy logs

Proxy servers are likely to log GET URLs in their entirety, without stripping the query string. POST request parameters are not normally logged. Cookies are unlikely to be logged in either case. (example)

This is a very weak argument in favour of POST. Firstly, un-encrypted traffic can be logged in its entirety; a malicious proxy already has everything it needs. Secondly, the request parameters are of limited use to an attacker: what they really need is the cookies, so if the only thing they have are proxy logs, they are unlikely to be able to attack either a GET or a POST URL.

There is one exception for login requests: these tend to contain the user’s password. Saving this in the proxy log opens up a vector of attack that is absent in the case of POST. However, login over plain HTTP is inherently insecure anyway.

Proxy cache

Caching proxies might retain GET responses, but not POST responses. Having said that, GET responses can be made non-cacheable with less effort than converting the URL to a POST handler.

HTTP "Referer"

If the user were to navigate to a third party website from the page served in response to a GET request, that third party website gets to see all the GET request parameters.

Belongs to the category of "reveals request parameters to a third party", whose severity depends on what is present in those parameters. POST requests are naturally immune to this, however to exploit the GET request a hacker would need to insert a link to their own website into the server’s response.

Browser history

This is very similar to the "proxy logs" argument: GET requests are stored in the browser history along with their parameters. The attacker can easily obtain these if they have physical access to the machine.

Browser refresh action

The browser will retry a GET request as soon as the user hits "refresh". It might do that when restoring tabs after shutdown. Any action (say, a payment) will thus be repeated without warning.

The browser will not retry a POST request without a warning.

This is a good reason to use only POST requests for changing data, but has nothing to do with malicious behaviour and, hence, security.

So what should I do?

  • Use only POST requests to change data, mainly for non-security-related reasons.
  • Use only POST requests for login forms; doing otherwise introduces attack vectors.
  • If your site performs sensitive operations, you really need someone who knows what they’re doing, because this can’t be covered in a single answer. You need to use HTTPS, HSTS, CSP, mitigate SQL injection, script injection (XSS), CSRF, and a gazillion of other things that may be specific to your platform (like the mass assignment vulnerability in various frameworks: ASP.NET MVC, Ruby on Rails, etc.). There is no single thing that will make the difference between "secure" (not exploitable) and "not secure".

Over HTTPS, POST data is encoded, but could URLs be sniffed by a 3rd party?

No, they can’t be sniffed. But the URLs will be stored in the browser history.

Would it be fair to say the best practice is to avoid possible placing sensitive data in the POST or GET altogether and using server side code to handle sensitive information instead?

Depends on how sensitive it is, or more specifically, in what way. Obviously the client will see it. Anyone with physical access to the client’s computer will see it. The client can spoof it when sending it back to you. If those matter then yes, keep the sensitive data on the server and don’t let it leave.

Solution 3

You have no greater security provided because the variables are sent over HTTP POST than you have with variables sent over HTTP GET.

HTTP/1.1 provides us with a bunch of methods to send a request:

  • OPTIONS
  • GET
  • HEAD
  • POST
  • PUT
  • DELETE
  • TRACE
  • CONNECT

Lets suppose you have the following HTML document using GET:

<html>
<body>
<form action="http://example.com" method="get">
    User: <input type="text" name="username" /><br/>
    Password: <input type="password" name="password" /><br/>
    <input type="hidden" name="extra" value="lolcatz" />
    <input type="submit"/>
</form>
</body>
</html>

What does your browser ask? It asks this:

 GET /?username=swordfish&password=hunter2&extra=lolcatz HTTP/1.1
 Host: example.com
 Connection: keep-alive
 Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/ [...truncated]
 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) [...truncated]
 Accept-Encoding: gzip,deflate,sdch
 Accept-Language: en-US,en;q=0.8
 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

Now lets pretend we changed that request method to a POST:

 POST / HTTP/1.1
 Host: example.com
 Connection: keep-alive
 Content-Length: 49
 Cache-Control: max-age=0
 Origin: null
 Content-Type: application/x-www-form-urlencoded
 Accept: application/xml,application/xhtml+xml,text/ [...truncated]
 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; [...truncated]
 Accept-Encoding: gzip,deflate,sdch
 Accept-Language: en-US,en;q=0.8
 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

 username=swordfish&password=hunter2&extra=lolcatz

BOTH of these HTTP requests are:

  • Not encrypted
  • Included in both examples
  • Can be evesdroped on, and subject to MITM attacks.
  • Easily reproduced by third party, and script bots.

Many browsers do not support HTTP methods other than POST/GET.

Many browsers behaviors store the page address, but this doesn't mean you can ignore any of these other issues.

So to be specific:

Is one inherently more secure then another? I realize that POST doesn't expose information on the URL but is there any real value in that or is it just security through obscurity? What is the best practice here?

This is correct, because the software you're using to speak HTTP tends to store the request variables with one method but not another only prevents someone from looking at your browser history or some other naive attack from a 10 year old who thinks they understand h4x0r1ng, or scripts that check your history store. If you have a script that can check your history store, you could just as easily have one that checks your network traffic, so this entire security through obscurity is only providing obscurity to script kiddies and jealous girlfriends.

Over https, POST data is encoded, but could urls be sniffed by a 3rd party?

Here's how SSL works. Remember those two requests I sent above? Here's what they look like in SSL: (I changed the page to https://encrypted.google.com/ as example.com doesn't respond on SSL).

POST over SSL

q5XQP%RWCd2u#o/T9oiOyR2_YO?yo/3#tR_G7 2_RO8w?FoaObi)
oXpB_y?oO4q?`2o?O4G5D12Aovo?C@?/P/oOEQC5v?vai /%0Odo
QVw#6eoGXBF_o?/u0_F!_1a0A?Q b%TFyS@Or1SR/O/o/_@5o&_o
9q1/?q$7yOAXOD5sc$H`BECo1w/`4?)f!%geOOF/!/#Of_f&AEI#
yvv/wu_b5?/o d9O?VOVOFHwRO/pO/OSv_/8/9o6b0FGOH61O?ti
/i7b?!_o8u%RS/Doai%/Be/d4$0sv_%YD2_/EOAO/C?vv/%X!T?R
_o_2yoBP)orw7H_yQsXOhoVUo49itare#cA?/c)I7R?YCsg ??c'
(_!(0u)o4eIis/S8Oo8_BDueC?1uUO%ooOI_o8WaoO/ x?B?oO@&
Pw?os9Od!c?/$3bWWeIrd_?( `P_C?7_g5O(ob(go?&/ooRxR'u/
T/yO3dS&??hIOB/?/OI?$oH2_?c_?OsD//0/_s%r

GET over SSL

rV/O8ow1pc`?058/8OS_Qy/$7oSsU'qoo#vCbOO`vt?yFo_?EYif)
43`I/WOP_8oH0%3OqP_h/cBO&24?'?o_4`scooPSOVWYSV?H?pV!i
?78cU!_b5h'/b2coWD?/43Tu?153pI/9?R8!_Od"(//O_a#t8x?__
bb3D?05Dh/PrS6_/&5p@V f $)/xvxfgO'q@y&e&S0rB3D/Y_/fO?
_'woRbOV?_!yxSOdwo1G1?8d_p?4fo81VS3sAOvO/Db/br)f4fOxt
_Qs3EO/?2O/TOo_8p82FOt/hO?X_P3o"OVQO_?Ww_dr"'DxHwo//P
oEfGtt/_o)5RgoGqui&AXEq/oXv&//?%/6_?/x_OTgOEE%v (u(?/
t7DX1O8oD?fVObiooi'8)so?o??`o"FyVOByY_ Supo? /'i?Oi"4
tr'9/o_7too7q?c2Pv

(note: I converted the HEX to ASCII, some of it should obviously not be displayable)

The entire HTTP conversation is encrypted, the only visible portion of communication is on the TCP/IP layer (meaning the IP address and connection port information).

So let me make a big bold statement here. Your website is not provided greater security over one HTTP method than it is another, hackers and newbs all over the world know exactly how to do what I've just demonstrated here. If you want security, use SSL. Browsers tend to store history, it's recommended by RFC2616 9.1.1 to NOT use GET to perform an action, but to think that POST provides security is flatly wrong.

The only thing that POST is a security measure towards? Protection against your jealous ex flipping through your browser history. That's it. The rest of the world is logged into your account laughing at you.

To further demonstrate why POST isn't secure, Facebook uses POST requests all over the place, so how can software such as FireSheep exist?

Note that you may be attacked with CSRF even if you use HTTPS and your site does not contain XSS vulnerabilities. In short, this attack scenario assumes that the victim (the user of your site or service) is already logged in and has a proper cookie and then the victim's browser is requested to do something with your (supposedly secure) site. If you do not have protection against CSRF the attacker can still execute actions with the victims credentials. The attacker cannot see the server response because it will be transferred to the victim's browser but the damage is usually already done at that point.

Solution 4

There is no added security.

Post data does not show up in the history and/or log files but if the data should be kept secure, you need SSL.
Otherwise, anybody sniffing the wire can read your data anyway.

Solution 5

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:

  1. The information POSTed will not be saved in the user's history.
  2. The sensitive information (password, etc.) sent in the form will not be visible later on in the URL bar (by using 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)

Share:
173,648

Related videos on Youtube

James McMahon
Author by

James McMahon

Blogging at https://dev.to/jamesmcmahon.

Updated on February 19, 2022

Comments

  • James McMahon
    James McMahon about 2 years

    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?

    I realize that POST doesn't expose information on the URL, but is there any real value in that or is it just security through obscurity? Is there ever a reason that I should prefer POST when security is a concern?

    Edit:
    Over HTTPS, POST data is encoded, but could URLs be sniffed by a 3rd party? Additionally, I am dealing with JSP; when using JSP or a similar framework, would it be fair to say the best practice is to avoid placing sensitive data in the POST or GET altogether and using server side code to handle sensitive information instead?

    • fhe
      fhe over 15 years
      There is a nice blog entry about this on Jeff's blog Coding Horror: Cross-Site Request Forgeries and You.
    • James111
      James111 over 8 years
      Wouldn't you use POST for most things. E.g for an API, say you needed to GET data from a DB, but before the server returns data you would have to be authenticated first? Using post you would simply pass your session ID + all the parameters you need for the request. If you used a GET req for this then your session ID could easily be found either in your browser history or somewhere in the middle.
    • David Tonhofer
      David Tonhofer about 7 years
      I remember this discussion from before the war (99' or '00 or so) when https wasn't prevalent.
    • DeltaFlyer
      DeltaFlyer over 5 years
      @DavidTonhofer, which war are you referring to? The browser war?
    • David Tonhofer
      David Tonhofer over 5 years
      @DeltaFlyer No, the Forever War on Stuff, aka GWOT. What have we done.
  • stephenbayer
    stephenbayer over 15 years
    I can alter POST requests just as easy as query string requests, using a few add ons for Firefox. i can even modify cookie data to my heart's content.
  • Jacco
    Jacco over 15 years
    it won't slow down script kiddies, it is exactly the type of thing script kiddies try all the time. The problem is that they sometimes succeed.
  • eyelidlessness
    eyelidlessness over 15 years
    Uh. Using addons for Firefox = more effort than query string.
  • Chris Marasti-Georg
    Chris Marasti-Georg over 15 years
    Your answer will give people a false sense that they are being more secure when using a post, when in fact, they are not. Bad answer, bad man.
  • tvanfosson
    tvanfosson over 15 years
    With the caveat that for a GET the URL shown in the location bar can expose data that would be hidden in a POST.
  • eyelidlessness
    eyelidlessness over 15 years
    I edited to make the intent of my answer more clear. Hopefully that helps.
  • davetron5000
    davetron5000 over 15 years
    It's hidden only in the most naive sense
  • davetron5000
    davetron5000 over 15 years
    if you GET a URL over SSL, a third party will not be able to see the URL, so the security is the same
  • Kirschbaum
    Kirschbaum over 15 years
    that's correct, nemo. Obviously users can still see the data in the URL.
  • Jacco
    Jacco over 15 years
    GET information can only be seen at the start and end of the SSL tunnel
  • Tomalak
    Tomalak over 15 years
    And the sys admins when they grep trough the log files.
  • James McMahon
    James McMahon over 15 years
    Andrew I think he means auto complete on user input fields. For instance, Firefox remembers all data I enter in my website, so when I begin to type text into a search box it will offer to complete the text with my previous searches.
  • John Nilsson
    John Nilsson over 15 years
    Actually it isn't a "convention" it's part of the HTTP standard. The RFC is very explicit in what to expect from the different methods.
  • Andrew Moore
    Andrew Moore over 15 years
    Yes, well, that's the point of auto-complete, isn't it. What I meant was the actually history, not auto-complete.
  • Kip
    Kip over 15 years
    I would say there is some added security in that POST data won't be stored in the user's browser history, but GET data will.
  • stephenbayer
    stephenbayer over 15 years
    true, but you can also say that the keyboard is insecure because someone could be looking over your shoulder when your typing your password. There's very little difference between security through obscurity and no security at all.
  • Gavin H
    Gavin H almost 15 years
    As mentioned in this post, if data is going to be submitted and especially if it will be saved, it should not be using GET parameters. Thats one easy way for cross site scripting attacks to take place.
  • pbreitenbach
    pbreitenbach almost 15 years
    But it is harder to do a POST than a GET. A GET is just a URL in the address box. A POST requires a <form> in an HTML page or cURL.
  • pbreitenbach
    pbreitenbach almost 15 years
    I agree with this. The question is not security, it's what POST and GET are designed to do.
  • Raquel
    Raquel over 14 years
    So a fake post takes notepad and 5 minutes of time... not really much harder. I have used notepad to add features to a phone system that didn't exist. I was able to create a copy of the admin forms for the system that would allow me to assign commands to buttons that "were not possible" as far the vendor was concerned.
  • MD Sayem Ahmed
    MD Sayem Ahmed about 14 years
    @stephenbayer: Suppose that I need to send, say, order id to server to search for the corresponding order details, and then show it to the user for modification. If I use "GET", the order id will be exposed, and if the user is clever enough, he/she may change the order id in the url, which will allow him/her to see orders from other users. What should I do in that case ?
  • stephenbayer
    stephenbayer about 14 years
    it's even exposed if you use a post. in your case, the post would be slightly more secure. But seriously.. I can change post variables all day long, just as easy as get variables. Cookies can even be viewed and modified.. never rely on the information you're site is sending in any way shape or form. The more security you need, the more verification methods you should have in place.
  • Juan Pablo Califano
    Juan Pablo Califano over 13 years
    @Night Shade. How about validating that the order belongs to the user before displaying it? If the user is "clever enough" (read, if they can install any of the gazillion browser plugins that allow you modifiy the http request at will), POST doesn't buy you anything.
  • AviD
    AviD over 13 years
    ahem, CSRF is just as possible with POST.
  • Lotus Notes
    Lotus Notes over 13 years
    @AviD It's just slightly more difficult, as you'll also have to incorporate XSS to get someone else to send an undesired POST request.
  • AviD
    AviD over 13 years
    @Lotus Notes, it is very slightly more difficult, but you do not need any kind of XSS. POST requests are being sent all the time all over the place, and dont forget the CSRF can be sourced from any website, XSS not included.
  • Incognito
    Incognito over 13 years
    So, something is more secure because to "hack the planet" I need to know to type in wget --post-data 'action=delete&id=3' http://example.com/do.php' instead of simply wget http://example.com/do.php?action=delete&id=3' ? That's not more secure at all. It's virtually the same thing.
  • kibitzer
    kibitzer over 13 years
    no you have to make somebody else with privileges to type it, as opposed to a GET which will be silently fetched by the browser. considering that every POST form should be protected with verifiable source hash, and there's no such means for a GET link, your point is silly.
  • Eli
    Eli over 13 years
    Well, you could add a hash to all your GET requests exactly the same way you add them to POST forms... But you should still not use GET for anything that modifies data.
  • Aaron
    Aaron over 13 years
    HTTP over SSL/TLS (implemented correctly) allows the attacker sniffing the wire (or actively tampering) to see only two thing -- the IP address of the destination, and the amount of data going both ways.
  • DaveJ
    DaveJ over 13 years
    @kibitzer — What Eli said. Also you could send a link to the admin and when they click it you can fill and submit a form with javascript. POST doesn't functionally offer any extra security than GET, they can both be executed silently within the browser it's just that forum software tends to allow GET requests to third-party sites using images.
  • FryGuy
    FryGuy over 13 years
    Using POST over GET doesn't prevent any kind of CSRF. It just makes them slightly easier to do, since it's easier to get people to go to a random website that allows images from urls, than go to a website that you control (enough to have javascript). Doing <body onload="document.getElementById('a').submit()"><form id="a" action="http://example.com/delete.php" action="post"><input type="hidden" name="id" value="12"></form> isn't really that hard to submit a post somewhere automatically by clicking a link (that contains that html)
  • Jesse
    Jesse over 13 years
    In fact if you allow GET requests to modify state then it's possible a browser that is pre-fetching pages it thinks you might visit will accidentally take actions you didn't want it to.
  • RandomNickName42
    RandomNickName42 about 13 years
    I cant believe nobody brought this up until I did just now, POST DOES NOT LOG BY DEFAULT, GET DOES LOG, therefor, POST < GET for security. And I mean POST Parameters, sure GET can have them also, but then your talking about very a-typical activity. Sorry about the caps, I didnt mean to scream ;)
  • Simeon G
    Simeon G about 12 years
    This is completely untrue. SSL is a transport layer protocol. It connects to the server FIRST, then sends ALL Application data as an encrypted binary stream of data. Check out this thread: answers.google.com/answers/threadview/id/758002.html
  • LVM
    LVM about 12 years
    Do a TCPDump and you'll see that this is 100% true. In order to connect to the server, you have to send your request unencrypted. If you do that as a GET, your args get added to the initial request and are therefore unencrypted. Regardless of what you see in the post you linked, you can test this with TCPDump (or similar).
  • Simeon G
    Simeon G about 12 years
    Done! Just ran tcpdump on my Mac. And your answer came up 100% false. Here's the command I used: sudo tcpdump -w ssl.data -A -i en1 -n dst port 443 Then when I looked in ssl.data of course I saw gobly gook. All HTTP data was encrypted. And to make sure a normal non-ssl call worked, I used: sudo tcpdump -w clear.data -A -i en1 -n dst port 80 And sure enough, inside clear.data I had all headers and URIs showing in the clear. I tested this on my gmail and google plus (which are HTTPS) and on some non SSL pages like google.com.
  • Simeon G
    Simeon G about 12 years
    I'm not a network expert so if you think I used the wrong commands on tcpdump please feel free to correct me.
  • LVM
    LVM about 12 years
    I don't have the command offhand, but you can also check it with Wireshark/Ethereal.
  • Florian Margaine
    Florian Margaine about 12 years
    A shame you didn't talk about CSRF :-). Is there any way to contact you?
  • Incognito
    Incognito about 12 years
    @FlorianMargaine Add me on twitter and I'll DM you my email. twitter.com/#!/BrianJGraham
  • Colin 't Hart
    Colin 't Hart over 11 years
    Not true! This depends entirely on your backend as to whether code accepting POSTs also accepts GETs.
  • RocketR
    RocketR about 11 years
    This answer is totally misleading and dangerous. I can't imagine how it got so many votes. If GET and POST are the same, why do we need them at all?
  • stephenbayer
    stephenbayer about 11 years
    @RocketR POST and GET are only verbs, You can apply a few verbs to an HTTP request. The difference is mainly semantics. GET is used to get information, while POST is used to send new information, PUT is used to update information. Well that was the design idea, but people use whatever verbs they want. POST transmissions are no more secure that GET, it is in a different OSI layer that security is handled. It is dangerous to think there is a difference in security between GET and POST.
  • RocketR
    RocketR about 11 years
    @stephenbayer Please read the community answer below and you'll know the difference. I don't mean you can be secure just by using POST alone, but it's a necessary part of a bigger strategy. And it is too thoughtless to just say there's no difference without giving more context. I've seen too many Rails-people using a "catch-everything" method match in place of specific get, post, etc, who don't have a clue about CSRF.
  • Mikko Rantalainen
    Mikko Rantalainen about 11 years
    If the attacker can access full browser history, he has access to full browser auto-complete data, too.
  • griffin
    griffin almost 11 years
    That's because you're talking about specific software, and not POST vs GET - the server software I'm using doesn't log any requests at all for example, and I would never tell people to use Apache or the like anyway if security (or speed, or ease of use, or ...) is of concern.
  • Amal Murali
    Amal Murali over 10 years
    Who said Facebook is secure? Good answer though. +1.
  • kert
    kert over 10 years
    Nobody has mentioned it here, but browsers happily execute GET requests all over injecting code across random domains into clients browser - a script link can be loaded from anywhere ( which is why jsonp could exist and is actively being shunned ) Thats a fairly large attack surface.
  • kert
    kert over 10 years
    Imagine if a someone manages to quietly poison one of the popular javascript compressed libraries ( jquery ) on a prominent CDN site, both with and without SSL .. browsers dont do any code signature checking or even md5sums. just a http get ..
  • jesse reiss
    jesse reiss over 9 years
    URLs also are frequently logged, for example by nginx. POST is more secure because request bodies are rarely logged. You should never send sensitive information in a query string.
  • turkishweb
    turkishweb almost 8 years
    "[...] so this entire security through obscurity is only providing obscurity to script kiddies and jealous girlfriends.[...]" . this entirely depends on the skills of the jealous gf. moreover, no gf/bf should be allowed to visit your browser history. ever. lol.
  • PalDev
    PalDev over 4 years
    Even Google are using GET to change data, the argument that you must not use GET requests to make changes is silly, it is a historical way of how methods in forms were implemented way back in 1990's. GET is sent with the URL, POST is sent with the header. Just choose whatever is good for your applications, there aren't any strict rules here
  • Yohanim
    Yohanim almost 3 years
    if we send query string through post method, does it secure? I mean can someone using sniffing or tampering app to get query string data (like wireshark or burp suite)