Demystifying CSRF? - security

I've read through a lot of long explanations of CSRF and IIUC the core thing that enables the attack is cookie based identification of server sessions.
So in other words if the browser (And note I'm specifically narrowing the scope to web browsers here) does not use a cookie based session key to identify the session on the server, then a CSRF attack cannot happen. Did I understand this correctly?
So for example suppose someone creates a link like:
href="http://notsosecurebank.com/transfer.do?acct=AttackerA&amount;=$100">Read more!
You are tricked into clicking on this link while logged into http://notsosecurebank.com, however http://notsosecurebank.com does not use cookies to track your login session, and therefore the link does not do any harm since the request cannot be authenticated and just gets thrown in the garbage?
Assumptions
The OpenID Connect Server / OAuth Authorization server has been implemented correctly and will not send authentication redirects to any URL that you ask it to.
The attacker does not know the client id and client secret
Footnotes
The scenario I'm targeting in this question is the CSRF scenario most commonly talked about. There are other scenarios that fit the CSRF tag. These scenarios are highly unlikely, yet good to be aware of, and prepared for. One of them has the following components:
1) The attacker is able to direct you to a bad client
2) The attacker owns that client
3) The attacker has the secret for that client registered with the OAuth Authorization Server
4) The attacker is able to tell the Authorization Server that authenticates you to redirect back to the bad client after you have been authenticated with the proper server.
So setting this up is a little bit like breaking into Fort Knox, but certainly good to be aware of. For example OpenID Connect or OAuth Authorization Providers should most likely flag clients that register redirect URLs pointing to redirect URLs that other clients have also registered.

The most common / usually discussed CSRF Cross Site Request Forgery scenario can only happen when the browser stores credentials (as a cookie or as basic authentication credentials).
OAuth2 implementations (client and authorization server) must be careful about CSRF attacks. CSRF attacks can happens on the client's redirection URI and on the authorization server. According to the specification (RFC 6749):
A CSRF attack against the client's redirection URI allows an attacker
to inject its own authorization code or access token, which can
result in the client using an access token associated with the
attacker's protected resources rather than the victim's (e.g., save
the victim's bank account information to a protected resource
controlled by the attacker).
The client MUST implement CSRF protection for its redirection URI.
This is typically accomplished by requiring any request sent to the
redirection URI endpoint to include a value that binds the request to
the user-agent's authenticated state (e.g., a hash of the session
cookie used to authenticate the user-agent). The client SHOULD
utilize the "state" request parameter to deliver this value to the
authorization server when making an authorization request.
[...]
A CSRF attack against the authorization server's authorization
endpoint can result in an attacker obtaining end-user authorization
for a malicious client without involving or alerting the end-user.
The authorization server MUST implement CSRF protection for its
authorization endpoint and ensure that a malicious client cannot
obtain authorization without the awareness and explicit consent of
the resource owner

Theory is, CSRF is not related to the authentication method. If an adversary can have a victim user perform actions in another application that the victim didn't want, then that application is vulnerable to CSRF.
This can manifest in several ways, the most common being that a victim user visits a malicious website which in turn makes requests from the victim's browser to another application, thus performing actions the user didn't want. This way it is possible if credentials are sent by the victim browser automatically. By far the most common scenario is a session cookie, but there can be others as well, for example HTTP Basic auth (the browser remembers that as well), or Windows authentication in a domain (Kerberos/SPNEGO), or client certificates, or even some kind of an SSO under certain circumstances.
Also sometimes application authentication is cookie-based, and all non-GET (POST, PUT, etc.) requests are protected against CSRF, but GETs are not for obvious reasons. In languages like PHP, it is easy to make calls intended to be POST requests also work as GETs (think of using $_REQUEST in PHP). In that case, any other website can include something like <img src='http://victim.com/performstuff&param=123> to have actions performed silently.
There are also less obvious CSRF attacks in complex systems or flows, like for example the CSRF attacks against oauth.
So if a web application uses say tokens (sent as request headers, instead of session cookies) for authentication, meaning a client will have to add the token to each request, that is probably not vulnerable to CSRF, but as always, the devil is in the details.

Related

Does public contact form require a CSRF token?

Let's say we have a simple contact form publicly available in our website. The FE application makes a request that goes to an BE service and is being processed somehow there. It doesn't require any authentication, so everybody can just submit a request and that's it.
When I look at OWASP doc here it looks like the above example doesn't fall into that.
There is no authenticated user context in the contact request, so I don't see any scenario of an attack that CSRF token would prevent.
Could anybody either confirm this approach or present a scenario of such attack where CSRF would make sense.
Maybe worth adding that we don't keep any user session. We have a SPA (in Angular) that is served by Nginx and we use only stateless bearer token for authentication (based on SSO) with BE services.
So above seems to be another impediment of using CSRF token, because we don't have any session object stored anywhere to verify the CSRF token in the BE.
Using cookie to transport the token to the browser also seems not be be valid here, as Nginx is serving the app, so we can't do any token validation that comes with the cookie.
you are right CSRF Deals only when a user is Authenticated and sending a Resource changing request.
Since There is No Authentication Involved, The Attacker Couldn't abuse a user Authority to do something .
As every one can send The Form
The Only Scenario i can think of you might need a CSRF Protection for the Public Form is When you add some semi-authentication like for detecting DDOS. for example:
you using a mechanism to validate each ip address can send only one request a day, without asking them for captcha.
since you are semi-authenticating them (one user is not equal to others) .
Attacker might using CSRF Attack for Passing Your DDos Protection
he/she may send a malware to a network which each node can sends a Form and take down the Application Level DDOS prevention based on IP (semi-auth)

What kind of CSRF attack does state parameter prevent in OAuth2-based authentication?

I'm working on authentication part with Google OAuth2 API.
I'm using "server" flow, not "implicit".
When implementing step 1 for obtaining code guidelines recommend using the state parameter to ensure that in the end, the service provider will receive the response that correlates to the auth request he initiated.
See https://developers.google.com/identity/protocols/OpenIDConnect#createxsrftoken
I understand that there is a possibility that code can be stolen, and redirect_uri guessed.
But I don't understand why this is called anti-CSRF protection?
According to wiki CSRF attack "exploits the trust that a site has in a user's browser".
As I understand something sensitive should be kept in the browser to make CSRF attack possible. The most classic example - an authentication cookie.
But what is kept in the browser in relation to OpenID-connect code flow?
It is just two consequent redirects from service provider to identity provider and back. The code itself is passed on callback as a URL param.Browser's role is passive - to be redirected two times. Nothing is stored here.
So my question is what exactly kind of CSRF attack does state prevent? Can anyone give a detailed example? Or is it just misusing of term "CSRF" in google guidelines?
When using the authorization code flow in OAuth2, the user browses to the client application, which then redirects the browser to the authorization server to be logged in and get an access token.
302 https://auth.server/authorize?response_type=code&client_id=....
After you've signed in on the authorization server, it will redirect you back to the registered redirection URI with the issued code. The client application will then exchange the code for an access token and optionally go to a URL encoded in the state parameter.
Now, an attacker could trick you into clicking a link (from an email or something) like:
<a href="https://auth.server/authorize?response_type=code&client_id=...."
This would execute the same request to the authorization server. Once you logged in and the authorization server redirects you back to the client application, the client application has no way of knowing whether the incoming GET request with the authorization code was caused by a 302 redirect it initiated or by you clicking that hyperlink in the malicious email.
The client application can prevent this by sticking some entropy in the state parameter of the authorization request. Since the state parameter will be included as a query parameter on the final redirect back to the client application, the client application can check if the entropy matches what it kept locally (or in a secure HTTP only cookie) and know for sure that it initiated the authorization request, since there's no way an attacker can craft a URL with entropy in the state parameter that will match something the client application keeps.
The objective of CSRF is to dupe the user into performing an action (usually a destructive write action that the user wouldn't do under normal circumstances) in a website by clicking on a link sent by the attacker. An example of such an activity could be deletion of user's own account in the website. Assuming that the user is logged into the website, the requests originating from the user's browser are trusted by the website server which has no way to find out (without the CSRF token) that the user is actually duped into making that request.
In case of Google OAuth2 (Authorization code grant type), note that the initial request to the Google auth server contains the url that the user actually wants to visit after succesful authentication. An attacker can carefully contruct that url with some malicious intent and make the user use it.
The state token check enables the server ensure that the request is indeed originated from its own website and not from any other place. If the attacker creates the url with some random state token, the server wouldn't recognise that and reject the request.
If you have such doubts, best resource you must refer is the specification. For OAuth 2.0, this is RFC6749 . There is a dedicated section in the specification which discuss about Cross-Site Request Forgery
Cross-site request forgery (CSRF) is an exploit in which an attacker
causes the user-agent of a victim end-user to follow a malicious URI
(e.g., provided to the user-agent as a misleading link, image, or
redirection) to a trusting server (usually established via the
presence of a valid session cookie).
From the specification perspective, you must implement state handling mechanism into your application
The client MUST implement CSRF protection for its redirection URI.
This is typically accomplished by requiring any request sent to the
redirection URI endpoint to include a value that binds the request to
the user-agent's authenticated state (e.g., a hash of the session
cookie used to authenticate the user-agent). The client SHOULD
utilize the "state" request parameter to deliver this value to the
authorization server when making an authorization request.
And about a detailed explanation, directly from specifaciton
A CSRF attack against the client's redirection URI allows an attacker
to inject its own authorization code or access token, which can
result in the client using an access token associated with the
attacker's protected resources rather than the victim's
Injecting an authorisation code from attacker, then manipulating your application to behave in a manner attacker wants.

How to prevent the following CSRF attack on Oauth2?

The victim authenticates via system browser at the Authorization Server in a Oauth2 authorization code flow and is issued a session cookie by the Authorization Server
The victim is tricked into clicking at a link on attackers web site which launches an Oauth2 authorization request via victims browser towards the Oauth2 Authorization Server with client ID and redirect URI for the attackers Oauth2 client
The Authorization Server will not need to authenticate victim since a session cookie is already issued by the Authorization Server but just ask victim to grant the attackers client access – which in this case the victim is assumed to do
The Authorization Server will redirect victims browser to the attackers redirect URI (which is assumed to point to a web application) with authorization response with Authorization Code for victim
The attacker is now in possession of Authorization Code for the victim, that he or she can exchange for refresh & access token
What are the best possible precautions against this except for the victim not to accept to grant the attackers client access?
I mean the average internet user will typically click accept to a lot of stuff on a normal day without thinking much about it.
For this to work, the attacker would have to register his client with the authentication provider, which in an enterprise setting should not be possible. Also as the redirect URI is not registered, the AP should never redirect the user back to the attacker.
In case of public APs where anyone can register a client, this is indeed a problem, but this is also the point in a sense. If the user authorizes the attacker's app, then the attacker's app will have access. As it is not different from normal apps in this regard, users will have to take care (while you are right, the majority of users will just click OK to anything).
The AP could still maintain a blacklist based on user reports for example, but that is a weak control. The best an AP can probably do is provide adequate information and warnings for the user, delaying the OK button for a few seconds to try to get them to read, etc.

SPA best practices for authentication and session management

When building SPA style applications using frameworks like Angular, Ember, React, etc. what do people believe to be some best practices for authentication and session management? I can think of a couple of ways of considering approaching the problem.
Treat it no differently than authentication with a regular web application assuming the API and and UI have the same origin domain.
This would likely involve having a session cookie, server side session storage and probably some session API endpoint that the authenticated web UI can hit to get current user information to help with personalization or possibly even determining roles/abilities on the client side. The server would still enforce rules protecting access to data of course, the UI would just use this information to customize the experience.
Treat it like any third-party client using a public API and authenticate with some sort of token system similar to OAuth. This token mechanism would used by the client UI to authenticate each and every request made to the server API.
I'm not really much of an expert here but #1 seems to be completely sufficient for the vast majority of cases, but I'd really like to hear some more experienced opinions.
This question has been addressed, in a slightly different form, at length, here:
RESTful Authentication
But this addresses it from the server-side. Let's look at this from the client-side. Before we do that, though, there's an important prelude:
Javascript Crypto is Hopeless
Matasano's article on this is famous, but the lessons contained therein are pretty important:
https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/
To summarize:
A man-in-the-middle attack can trivially replace your crypto code with <script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script>
A man-in-the-middle attack is trivial against a page that serves any resource over a non-SSL connection.
Once you have SSL, you're using real crypto anyways.
And to add a corollary of my own:
A successful XSS attack can result in an attacker executing code on your client's browser, even if you're using SSL - so even if you've got every hatch battened down, your browser crypto can still fail if your attacker finds a way to execute any javascript code on someone else's browser.
This renders a lot of RESTful authentication schemes impossible or silly if you're intending to use a JavaScript client. Let's look!
HTTP Basic Auth
First and foremost, HTTP Basic Auth. The simplest of schemes: simply pass a name and password with every request.
This, of course, absolutely requires SSL, because you're passing a Base64 (reversibly) encoded name and password with every request. Anybody listening on the line could extract username and password trivially. Most of the "Basic Auth is insecure" arguments come from a place of "Basic Auth over HTTP" which is an awful idea.
The browser provides baked-in HTTP Basic Auth support, but it is ugly as sin and you probably shouldn't use it for your app. The alternative, though, is to stash username and password in JavaScript.
This is the most RESTful solution. The server requires no knowledge of state whatsoever and authenticates every individual interaction with the user. Some REST enthusiasts (mostly strawmen) insist that maintaining any sort of state is heresy and will froth at the mouth if you think of any other authentication method. There are theoretical benefits to this sort of standards-compliance - it's supported by Apache out of the box - you could store your objects as files in folders protected by .htaccess files if your heart desired!
The problem? You are caching on the client-side a username and password. This gives evil.ru a better crack at it - even the most basic of XSS vulnerabilities could result in the client beaming his username and password to an evil server. You could try to alleviate this risk by hashing and salting the password, but remember: JavaScript Crypto is Hopeless. You could alleviate this risk by leaving it up to the Browser's Basic Auth support, but.. ugly as sin, as mentioned earlier.
HTTP Digest Auth
Is Digest authentication possible with jQuery?
A more "secure" auth, this is a request/response hash challenge. Except JavaScript Crypto is Hopeless, so it only works over SSL and you still have to cache the username and password on the client side, making it more complicated than HTTP Basic Auth but no more secure.
Query Authentication with Additional Signature Parameters.
Another more "secure" auth, where you encrypt your parameters with nonce and timing data (to protect against repeat and timing attacks) and send the. One of the best examples of this is the OAuth 1.0 protocol, which is, as far as I know, a pretty stonking way to implement authentication on a REST server.
https://www.rfc-editor.org/rfc/rfc5849
Oh, but there aren't any OAuth 1.0 clients for JavaScript. Why?
JavaScript Crypto is Hopeless, remember. JavaScript can't participate in OAuth 1.0 without SSL, and you still have to store the client's username and password locally - which puts this in the same category as Digest Auth - it's more complicated than HTTP Basic Auth but it's no more secure.
Token
The user sends a username and password, and in exchange gets a token that can be used to authenticate requests.
This is marginally more secure than HTTP Basic Auth, because as soon as the username/password transaction is complete you can discard the sensitive data. It's also less RESTful, as tokens constitute "state" and make the server implementation more complicated.
SSL Still
The rub though, is that you still have to send that initial username and password to get a token. Sensitive information still touches your compromisable JavaScript.
To protect your user's credentials, you still need to keep attackers out of your JavaScript, and you still need to send a username and password over the wire. SSL Required.
Token Expiry
It's common to enforce token policies like "hey, when this token has been around too long, discard it and make the user authenticate again." or "I'm pretty sure that the only IP address allowed to use this token is XXX.XXX.XXX.XXX". Many of these policies are pretty good ideas.
Firesheeping
However, using a token Without SSL is still vulnerable to an attack called 'sidejacking': http://codebutler.github.io/firesheep/
The attacker doesn't get your user's credentials, but they can still pretend to be your user, which can be pretty bad.
tl;dr: Sending unencrypted tokens over the wire means that attackers can easily nab those tokens and pretend to be your user. FireSheep is a program that makes this very easy.
A Separate, More Secure Zone
The larger the application that you're running, the harder it is to absolutely ensure that they won't be able to inject some code that changes how you process sensitive data. Do you absolutely trust your CDN? Your advertisers? Your own code base?
Common for credit card details and less common for username and password - some implementers keep 'sensitive data entry' on a separate page from the rest of their application, a page that can be tightly controlled and locked down as best as possible, preferably one that is difficult to phish users with.
Cookie (just means Token)
It is possible (and common) to put the authentication token in a cookie. This doesn't change any of the properties of auth with the token, it's more of a convenience thing. All of the previous arguments still apply.
Session (still just means Token)
Session Auth is just Token authentication, but with a few differences that make it seem like a slightly different thing:
Users start with an unauthenticated token.
The backend maintains a 'state' object that is tied to a user's token.
The token is provided in a cookie.
The application environment abstracts the details away from you.
Aside from that, though, it's no different from Token Auth, really.
This wanders even further from a RESTful implementation - with state objects you're going further and further down the path of plain ol' RPC on a stateful server.
OAuth 2.0
OAuth 2.0 looks at the problem of "How does Software A give Software B access to User X's data without Software B having access to User X's login credentials."
The implementation is very much just a standard way for a user to get a token, and then for a third party service to go "yep, this user and this token match, and you can get some of their data from us now."
Fundamentally, though, OAuth 2.0 is just a token protocol. It exhibits the same properties as other token protocols - you still need SSL to protect those tokens - it just changes up how those tokens are generated.
There are two ways that OAuth 2.0 can help you:
Providing Authentication/Information to Others
Getting Authentication/Information from Others
But when it comes down to it, you're just... using tokens.
Back to your question
So, the question that you're asking is "should I store my token in a cookie and have my environment's automatic session management take care of the details, or should I store my token in Javascript and handle those details myself?"
And the answer is: do whatever makes you happy.
The thing about automatic session management, though, is that there's a lot of magic happening behind the scenes for you. Often it's nicer to be in control of those details yourself.
I am 21 so SSL is yes
The other answer is: Use https for everything or brigands will steal your users' passwords and tokens.
You can increase security in authentication process by using JWT (JSON Web Tokens) and SSL/HTTPS.
The Basic Auth / Session ID can be stolen via:
MITM attack (Man-In-The-Middle) - without SSL/HTTPS
An intruder gaining access to a user's computer
XSS
By using JWT you're encrypting the user's authentication details and storing in the client, and sending it along with every request to the API, where the server/API validates the token. It can't be decrypted/read without the private key (which the server/API stores secretly) Read update.
The new (more secure) flow would be:
Login
User logs in and sends login credentials to API (over SSL/HTTPS)
API receives login credentials
If valid:
Register a new session in the database Read update
Encrypt User ID, Session ID, IP address, timestamp, etc. in a JWT with a private key.
API sends the JWT token back to the client (over SSL/HTTPS)
Client receives the JWT token and stores in localStorage/cookie
Every request to API
User sends a HTTP request to API (over SSL/HTTPS) with the stored JWT token in the HTTP header
API reads HTTP header and decrypts JWT token with its private key
API validates the JWT token, matches the IP address from the HTTP request with the one in the JWT token and checks if session has expired
If valid:
Return response with requested content
If invalid:
Throw exception (403 / 401)
Flag intrusion in the system
Send a warning email to the user.
Updated 30.07.15:
JWT payload/claims can actually be read without the private key (secret) and it's not secure to store it in localStorage. I'm sorry about these false statements. However they seem to be working on a JWE standard (JSON Web Encryption).
I implemented this by storing claims (userID, exp) in a JWT, signed it with a private key (secret) the API/backend only knows about and stored it as a secure HttpOnly cookie on the client. That way it cannot be read via XSS and cannot be manipulated, otherwise the JWT fails signature verification. Also by using a secure HttpOnly cookie, you're making sure that the cookie is sent only via HTTP requests (not accessible to script) and only sent via secure connection (HTTPS).
Updated 17.07.16:
JWTs are by nature stateless. That means they invalidate/expire themselves. By adding the SessionID in the token's claims you're making it stateful, because its validity doesn't now only depend on signature verification and expiry date, it also depends on the session state on the server. However the upside is you can invalidate tokens/sessions easily, which you couldn't before with stateless JWTs.
I would go for the second, the token system.
Did you know about ember-auth or ember-simple-auth? They both use the token based system, like ember-simple-auth states:
A lightweight and unobtrusive library for implementing token based
authentication in Ember.js applications.
http://ember-simple-auth.simplabs.com
They have session management, and are easy to plug into existing projects too.
There is also an Ember App Kit example version of ember-simple-auth: Working example of ember-app-kit using ember-simple-auth for OAuth2 authentication.

How secure is Oauth 2.0 Implicit Grant?

In Implicit Grant, the access token is sent back in the callback URL. Is this not a security risk because, if this callback URL is cached in the hop. In general it is advised, not to send sensitive data in URL params, and this access token will be a token to access all secured user resources. So why is it getting passed as fragment in URL
Hmmm, I am afraid there are some misunderstandings in the answers above. While URL query strings are secured when using TLS, and thus the access token is protected in flight, it is exposed in the users browser (part of their history) and also in the destination web browser logs. Most web browsers will log the entire URL of the incoming request. Their is an additional issue known as the "referer" leak problem wherein the query string will be passed to third-party sites. A good overview may be found at:
http://blog.httpwatch.com/2009/02/20/how-secure-are-query-strings-over-https/
Elaborating on #vlatko's response...
To mitigate the risk of sending the token in the fragment (or via any other OAuth2 grant):
ensure that the OAuth endpoint and the callback endpoint are TLS (https) (See countermeasures)
send a state parameter to prevent cross-site forgery (Also see: https://www.rfc-editor.org/rfc/rfc6749#section-4.2.1)
Issuing short-lived access token (as #vlatko said) will reduce the impact of a leaked token, but is not a preventative measure.
Like you pointed out, the token is passed the URI fragment. Since browsers don't send fragments of URLs to HTTP servers, the chances that someone will eavesdrop and pick up the access token are drastically reduced.
There are also additional security measures, like only issuing short lived access tokens in the implicit grant flow.
More info in the OAuth2 threat models document.

Resources