How secure is a HTTP POST? - security

Is a POST secure enough to send login credentials over?
Or is an SSL connection a must?

SSL is a must.
POST method is not more secure than GET as it also gets sent unencrypted over network.
SSL will cover the whole HTTP communication and encrypt the HTTP data being transmitted between the client and the server.

<shameless plug>I have a blog post that details what an HTTP request looks like and how a GET request compares to a POST request. For brevity's sake, GET:
GET /?page=123 HTTP/1.1 CRLF
Host: jasonmbaker.wordpress.com CRLF
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 CRLF
Connection: close CRLF
and POST:
POST / HTTP/1.1 CRLF
Host: jasonmbaker.wordpress.com CRLF
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1 CRLF
Connection: close CRLF
CRLF
page=123
(The CRLF is just a newline)
As you can see, the only differences from the standpoint of how a request is formed* is that a POST request uses the word POST and the form data is sent in the body of the request vs the URI. Thus, using HTTP POST is security by obscurity. If you want to protect data, you should use SSL.
* Note that there are other differences.

That depends on your circumstances, how much would the interception of the credentials cost somebody?
If it's just a login to a software Q+A site then SSL might not be necessary, if it's an online banking site or you store credit card data then it is.
This is a business not a techncial decision.

HTTP POST is not encrypted, it can be intercepted by a network sniffer, by a proxy or leaked in the logs of the server with a customised logging level. Yes, POST is better than GET because POST data is not usualy logged by a proxy or server, but it is not secure.
To secure a password or other confidential data you must use SSL or encrypt the data before you POST. Another option would be to use Digest Authentication with the browser (see RFC 2617). Remember that (home grown) encryption is not enough to prevent replay attacks, you must concatenate a nonce and other data (eg. realm) before encrypting (see RFC 2617 for how it is done in Digest Auth).

SSL is a must :)
HTTP Post is transmitted in plain text. For an example, download and use Fiddler to watch HTTP traffic. You can easily see the entire post in there (or via a network traffic monitor like WireShark)

It is not secure. A POST can be sniffed just as easily as a GET.

No...POST is not secure enough at all. SSL is a MUST.
POST only effectively hides the parameters in the query string. Those parameters can still be picked up by anybody looking at the traffic in between the browser and the end point.

No, use SSL.
With POST the values are still submitted as plain text unless SSL is used.

The most secure way is to not send credentials at all.
If you use Digest Authentication, then SSL is NOT a must.
(NB: I am not implying that Digest Authentication over HTTP is always more secure than using POST over HTTPS).

POST is plaintext.
A secure connection is a must.
That's why it's called a secure connection.

A POST request alone is not secure because all the data is "traveling" in plain text.
You need SSL, to make it secure.

The only difference between HTTP GET and HTTP POST is the manner in which the data is encoded. In both cases it is sent as plain-text.
In order to provide any sort of security for login credentials, HTTPS is a must.
You do not need an expensive certificate to provide HTTPS either. There are many providers that will issue very basic certificates for about $20USD. The more expensive ones include identity verification which is more of a concern for e-commerce sites.

Please see this great article:
Protect Against Malicious POST Requests
https://perishablepress.com/protect-post-requests/

POST data is sent in plain text if you are using an unencrypted HTTP connection.
IF this is secure enough depends on your usage (hint: it's not).
If both the server, the client machine and ALL MACHINES BETWEEN THEM are part of a controlled, fully trusted network, this may be ok.
Outside of these very limited circumstances (and sometimes even within them) plain text authentication is asking for trouble.

Related

Sending cookies between servers vs sending headers

I'm a bit naive about how to send cookie data between servers. I am aware that in the HTTP request you use Set-Cookie.
Right now, I am sending a header between the servers, for authorization purposes, so that one server is authorized with the other. But I am wondering if there is some advantage to using cookies, if cookies act differently than headers in this case. From what I have read, cookies and headers are one and the same for most purposes?
Using two Node.js servers, one being the web server, the other being the API server, is there any reason why sending a cookie vs a regular non-cookie header is better?
The "cookie" represents shared state between the client and the server. As was mentioned, the way to set cookie values, is to use the Set-Cookie header. And the way to communicate values that have already been set is to use the Cookie header.
Cookies are typically associated with web browsers, as tool to track and identify existing users. I've never seen cookies used for server to server communication.
The Authorization header is good for passing encoded or encrypted strings.
So for example you might see:
Authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
The value in this case is the base64 encoded string of "username:password"
I wouldn't worry too much about what header you use. You can make up your own x-my-awesome-auth-header: Its conventional to prefix a custom header with an "x".
An important thing to consider, is what the header value contains. If you are communicating over plain http make sure you encrypt.
Also consider using open source standards for passing encrypted data such as JWT
Edit: To answer your question, is there any reason why sending a cookie is better? When it comes to server to server communication, its actually much worse to use Cookies, because those servers have to maintain state with other servers. eg. When A talks to B, A has to remember what B said when they talk again. You typically what server to server communication to be stateless, meaning you can throw away data pertaining to authorization and permission after each transaction. Each transaction has to go through the full authorization and permission resolution process. Its much easier to code, and there is no penalty in terms of security as long as your are protected via encryption
Yes, "cookies" is just jargon for the Cookie: HTTP header and corresponding Set-Cookie: header. So they are ultimately the same basic thing. Many APIs use the slightly more semantic Authorization: header, so that would be a good place to start.

Are security concerns sending a password using a GET request over https valid?

We have webpage which uses the sapui5-framework to build a spa. The communication between the browser and the server uses https. The interaction to log into the page is the following:
The user opens the website by entering https://myserver.com in the browser
A login dialogue with two form fields for unsername and password is shown.
After entering username and password and pressing the login-button
an ajax-request is send using GET to the URL: https://myusername:myPassword#myserver.com/foo/bar/metadata
According to my understanding using GET to send sensitive data is never a good idea. But this answer to HTTPS is the url string secure says the following
HTTPS Establishes an underlying SSL conenction before any HTTP data is
transferred. This ensures that all URL data (with the exception of
hostname, which is used to establish the connection) is carried solely
within this encrypted connection and is protected from
man-in-the-middle attacks in the same way that any HTTPS data is.
An in another answer in the same thread:
These fields [for example form field, query strings] are stripped off
of the URL when creating the routing information in the https packaging
process by the browser and are included in the encrypted data block.
The page data (form, text, and query string) are passed in the
encrypted block after the encryption methods are determined and the
handshake completes.
But it seems that there still might be security concerns using get:
the URL is stored in the logs on the server and in the same thread
leakage through browser history
Is this the case for URLs like?
https://myusername:myPassword#myserver.com/foo/bar/metadata
// or
https://myserver.com/?user=myUsername&pass=MyPasswort
Additional questions on this topic:
Is passsing get variables over ssl secure
Is sending a password in json over https considered secure
How to send securely passwords via GET/POST?
On security.stackexchange are additional informations:
can urls be sniffed when using ssl
ssl with get and post
But in my opinion a few aspects are still not answered
Question
In my opinion the mentioned points are valid objections to not use get. Is the case; is using get for sending passwords a bad idea?
Are these the attack options, are there more?
browser history
server logs (assuming that the url is stored in the logs unencrypted or encrypted)
referer information (if this is really the case)
Which attack options do exist when sending sensitive data (password) over https using get?
Thanks
Sending any kind of sensitive data over GET is dangerous, even if it is HTTPS. These data might end up in log files at the server and will be included in the Referer header in links to or includes from other sides. They will also be saved in the history of the browser so an attacker might try to guess and verify the original contents of the link with an attack against the history.
Apart from that you better ask that kind of questions at security.stackexchange.com.
These two approaches are fundamentally different:
https://myusername:myPassword#myserver.com/foo/bar/metadata
https://myserver.com/?user=myUsername&pass=MyPasswort
myusername:myPassword# is the "User Information" (this form is actually deprecated in the latest URI RFC), whereas ?user=myUsername&pass=MyPasswort is part of the query.
If you look at this example from RFC 3986:
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
| _____________________|__
/ \ / \
urn:example:animal:ferret:nose
myusername:myPassword# is part of the authority. In practice, use HTTP (Basic) authentication headers will generally be used to convey this information. On the server side, headers are generally not logged (and if they are, whether the client entered them into their location bar or via an input dialog would make no difference). In general (although it's implementation dependent), browsers don't store it in the location bar, or at least they remove the password. It appears that Firefox keeps the userinfo in the browser history, while Chrome doesn't (and IE doesn't really support them without workaround)
In contrast, ?user=myUsername&pass=MyPasswort is the query, a much more integral part of the URI, and it is send as the HTTP Request-URI. This will be in the browser's history and the server's logs. This will also be passed in the referrer.
To put it simply, myusername:myPassword# is clearly designed to convey information that is potentially sensitive, and browsers are generally designed to handle this appropriately, whereas browsers can't guess which part of which queries are sensitive and which are not: expect information leakage there.
The referrer information will also generally not leak to third parties, since the Referer header coming from an HTTPS page is normally only sent with other request on HTTPS to the same host. (Of course, if you have used https://myserver.com/?user=myUsername&pass=MyPasswort, this will be in the logs of that same host, but you're not making it much worth since it stays on the same server logs.)
This is specified in the HTTP specification (Section 15.1.3):
Clients SHOULD NOT include a Referer header field in a (non-secure) HTTP request if the referring page was transferred with a secure protocol.
Although it is just a "SHOULD NOT", Internet Explorer, Chrome and Firefox seem to implement it this way. Whether this applies to HTTPS requests from one host to another depends on the browser and its version.
It is now possible to override this behaviour, as described in this question and this draft specification, using a <meta> header, but you wouldn't do that on a sensitive page that uses ?user=myUsername&pass=MyPasswort anyway.
Note that the rest of HTTP specification (Section 15.1.3) is also relevant:
Authors of services which use the HTTP protocol SHOULD NOT use GET based forms for the submission of sensitive data, because this will cause this data to be encoded in the Request-URI. Many existing servers, proxies, and user agents will log the request URI in some place where it might be visible to third parties. Servers can use POST-based form submission instead
Using ?user=myUsername&pass=MyPasswort is exactly like using a GET based form and, while the Referer issue can be contained, the problems regarding logs and history remain.
Let assume that user clicked a button and following request generated by client browser.
https://www.site.com/?username=alice&password=b0b123!
HTTPS
First thing first. HTTPS is not related with this topic. Because using POST or GET does not matter from attacker perspective. Attackers can easily grab sensitive data from query string or directly POST request body when traffic is HTTP. Therefor it does not make any difference.
Server Logs
We know that Apache, Nginx or other services logging every single HTTP request into log file. Which means query string ( ?username=alice&password=b0b123! ) gonna be written into log files. This can be dangerous because of your system administrator can access this data too and grab all user credentials. Also another case could be happen when your application server compromise. I believe you are storing password as hashed. If you use powerful hashing algorithm like SHA256, your client's password will be more secure against hackers. But hackers can access log files directly get passwords as a plain-text with very basic shell scripts.
Referer Information
We assumed that client opened above link. When client browser get html content and try to parse it, it will see image tag. This images can be hosted at out of your domain ( postimage or similar services, or directly a domain that under the hacker's control ) . Browser make a HTTP request in order to get image. But current url is https://www.site.com/?username=alice&password=b0b123! which is going to be referer information!
That means alice and her password will be passed to another domain and can be accessible directly from web logs. This is really important security issue.
This topic reminds me to Session Fixation Vulnerabilities. Please read following OWASP article for almost same security flaw with sessions. ( https://www.owasp.org/index.php/Session_fixation ) It's worth to read it.
The community has provided a broad view on the considerations, the above stands with respect to the question. However, GET requests may, in general, need authentication. As observed above, sending user name/password as part of the URL is never correct, however, that is typically not the way authentication information is usually handled. When a request for a resource is sent to the server, the server generally responds with a 401 and Authentication header in the response, against which the client sends an Authorization header with the authentication information (in the Basic scheme). Now, this second request from client can be a POST or a GET request, nothing prevents that. So, generally, it is not the request type but the mode of communicating the information is in question.
Refer http://en.wikipedia.org/wiki/Basic_access_authentication
Consider this:
https://www.example.com/login
Javascript within login page:
$.getJSON("/login?user=joeblow&pass=securepassword123");
What would the referer be now?
If you're concerned about security, an extra layer could be:
var a = Base64.encode(user.':'.pass);
$.getJSON("/login?a="+a);
Although not encrypted, at least the data is obscured from plain sight.

HTTP Referer for Single Sign On

As part of a project with a partner, we are required to provide single-sign-on service on our app. Basically, people will log in through our partner's website, then they are redirected to ours. The redirected request will have the user's data in the HTTP header fields.
Here's where it gets "iffy". The process of authenticating if this request is valid or not is dependent on the value of the HTTP Referer field. Our partner tells us to check this field to see that the source is a legitimate one.
Now I know (and I'm glad to be proven wrong) that this field is easy enough to forge, and since no other method of authentication is given to us, a malicious user could easily construct a false HTTP request and gain access to our web app.
I'm a programmer first, and admittedly know very little about the intricacies of HTTP. So are my concerns real? Would using SSL (somehow) void this concern?
Remember that rule number one is never trust client input. Like any other client input, the Referer header is trivial to forge. SSL does nothing for you because you still rely on client input. Also, note that browsers SHOULD NOT send Referer to http pages when referred by https pages.
Additionally, consider that many privacy-conscious people and proxies (that individuals may not have any control over) might strip Referer headers from their requests, breaking your scheme.
To do this properly, you need to use something like OAuth or OpenID, where the protocols have been designed to be secure.
The HTTP Referrer header is unreliable: depending on the browser used it may not be sent.
Does http-equiv="refresh" keep referrer info and metadata?
Yes - It is forgeable.
No - A client can just as easily send a (fake) HTTPS request as a (fake) HTTP request. The only difference is the connection is encrypted. It says nothing about the data transmitted.
That being said, it is another precaution that can be used. It should not be relied upon for security, however.
I would look at Microsoft Federation -- it's likely overkill, but it shows one way to implement SSO securely.

Safe to send login credentials using HTTP and not HTTPS?

Is it safe to submit an HTTP POST whose body contains plaintext username and password, or is HTTPS completely necessary?
HTTPS is required. All HTTP traffic can be sniffed.
No, HTTP alone does not give you any security at all. If someone is able to read the network traffic, they would be able to read the credentials too.
The network traffic might also be protected separately, but you can’t control the network. But you can control your application. So HTTPS ist a must.
It's never safe to send an unencrypted, plaintext username and password over a wire others have access to.
While it's safe to send encrypted data over HTTP, HTTPS does this for you, giving you the added benefit of TLS. Given how well it stands up theoretically and in practice, it's far more compelling to use than inventing your own algorithm.

REST vs Security

Couple of days back, i came across news about how hackers Stole 200,000+ Citi Accounts Just By Changing Numbers In The URL. Seems like Developers compromised security for being RESTful and also didn't bothered to keep session id in place of userId. I'm also working on a product where security is the main concern so I'm wondering whether we should avoid REST and use post requests everywhere in such a case? or am I missing something important about REST ?
Don't blame the model for a poor implementation, instead learn from the mistakes of others.
That's my (brief) opinion, but I'm sure better answers will be added :)
(P.S. - using Post doesn't increase the security in any way)
The kind of security issues mentioned in the question have largely nothing to do with REST, SOAP or Web. It has got to do with how one designs the applications.
Here is another common example. Say, there is a screen in an e-commerce application to show the details of an order. For a logged in user, the URL may look like this:
http://example.com/site/orders?orderId=1234
Assuming that orders are globally unique (across all users of that system), one could easily replace that orderId with some other valid OrderId not belonging to the user and see the details. The simple way to protect this is to make sure that the underlying query (SQL etc) has user's Id also added as conjunction (AND in a WHERE clause for SQL).
In this specific case, a good application design would have ensured that the account id coming in the URL is verified with the associated authenticated session.
The same data gets transmitted across the wire whether you use GET or POST. Here is a sample GET request that is the result of submitting a form [took out User-Agent value because it was long]:
GET /Testing/?foo=bar&submit=submit HTTP/1.1
Host: localhost
User-Agent: ...
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://localhost/Testing/demoform.html
Now here's the same request as a POST:
POST /Testing/ HTTP/1.1
Host: localhost
User-Agent: ...
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://localhost/Testing/demoform.html
Content-Type: application/x-www-form-urlencoded
Content-Length: 21
foo=bar&submit=submit
Note that this is what the server sees when you submit the request or what a man-in-the-middle attacker might see while intercepting the request.
In the GET we see that foo = bar and submit = submit on the first line of the request. In the POST we have to look at the last line to see that...hey! foo = bar and submit = submit. Same thing.
At the browser level, the difference manifests itself in the address bar. The first request shows the ?foo=bar&submit=submit string and the second one does not. A malicious person that wants to intercept this data doesn't care about what appears in the browser's address bar. The main danger comes about because anyone can copy a URL out of the address bar and pass it around thus leaking the parameters; in fact it is very common for people to do that.
The only way to keep our malicious person from seeing either of these types of requests is for it all to be encrypted before it is sent to the server. The server provides the public key which is used (via the https protocol and SSL/TLS). The browser uses the key to encrypt the request and the server decrypts it with its private key. There is still an issue on the client side as to whether the key it received from the server actually belongs to the people running the server. This has to be verified via some out of band trust system like a third party verification or fingerprint comparisons or something like that.
All this is completely orthogonal to REST. Regardless of how you do it, if you are communicating information across the wire with HTTP you are going to have this issue and you're going to need to encrypt the requests/responses to prevent malicious people from seeing them.
POST requests are no safer than RESTful requests, which are no safer than GET requests.
There are a range of measures to increase the security of your application, that cannot all be listed here. Wikipedia has a good number of them and methods to prevent them.
Here's an example: GET requests shouldn't be used for critical actions such as withdrawing a bank account, because if you're logged into your bank account, someone can set a rouge image with the source as http://yourbank.com/actions/withdraw/300USD , and the URL will be loaded, withdrawing money from your bank account. This is easily countered by using a POST request.
And then, we have some further security considerations to take dealing with this post request, because again it can be spoofed.
Using POST instead of GET as a security measure is simply a use of "security through obscurity". In reality it is no safer as any one with a small amount of knowledge of HTTP can forge a POST request.
Using sessions ids instead of user ids is also just another way of obscuring the security hole, it's not really fixing the problem as session ids can be hijacked too.
The fact that in this particular case security hole was made extremely easy to exploit by changing the URL does not make the use of REST the cause of the security issue.
As others have mentioned, whenever you need to secure REST services, HTTPS is the place to start looking.
I would consider REST and all web applications security concerns very similar.
The problem stated in the question is considered "school" error - something experienced web developer would not do. So if you understand web app security - you'll understand REST security as well.
So add experienced web developer to your team if you don't have any - he'll help you with REST.
If security is the main concern, exclusively use https:// and POST, never http:// and GET.
This will avoid the attack you describe as well as many others such as session hijacking, and simple eavesdropping on the line.
(... and, abstain from making the mistake of authenticating with https:// and switching to http:// later, which was "de facto standard" until a few months ago when someone published a tool which did the obvious)

Resources