Lets say an attacker controlling site B is exploiting the session a user has with site A.
I know that the attacker is able to exploit the trust server A has for the user, but I don't understand how. Explanations of CSRF I have read make it seem like when the attacker makes a request to site A that the browser automatically includes the necessary authentication information because there is an active session and thus the attack is successful.
The 'browser automatically includes the authentication information' is what doesn't make sense to me. In applications I've worked on auth tokens or cookies are sent explicitly by the client code. So if the client code is specifying what header the token is being sent in for instance, how could the attacker know this?
Related
I understand that the client makes a request to the server, server sends back the token which is used by the clients to make requests. I do not understand how this is secure as the man in the middle can catch the response which comes from the server and use that token.
Maybe I do not understand this fully but I would like to.
Thanks
Your concern of a man in the middle somehow getting a copy of the JWT is a valid one, and, if that were to happen, then the MITM could potentially masquerade as a valid user, using his JWT as identification.
However, this problem only could easily happen if the data being passed between server and client were completely unencrypted. Most likely, your app would be using some form of SSL (e.g. HTTPS) for communication between the server and client. In this case, the most a MITM could obtain would be a bunch of gibberish, which might contain all/part of the JWT. But, he would not easily be able to back out the original JWT.
The main focus of JWT is that they are tamper proof by the client. This means that a user cannot go into his JWT and change his claims or metadata. Rather, the server locks away some claims into the JWT, and only the server can control this. Even a MITM would not be able to tamper with a valid JWT.
I am developing a REST application with its own authentication and authorization mechanism. I want to use JSON Web Tokens for authentication. Is the following a valid and safe implementation?
A REST API will be developed to accept username and password and do the authentication. The HTTP method to be used is POST so that there is no caching. Also, there will be SSL for security at the time of transit
At the time of authentication, two JWTs will be created - access token and refresh token. Refresh token will have longer validity. Both the tokens will be written in cookies, so that they are sent in every subsequent requests
On every REST API call, the tokens will be retrieved from the HTTP header. If the access token is not expired, check the privileges of the user and allow access accordingly. If the access token is expired but the refresh token is valid, recreate new access token and refresh token with new expiry dates (do all necessary checks to ensure that the user rights to authenticate are not revoked) and sent back through Cookies
Provide a logout REST API that will reset the cookie and hence subsequent API calls will be rejected until login is done.
My understanding of refresh token here is:
Due to the presence of refresh token, we can keep shorter validity period for access token and check frequently (at the expiry of access token) that the user is still authorized to login.
Please correct me if I am wrong.
A REST API will be developed to accept username and password and do
the authentication. The HTTP method to be used is POST so that there
is no caching. Also, there will be SSL for security at the time of
transit
This is the way most do it, so you're good here.
At the time of authentication, two JWTs will be created - access token
and refresh token. Refresh token will have longer validity. Both the
tokens will be written in cookies so that they are sent in every
subsequent requests
Storing the tokens in cookies I not dangerous in itself, but if you somehow get you JWT module on your server to read them from there you vulnerable to CSRF attacks where any webpage can trigger a users browser to send a form + you sites cookie to your server unless you use CSRF tokens. So generally they are stored in localStorage and "manually" added to request headers every time.
On every REST API call, the tokens will be retrieved from the HTTP
header. If the access token is not expired, check the privileges of
the user and allow access accordingly. If the access token is expired
but the refresh token is valid, recreate new access token and refresh
token with new expiry dates (do all necessary checks to ensure that
the user rights to authenticate are not revoked) and sent back through
Cookies
Apart from the cookie dangers, it seems safe.
Provide a logout REST API that will reset the cookie and hence
subsequent API calls will be rejected until login is done.
You don't even need to make an API call, you can simply just purge the cookies or the localStorage object and make sure your client doesn't break on missing tokens.
The standard for the express-jwt module expects the tokens to be in its own "Authorization: Bearer [Token]" header, which I would strongly recommend over cookies. The localStorage API is available all the way back to IE8 so you should be good.
Edit:
First, it's important to know the difference between XSS and CSRF attacks since they're often believed to be the same thing.
XSS is when users get unsafe JS running on your domain in other users browsers when that happens neither JWT in localStorage or sessions and JWT in cookies are safe. With httpOnly flag on cookies, you can't directly access them, but the browser will still send them with AJAX requests to your server. If this happens you generally out of luck. To prevent this, make sure to escape all user input if it's sent to the browser.
If you load 3rd party JS with script tags or iframes this might compromise localStorage unless you are careful, but I haven't worked enough with this to help you here.
CSRF is only when other domains are trying to send normal HTML forms to your server by getting the browser to send cookies automatically. Frameworks prevent this by inserting unique random strings as hidden fields and checking them again when it's submitted. JWT's in localStorage is safe from this since each domain gets its own separate localStorage area.
But ultimately all this depends on if your service will be using one single domain, in which case httpOnly cookies will be plenty secure and easier to set up, but if you wanna spread your service out on multiple domains like api.domain.com + app.domain.com or add a native app you're forced to store you're JWTs in localStorage or some other native storage area.
Hope this helps!
I asked this question two years back and also accepted the answer. However, based on my experience and study in the last two years, I'd like to answer this just in case someone stumbles on this thread with the same question.
The approach mentioned in the question is similar to the "Resource Owner Password Credentials" grant type of OAuth 2.0. However, I think it is better to use the "Authorization Code Grant" type instead and Cookie to store the tokens instead of browser localStorage or sessionStorage. I have detailed my reasons, implementation points, security considerations and references in this StackOverlow answer.
Like OP I been using resource owner password grant.
I learned so much from Saptarshi Basu's other answer in a different post I think anyone looking into OAuth Code Flow should take a look at it, it has outlined a very solid approach to auth SPA and resource servers. It primarily relies on your backend(resource server) to handle authentication with the auth provider as a private client.
However, I will just add that people looking at implementing authentication with SPA should also consider OAuth Code Flow with PKCE. The main goal of PKCE is to allow public client such as SPA to authenticate directly with auth provider. All PKCE adds, is that when a SPA app initiates authentication, a hashed value is sent to the auth provider when the user is authenticated. And after user authenticate with the authorization provider, it redirects the user back to SPA with that hashed value as well as authorization code. Now, for the next part where the SPA calls auth provider to exchange code for tokens, instead of providing client secret, it has to provide the key that was originally used to create the hashed value. This mechanism guarantees the code cannot be used by someone who intercepted the code, and the SPA doesnt need to store a client secret like a server-side app does.
Now the only thing I'm not certain at this point is which is technically more secure, server-side authentication using standard Code Flow without PKCE or SPA authenticating directly using PKCE? Most resources I could find online currently describes and recommends the latter . However I feel that letting a private server side client handle authentication (as Saptarshi Basu described) might still be more secure. I would love to hear his opinion on this as well.
My understanding of refresh token here is:
Due to the presence of refresh token, we can keep shorter validity period for access token and check frequently (at the expiry of access token) that the user is still authorized to login.
Please correct me if I am wrong.
Assuming you're talking about using JWT as Bearer-token in OAuth (and I would strongly advice to follow the OAuth 2.0 protocol), that's right.
With an additional auth-time (timestamp of authentication) claim in your JWT, you could even drop the second token and sent your access- as a refresh-token (the auth-server could then issue a new access-token if token is valid & auth-time within allowed range)... but sure, it's also good to follow the standard ;)
Anyway, there are certain additional aspects (that tend to get difficult or are even against the fundamental ideas of JWT) you should consider before using JWTs as refresh-token, as this basically means you introduce long-living JWT:
do you need to have something like forced user logout/ token revocation by subject (e.g. if user got identified as fraudulent)?
do you need to have something like revocation of a specific token (e.g. if a user looses a device)?
...
Dependent on your use-case you should consider all the possible implications, long-living tokens have as they usually require you to introduce some kind of state on your server-side (e.g. to allow revocation/ blacklisting). Keep in mind the beauty and security of the JWT concept lies within JWTs being short-lived.
I'm building SPA app with server side rendering, using JWT-based authentication.
Current implementation is:
JWT token is issued and transferred to client after successful username and password verification
token is then stored in cookie (not HttpOnly) - the purpose of that is to avoid the need to login again after full refresh or closing page
logging out deleted cookie with token
Authorization header is attached to every API request if token exists
full SSL traffic
I can't store token in LocalStorage because of server side rendering, also the there is no HttpOnly because I need to access cookie in order to construct Authorization header.
What are the possibilities of stealing the token in such architecture?
One major risk is that any single cross-site scripting vulnerability in your application could be used to steal the token from the cookie, because it's not httpOnly (while I understand why that is the case). XSS in a javascript-heavy application like an SPA is very common and hard to avoid.
Also you're saying the token is kept in the cookie so that after closing the browser, the user is still logged in. On the one hand, that's bad practice, a user closing the browser probably expects being logged out. On the other hand, this means the cookie is persisted to disk, so it is much easier for an attacker to steal it from the client.
Another thing that comes to mind is cross-site request forgery (CSRF), but if I understand correctly, authentication is actually based on the Authorize header, where the token is copied in each request. If that's the case, CSRF is not an issue for you (but it would be, if sending the token in the cookie was enough).
So at the very least, I think you should
not use a persisted cookie for the token
try to minimize the chance of XSS (eg. by automatically scanning your code, but that will never be 100%, also by carefully choosing secure by default technologies)
make sure auhentication is based on the Authorize header and not the cookie
Still mainly because of the XSS risk, I would probably not recommend doing it this way in a security-critical application.
I was wondering if there is any relation between login and cross site request foregry ?
My question is, are there sites that have no login required but still require to be protected from CSRF ? Can you give an example
For CSRF to be effective, your site just needs to be able to act on behalf of someone in a way that doesn't require explicit authentication or validation.
Signed in users via auto-login cookies are the most popular CSRF attacks, but e.g. newsletter subscription forms may be just as vulnerable and can cause people to receive unwanted emails from your system to confirm their subscription.
So to answer your question, although login and CSRF are related, they are not exclusive to each other.
CSRF attacks exploit the authenticity of a client’s requests as an attacking site is able to forge requests that are executed by the client in behalf of the client and thus enjoy the server’s trust in the client’s requests. So the server assumes that any request from a client is intended behavior of the user that controlling the client. CSRF exploits this implicit trust.
At this point it is not necessary that the client is authenticated. Although authenticated users generally have special privileges that attacking sites are aiming for, the main goal of CSRF attacks is sending arbitrary requests in behalf of the user without their knowledge. So target sites can also be any site where you need a different originator than the attacking site (e. g. polls, unique visitors, malicious activities, etc.).
I had one doubt about CSRF prevention. A lot of sites say that CSRF can be prevented by using 'tokens' which are randomly generated per session.
Now my doubt is,
suppose i have a function like :
$.post("abcd.php",{'fbuid':userid,'code':'<?php echo md5($_SESSION['randcode']); ?>'}
now this md5 hash would obviously be visible to any hacker through the source code.He could simply open this page, generate a token, and keep the page open, so that the session doesn't get destroyed, and useanother tab or anything else , to start hacking,
No ?
Or is my idea of tokens incorrect ?
Thanks for your help :D
I think you are misunderstanding what needs to be done. To protect against CSRF you need to create a token and save it for that session. Then you need to append all your submits and AJAX calls with that token.
For another person to send you to a page on your website they would need to have access to the request with in the same session. It is true that one could parse the HTML and look for the token. But when they try to request a http call on your website they will have a new session created. The new session will have a new token which will not match the token that was passed.
Next you will ask what if you can copy the cookies and the session id as a result. This is not something that is protected. I can simply sit anybody's computer and copy all their cookies and I will then be logged in as them.
As kapep points out, you are confusing the two seperate issues of input validation and cross-site form posting. You must validate your inputs anyway, so the case of your malicious attacker using his own session token is already handled if you have sound input validation. CSRF protection is not there to protect the data, it is simply to ensure that only forms from your own application can post data back to that application. the CSRF protection is simply stopping other people being able to post data directly into your app from forms they put up on their own site.
One specific point to be aware of is that the token is visible to any javascript running on your page, so as soon as you have a cross-site scripting (XSS) vulnerability, your CSRF protection is defeated.
See Cross-site scripting and the prevention cheat sheet
You should use a per request token.
Generate a token and store it in the session.
Pass the token to the client.
Execute actions.
Destroy the token.
The token is safer and cannot be used more than one time.
I would define a stolen token as a token that is used by someone else, and not the one you have send the token to. If you send someone a token he can't really steal it from himself.
If you are concerned that a user can run a malicious script with his own token, your design seems to be broken. You can't prevent a user from sending data that you didn't indented to receive. It's your job to validate any data, the session token is just there to identify multiple requests by the same client.
It could be a security issue if you send that token over unsecured http. Then it could easily be stolen by monitoring the clients network.