I am successfully able to authenticate Facebook and Google accounts using my Oauth2 servlets. I am using state with a timer and a session cookie to try to verify that it is indeed a legitimate Oauth callback.
Is there any benefit if I also examine the HTTP Referer header to ensure that I was redirected from the provider's OAuth page?
If no benefit, could there be a problem if I also examine the HTTP Referer field?
No.
I can simulate any headers I want as a malicious attacker. I can make it look like I'm coming from http://cia.fbi.gov.vpn/uber1337h4x. This is obvious and well known.
Any pages coming from HTTPS do not send a refer header as per RFC2616 sec15:
Clients SHOULD NOT include a Referer header field in a (non-secure) HTTP request if the referring page was transferred with a secure protocol.
Breaks usability as per RFC2616 sec15:
Because the source of a link might be private information or might reveal an otherwise private information source, it is strongly recommended that the user be able to select whether or not the Referer field is sent.
In short, you are not given greater security. Your security is not in inspecting a vastly insecure transport protocol, it's in the OAuth layer. You also break usability.
Don't do it.
The answer is:
No, you shouldn't use it, and there is NO valuable benefit of doing it.
Authorization Servers are very aware of this also. And here was stated.
From the mailing list of OAuth-WG:
Callback URL pages SHOULD redirect to a trusted page immediately after receiving the authorization code in the URL. This prevents the authorization code from remaining in the browser history, or from inadvertently leaking in a referer header.
If you are worry about CSRF, you SHOULD NOT use the HTTP Referer as a technique to verify the origin of an authorization, that's why the parameter state is (which sound you're using).
If you worry about an specific security concern of the oauth2 protocol, there is a full section inside the draft.
If you worry about other Security Considerations, this is the source.
I suggest you give all your effort implementing all the validations around the param: state.
Edit:
After reading the nuances of the question, you are really answered your own question. The use of cookies (probably HTML5 local storage) for both cases, is the best solution we know so far.
The first nuance is about CSRF and one of the possible countermeasures available is Checking the HTTP Referer header, and this was already addressed in the protocol.
The second nuance, I'm not completly sure, but is probably a case of Extension Grant, this is because it sounds that you may work as an "auth proxy requester", same as SAML oauth2 extension.
Don't verify the HTTP referer; the "state" parameter (which it sounds you're using) is the approach OAuth 2.0 defines to defend against cross-site request forgery (CSRF) attacks.
You may want to have a look at the new O'Reilly book Getting Started with OAuth 2.0 by Ryan Boyd. It describes this and related security considerations.
Plain security was not a concern of the question because the state parameter is being used.
The main concerns I had in mind were:
Whether it is the same browser that my app sent to Facebook that's coming back to present a candidate token?
Whether the agent (browser-like agent) or agents are repeatedly doing OAuth requests and presenting me with bad OAuth tokens that cause my app to repeatedly contact Facebook with bad tokens leading to potentially adverse treatment by Facebook.
The only possible solution to the first problem is to also set a cookie in addition to using state. referer would help if most providers weren't using https.
The second problem has a nuance. The mis-behaving agents need not be directly controlled by a malicious entity. They may be normal users browsers redirected via some indirect means (a popular hijacked website, social engineering).
Because of the nuance there is a chance that the referer header may not be forged. However, https precludes any meaningful benefit.
Cookies definitely help in the second case also because if you are setting cookies in a POST no third-party website can cause them to be set and you cannot be flooded with bad OAuth responses due to hacked websites redirecting users en masse to OAuth you.
This is not a clear answer (or question) but hopefully this shows the nuances behind the question.
Related
I was reading articles about `JWT` security in SPA apps, but got confused about it being prone to many types of attacks, and unintuitively hard to grasp and set up.
As far as I am aware, this whole thing with the user-friendly security is about a user staying logged in even after a browser restart, and about still being protected from CSRF attacks.
I read some crazy approaches using localStorage, cookies, or in-memory values, and about setting some flags like httpOnly on cookies, and some headers in a browser, while being vulnerable to stuff like XSS or CSRF attacks if not set properly.
So, my question is if the following security scheme would work?:
store JWT token anywhere on user's device (localStorage, cookies, whatever,...) (as a public information, readable by anyone)
backend would return an anti-CSRF header on each request
app would store and refresh the header value in a memory every time and consecutively send it to prove being the originally logged-in user
an attacker could eventually get the JWT and/or try some XSS or CSRF, but it would be useless, because he wouldn't know the anti-CSRF header value
(Note that with such an approach I basically consider the JWT token to represent authentication, and the CSRF header to represent authorization.)
the answer to your question is no.
If i manage to do a XSS on your site, i will have access to everything that your javascript has access to and that includes both the CSRF token, and the JWT. Its your javascript that will run my malicious javascript, which means i have all access to everything you have.
JWT tokens as session trackers are very bad from many perspectives. Cookies have been around since Netscape created them back in the late 90s. They have been enhanced with several security features like HttpOnly flags etc which JWTs just don't have.
JWTs are good if you have server to server stateless communication, since you can include claims, which add extra information so that the server doesn't need to do extra calls to for instance an issuers /userInfo endpoint.
Server to server communication is also usually done in secured networks so the risk for token stealing or MITMs are reduced.
Security is hard, much harder than many think, there is no one "easy solution" you need to protect your sites from multiple different attacks, and combination of these.
You should NEVER build your own custom solutions, because there is always people smarter that can break custom solutions.
And you should constantly consult the OWASP Cheat Sheet series which tries to gather everything you should think about when building modern web pages.
I was using Fiddler see on-the-field how web sites use cookies in their login systems. Although I have some HTTP knowledge, I'm just just learning about cookies and how they are used within sites.
Initially I assumed that when submitting the form I'd see no cookies sent, and that the response would contain some cookie info that would then be saved by the browser.
In fact, just the opposite seems to be the case. It is the request that's sending in info, and the server returns nothing.
When fiddling about the issue, I noticed that even with a browser cleaned of cookies, the client seems to always be sending a RequestVerificationToken to the server, even when just looking around withot being signed in.
Why is this so?
Thanks
Cookies are set by the server with the Set-Cookie HTTP response header, and they can also be set through JavaScript.
A cookie has a path. If the path of a cookie matches the path of the document that is being requested, then the browser will include all such cookies in the Cookie HTTP request header.
You must make sure to be careful when setting or modifying cookies in order to avoid XSS attacks against your users. As such, it might be useful to include a hidden and unique secret within your login forms, and use such secret prior to setting any cookies. Alternatively, you can simply check that HTTP Referer header matches your site. Otherwise, a malicious site can copy your form fields, and create a login form to your site on their site, and do form.submit(), effectively logging out your user, or performing a brute-force attack on your site through unsuspecting users that happen to be visiting the malicious web-site.
The RequestVerificationToken that you mention has nothing to do with HTTP Cookies, it sounds like an implementation detail that some sites written in some specific site-scripting language use to protect their cookie-setting-pages against XSS attacks.
When you hit a page on a website, usually the response(the page that you landed on) contains instructions from the server in the http response to set some cookies.
Websites may use these to track information about your behavior or save your preferences for future or short term.
Website may do so on your first visit to any page or on you visit to a particular page.
The browser would then send all cookies that have been set with subsequent request to that domain.
Think about it, HTTP is stateless. You landed on Home Page and clicked set by background to blue. Then you went to a gallery page. The next request goes to your server but the server does not have any idea about your background color preference.
Now if the request contained a cookie telling the server about your preference, the website would serve you your right preference.
Now this is one way. Another way is a session. Think of cookies as information stored on client side. But what if server needs to store some temporary info about you on server side. Info that is maybe too sensitive to be exposed in cookies, which are local and easily intercepted.
Now you would ask, but HTTP is stateless. Correct. But Server could keep info about you in a map, whose is the session id. this session id is set on the client side as a cookie or resent with every request in parameters. Now server is only getting the key but can lookup information about you, like whether you are logged in successfully, what is your role in the system etc.
Wow, that a lot of text, but I hope it helped. If not feel free to ask more.
I am using Backbone.js and it communicates with a stateless rest API. Some calls require authentication, through HTTP basic.
What I don't understand is, somehow I have to authenticate each request, how could I do this securely? My first thought was to have a cookie, store the username and password but this would be vulnerable?
Can this be done securely?
There are two themes to this question. One is about security and one seems to be about REST rules.
The way to do authentication securely, is to pass that data through an SSL connection. It's the only way to securely transfer data over the wire.
With regards to sending authentication using basic auth over each request (REST), not many people I know do this in reality.
There's always a big long discussion on how much security is enough security and it really depends on your application and what the purpose is. I know this isn't the definitive answer you might be looking for but I'll just give you my take and how I'm going about dealing with the issues you mention.
With RESTful apps, the story is one should authenticate each request but in real practice I find this is more a "guide" than a hard rule. Rare is the fully RESTful application that follows all the rules. I use an encrypted cookie to store the user session data with a standard authentication flow that happens once and expires in a week. Data transfers happen through SSL to prevent MITM attacks and a modified Backbone sync sends a CSRF token along with each POST, PUT, DELETE to prevent cross site request forgeries. Probably "good enough" for the social app that I am working on. Maybe not if you're doing bank wire transfers and stuff. Hope this sort of gives you a point of reference in judging what you might want to do.
Is https://github.com/fiznool/backbone.basicauth something you'd find useful?
This plugin enables access to remote resources which are protected by HTTP Basic Authentication through your Backbone Models and Collections.
How does it work?
A resource protected with HTTP Basic Authentication requires the following HTTP header to be set on every request:
Authorization: Basic
The access token is formed by taking the username and password, concatenating together with a : separator and encoding into Base64.
This plugin handles the Base64 encoding and automatically sets the Authorization header on every request which uses Backbone.sync.
I have a webapplication (asp.net 3.5) with mixed SSL. All account related pages are delivered over SSL. Mostly all other pages are delivered over non-ssl. To automatically switch between HTTPS and HTTP I use this component. Lately there was a news item regarding the ability toch hijack user sessions on non-secure Wifi networks. This should be possible by catching the Cookie that is transmitted over non-ssl connections.
This triggered me to review my security choices in this webapplication. I've (again) grabbed this article from MSDN and tried the requireSSL=true property on my Formsauthentication. Before I've even started the webapplication I realized that my User.Identity will be null on non-SSL pages because the cookie containing this information isn't sent from and to the webbrowser.
I need a mechanism that Authenticates the user over a SSL connection... and remembers this authentication info, even on non-SSL pages.
While searching SO, I've found this post. It's seems to me that this is a good solution. But, I wonder if a solution can be found in storing login information in the Sessionstate? I'm thinking of catching the Application_AuthenticateRequest in the Global.asax. Checking if the connection is secure and check either the authcookie or Session. I don't know exactly how I'm going to implement this yet. Maybe you can think with me on this?
Unfortunately, you have conflicting requirements. You can't have a secure session over non-SSL, so I'd like to challenge your underlying assumption: why not have the whole site use SSL?
From the MVC FAQ (similar question answered by security guru Levi) asking for an attribute to not use SSL.
•The [RequireHttps] attribute can be used on a controller type or action method to say "this can be accessed only via SSL." Non-SSL requests to the controller or action will be redirected to the SSL version (if an HTTP GET) or rejected (if an HTTP POST). You can override the RequireHttpsAttribute and change this behavior if you wish. There's no [RequireHttp] attribute built-in that does the opposite, but you could easily make your own if you desired.
There are also overloads of Html.ActionLink() which take a protocol parameter; you can explicitly specify "http" or "https" as the protocol. Here's the MSDN documentation on one such overload. If you don't specify a protocol or if you call an overload which doesn't have a protocol parameter, it's assumed you wanted the link to have the same protocol as the current request.
The reason we don’t have a [RequireHttp] attribute in MVC is that there’s not really much benefit to it. It’s not as interesting as [RequireHttps], and it encourages users to do the wrong thing. For example, many web sites log in via SSL and redirect back to HTTP after you’re logged in, which is absolutely the wrong thing to do. Your login cookie is just as secret as your username + password, and now you’re sending it in cleartext across the wire. Besides, you’ve already taken the time to perform the handshake and secure the channel (which is the bulk of what makes HTTPS slower than HTTP) before the MVC pipeline is run, so [RequireHttp] won’t make the current request or future requests much faster.
I have been investigating this for some time, but I haven't found anything to satisfy my curiosity. Is it possible, as a user, to be the victim of a CSRF attack if cookies are disabled. Obviously CSRF depends on the users browser to send the user's credentials with the forged request to the legitimate server. Besides IP addresses, browsers don't automatically send in any other session values do they? In that case, as long as a user can login with cookies disabled, they would be safe from CSRF even on vulnerable websites.
So, you have to ask yourself how does the server know one client from another? In majority of cases, it is the session cookie, but there are other ways as well.
Consider an admin application, that is configured to work only if accessed from localhost. Here, the server is trusting the IP Address of the browser. Now, if an attacker creates a page like <img src="http://localhost/do/something/harmful"/>, and somehow gets the administrator to visit his page, you have a CSRF.
Other examples include abusing Http basic and digest authentication, as Bruno already pointed out.
There are other forms of authentication supported by browsers, in particular HTTP Basic and HTTP Digest, as well as SSL/TLS client-certificates. Unfortunately, the interface to "log out" when using these mechanisms is usually fairly poor. Unlike cookies and forms, stopping to use the credentials is controlled by the browser (not by the server and its cookies), but the buttons are at best in some advanced menu in general (if they exist at all).