Should sensitive data ever be passed via the query string as opposed to the POST request? I realize that the query string will be encrypted, but are there other reasons to avoid passing data in the query string, such as shoulder surfing?
-
Re: the SO question you linked to: yes, the URL is encrypted, but a man-in-the-middle can often still tell what website you are visiting based on the IP (and other metrics, such as amount of data transferred). If you have SNI enabled (your browser probably does), the domain is actually sent in plain text before upgrading to SSL.– Tom MarthenalCommented Jan 25, 2013 at 22:33
-
2@TomMarthenal But the pertinent part (for this question) is that the query string is encrypted during transmission.– C. RossCommented Jan 25, 2013 at 23:18
-
agreed, just wanted to throw that out there for anybody else reading.– Tom MarthenalCommented Jan 26, 2013 at 4:37
6 Answers
If the query string is the target of a user-clickable link (as opposed to a URL used from some Javascript), then it will appear in the URL bar of the browser when the corresponding page is loaded. It has the following issues:
- The URL will be displayed. Shoulder surfers may see it and learn things from that (e.g. a password).
- The user may bookmark it. This can be a feature; but it also means that the data gets written on the disk.
- Similarly, the URL will make it to the "history" so it will be written to disk anyway; and it might be retrieved afterwards. For instance, if the browser is Chrome, then a lunch-time attacker just has to type Ctrl+H to open the "history tab" and obtain all the query strings.
- If page is printed, the URL will be printed, including any sensitive information.
- URLs including query strings are also frequently logged on the web server, and those logs may not be secured appropriately.
- There are size limitations on the query string, which depend on the browser and the server (there is nothing really standard here, but expect trouble beyond about 4 kB).
Therefore, if the query string is a simple link target in an HTML page, then sensitive data should be transmitted as part of a POST form, not encoded in the URL itself. With programmatic downloads (the AJAX way), this is much less of an issue.
-
12also the URL will be printed out if the user goes to print that page.– rookCommented Jan 23, 2013 at 21:04
-
1You can also add that if bookmarks are synchronized across devices, the sensitive information goes along.– AlphaCommented Feb 1, 2013 at 21:28
-
1URLs with qstrings are also frequently logged on the web server, and those logs may not have the best security applied.– AndyCommented Apr 17, 2015 at 20:11
-
1Transmitting sensitive data in forms isn't a silver bullet either, in the event you have a XSS flaw anywhere in your site that can reach that form. Commented Jul 21, 2016 at 23:59
In addition to the other answers here, the query string is also stored in the webserver's logfiles, HTTP Proxies, and can even be seen if SSL is used in conjunction with a SSL monitoring tools like Bluecoat.
No, sensitive data should not be sent via a HTTP "GET" and should always be sent via "POST"
Edit:
One more reason you should use a POST is because GETs are more susceptible to CSRF attacks
-
Nice! I forgot all about the IIS logs. Shame on me! Commented Jan 23, 2013 at 20:39
-
Thanks DavidStratton - though I learned it from @drjimbob on this similar Sec.Se question here: security.stackexchange.com/a/12535/396 Commented Jan 24, 2013 at 15:20
Sensitive data should be passed either:
- Secure HTTP-only cookies (secure meaning SSL only; and HTTP-only meaning javascript can't access) (e.g., a random token identifying that you have logged in), or
- POST variables (over SSL).
Three reasons:
- Your computer by default typically logs the query string (in the browser history),
- The webserver at the other end by default logs the query string. This is bad if say passwords are being passed around that the webserver smartly only stores strong key-strengthened cryptographic hashes with random salts (e.g., bcrypt) to prevent the passwords being inadvertently obtained by attackers. Obviously, its not hard to log POST variables if you need to, but its not typically done.
- Sensitive data should generally only be passed when an action of some sort is being done based on that sensitive data; and in cases where you are doing some sort of action (like logging in; passing secure data to be stored/acted on in a database) you should use POST versus GET.
Generally the rules that prevent cross-site request forgeries (CSRF also known as XSRF) only get triggered for POST requests. GET is the intended HTTP request method for retrieving data from a web server that has no other effect (besides benign stuff like populating a log file saying this page was requested); POST is the protocol for a user to send data to do some action (e.g., like order something from a website; transfer money from your bank account; change your password). That is a random CSRF token typically is required by most frameworks for GET requests, but will often be required for POST requests.
(And while Thomas Pornin and makerofthings7 touched on 1 and 2, respectively I've mentioned both previously in a somewhat similar question. )
-
I was looking for that answer! In fact I give all credit to you since that answer is where I learned of this IIS issue first. Commented Jan 24, 2013 at 15:22
-
I'm guessing passing sensitive data in headers over SSL would also be safe? and perhaps should be added as no 3.– olfekCommented Mar 31, 2019 at 16:48
If it can be avoided I always avoid it. It's just one more attack surface that should be left closed unless there's a legitimate need to allow data to be passed in the query string.
There's always also the off chance that you or a future developer won't properly filter/sanitize the data, and open the attack surface even wider. Even in an insecure app, if you accidentally allow for an injection, a malicious attacker and inject XSS and XSRF script into your DB and use your non-sensitive app to attack others, so it's just best to play it safe.
Shoulder surfing is another legitimate concern, depending on the environment. If your app is going to be used in a place where it's possible (a library, a cubicle that someone can look into, and office with a desk facing the wrong direction, etc) it's a potential concern. If the people using your app are all in rooms where the desk is pointed so that shoulder surfing isn't a problem, don't worry about it. but if you don't know that for sure, and you don't know that it will always be that way, it's a concern.
Based on OWASP REST Security Cheat Sheet https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html
In GET requests sensitive data should be transferred in an HTTP Header.
It is worth noting that in many ways query strings are just as secure as other parts of the request
Query strings are encrypted with HTTPS - without an https MITM no one else will see it outside of the users computer
Post data is visible to the end user, in the developer tools
Headers are also visible in the tools.
Its not uncommon to pass sensitive data in query strings
Nearly very OAuth2/SAML process will send an access token back from the IdP to the SP in a query string - these tokens tend to be short lived/single use - as the SP will replace it using a server to server POST request.
Password reset links in email will have a token, but its normally invalidated after use.
Magic login links, used by Slack and others, again have single use tokens in the query string.