I want to bring a doubt about JWT tokens and CSRF from the Stormpath post that explain the advantages and disadvantages of storing the JWT either in localStorage or cookies.
[...] if you are reading values out of a cookie using JS, that means you
can't set the Httponly flag on the cookie, so now any JS on your site
can read it, thus making it the exact same security-level as storing
something in localStorage.
I'm trying to understand why they recommend adding the xsrfToken to
the JWT. Doesn't storing your JWT in the cookie and then extracting it
out and placing the JWT in the HTTP header and authenticating the
request based on the HTTP header accomplish the same thing as
Angular's X-XSRF-TOKEN? No other domain could make requests on a
user's behalf if you authenticate based on the JWT in the header,
since other domains cannot extract the JWT from the cookie. I don't
understand the purpose of the xsrfToken in the JWT - perhaps its just
an additional layer of defense - meaning that attackers would have to
have a compromised script on your site and CSRF a user at the time. So
they'd have to hit you in both ways to be able to pull of an attack.
The post is linked in this answer where says:
The last thing is to ensure that you have CSRF protection on every
HTTP request to ensure that external domains initiating requests to
your site cannot function.
[...] Then, on every request into your server, ensure that your own
JavaScript code reads the cookie value and sets this in a custom
header, e.g. X-CSRF-Token and verify that value on every request in
the server. External domain clients cannot set custom headers for
requests to your domain unless the external client gets authorization
via an HTTP Options request, so any attempt at a CSRF attack (e.g. in
an IFrame, whatever) will fail for them.
Even if they could set custom headers, they couldn't access the cookie where the JWT token is stored because only JavaScript that runs on the same domain can read the cookie.
The only way they could is via XSS, but having an xsrfToken in the JWT is compromised too if exists XSS vulnerabilities because a malicious script running in the trusted client domain could access the JWT in the cookie and include a header in the request with the xsrfToken.
So the equation should be:
TLS + JWT stored in secure cookie + JWT in request header + No XSS vulnerabilities.
If the client and server are running in different domains, the server should send the JWT and the client should create the cookie with the JWT.
I think that the equation is still valid for this situation.
UPDATE: MvdD agree with me:
As the browser does not automatically add the header to your request,
it is not vulnerable to a CSRF attack
I am the author of the Stormpath Blog Post. Storing XSRF token in the JWT isn't about that it is in the JWT, it is about that it is in a cookie. The cookie should be httpOnly, so you can not read it from Javascript.
Now, I think the point that caused a little confusion is where I talk about angular. Angular sets it's only XSRF cookie as well (which is not httpOnly) to put it into the header at request time (which can only be done by javascript on same domain). These are not the same cookie.
If you think about implementing XSRF support in your application, this has been done with storing server side state and the point of storing the XSRF. Storing it in the httpOnly cookie is about being stateless with XSRF. Here, you would validate the JWT signature, get the XSRF out of the claims, and compare it to the header.
The answer to your question is so that you do not need to store state on your server.
My understanding was this:
Store JWT is an HTTPonly cookie.
In that JWT, store a hashed version of an XSRF token.
Send the client the XSRF token when they sign in so they can store it in local storage
Later when the client sends requests, the JWT is automatically sent with each request via cookies and then you also send the XSRF token via a header or query variable and on the server side, re-hash to compare to what's in the JWT on the server
Your JWT is protected from being stolen in a XSS and you're protected from XSRF. XSS could still execute on your browser but could only do damage for that session in the browser. Ultimately, You couldn't stop someone from writing a really detailed script that just ran on your browser, so conventional safeties to protect from XSS are still needed by the web developer.
Related
i can't easily decide how to receive the refresh token and access token from the back-end and where to store it.
the authentication process I understand is as follows.
XSS can be defended with cookies.
using cookies is vulnerable to CSRF.
however, in the case of cookie, it can be stolen as 'document.cookie'. So, use the 'httponly' option to prevent access from javascript.
cookie is always included in header when making http request, so it is vulnerable to CSRF. So, when logging in, 'refresh token' and 'access token' are created in the back-end, stored in the DB, and returned to the client.
request an api using an access token, and if it expires, update it using a refresh token.
as I refer to many articles, it is said that XSS is to be blocked with cookies and CSRF is to be protected with refresh tokens and access tokens.
and in the case of refresh token, it is stored in webStorage.
however, in order to prevent XSS, it seems that in the case of access tokens, cookies should be used to protect them (+ httponly applied), and in the case of refresh tokens, it seems that they should be stored in the client.
if the refresh token is sent in a cookie with the httponly option, isn't it accessible from the client?
in conclusion...
in the back-end server, should the access token be sent as a cookie and the refresh token included in the body?
Any ideas would be appreciated.
The tokens are usually sent back in the body of the response. This way your frontend app can easily read them and store wherever needed. Usually storing them in memory should be enough (in a variable or state of your app, etc.). When the user refreshes the page they will have to log in again, but that should not be a problem if the Authorization Server supports things like "remember me". If you're using an OpenID Connect-compliant Authorization Server, then you can perform a silent login - so obtain tokens without the need of redirecting the user anywhere.
If you store your tokens in a http-only cookie then your app will not have access to them, so you won't be able to call any APIs from your app. I think this is not what you're trying to achieve.
Keeping the tokens in memory could help you be a bit more safe from XSS attacks, but you will never be 100% secure. Have a look at this talk: https://pragmaticwebsecurity.com/talks/xssoauth.html where it is explained. In fact the only way to be sure that an XSS attack can't steal your tokens is to keep the tokens in a backend app, not in the browser.
I'm using session based CSRF on a site using Angular. Is it safe to make an HTTP call to ask for the CSRF token?
For example, if I sent a request with valid user session to a page called /csrf/get and it prints a raw token, is this secure enough for CSRF functionality? If not, is there anything I can do to make it more secure while keeping the JSON retrieval functionality?
It will be the first api call before everything else and I will keep it on localstorage to use it on every http call
In short, no. The way that you are trying to do CSRF protection exposes you to CSRF since your csrf/get endpoint is not protected from CSRF.
Essentially, you need to protect yourself from two main attack vectors: XSS, and CSRF.
CSRF
CSRF involves your site and a malicious site that will attempt to make authenticated requests to your site. If there is a way to request a CSRF token from the malicious site, you are not protected.
Usual methods for protecting from CSRF are by returning a token from your authentication API call, and storing that token in the browser session. The problem with this method is that it opens you up to XSS.
XSS
Cross-Site scripting, or XSS vulnerabilities are related to external scripts running on your page. This includes potentially malicious scripts inserted by an attacker.
Local storage and session storage are not safe, so you shouldn't store a token in regular cookies, for example.
To be safe from XSS attacks Your authentication response can store cookies that javascript can't read by using HttpOnly cookies.
So, using a token that you store with javascript protects you from CSRF, but opens you up to XSS, where using a session cookie protects you from XSS, but opens you up to CSRF.
Protect your API from XSS and CSRF
The solution is to use both approaches: your authentication API should set an HttpOnly cookie to protect from XSS, and should return a token to protect from CSRF.
Note that there's no need for a csrf/get api since the token should be returned by the authentication method: you want to only send that token in exchange of valid credentials. Remember to also send and validate that same token on all authenticated API calls.
Here is a great article explaining API security, why and how to do it in much more detail:
http://www.redotheweb.com/2015/11/09/api-security.html
Note on login CSRF:
Logic forms should also be protected from CSRF by creating pre-sessions with CSRF tokens.
(from https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#login-csrf)
Most developers tend to ignore CSRF vulnerability on login forms as they assume that CSRF would not be applicable on login forms because user is not authenticated at that stage, however this assumption is not always true. CSRF vulnerabilities can still occur on login forms where the user is not authenticated, but the impact and risk is different.
For example, if an attacker uses CSRF to assume an authenticated identity of a target victim on a shopping website using the attacker's account, and the victim then enters their credit card information, an attacker may be able to purchase items using the victim's stored card details. For more information about login CSRF and other risks, see section 3 of this paper.
Login CSRF can be mitigated by creating pre-sessions (sessions before a user is authenticated) and including tokens in login form. You can use any of the techniques mentioned above to generate tokens. Remember that pre-sessions cannot be transitioned to real sessions once the user is authenticated - the session should be destroyed and a new one should be made to avoid session fixation attacks. This technique is described in Robust Defenses for Cross-Site Request Forgery section 4.1.
First of all, use https, http is unsafe.
Then, better not to use GET.
Safe way is to send token in successfull auth request's (POST) response.
For more info, check:
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
I am developing a web app and I am on a process of handling the Authentication of user. I am able to get the access token by initially making HTTP POST call to the API.
The idea know is where to store it so that it is not vulnerable to XSS.
Have heard of HttpOnly Cookie which makes it possible that the cookie is readable by the client (javascript), but the thing is why would I need something to store on my end when I cannot access it. How do I sent back to the backend (API) access token stored into coockie with http only since I cant get it so I am unable to attach it into headers of my http request.
Also, can I add a coockie with flag HttpOnly using javascript?
HttpOnly means you cannot read it from Javascript on the client but the browser is still aware of that cookie and it is being added to any subsequent request you are making to the server.
It can be useful for an auth session cookie for example.
Session cookies are usually opaque tokens that are meaningless to the user and are meaningful only to the server. Thus there's no real reason why the client code would need to read them
Also, can I add a cookie with flag HttpOnly using javascript?
No
My Application structure as follows
1)API server running in api.mydomain.com
2)Frontend VUejs application running in www.mydomain.com
So i implemented authentication via httponly cookie.
But little confused with CSRF token implementation
Mysolution
1).CSRF token from the url like /getCSRF.
2) Store it in localstorage.
3) Send with every request.
But i don't think its the good way does anyone have suggestion?
First things first: Feel free to use session-based authentication in combination with the httpOnly (prevents your session cookie to be hijacked via XSS attack) cookie. Nothing wrong with that.
After a certain action (e.g. login), generate a CSRF token and store it in a cookie (make it accessible to JavaScript). You can HMAC the token with server secret so that attacker cannot recreate a CSRF.
Sure that CSRF will be sent as a cookie in each request, but the trick is to send it and expect it in a custom header (e.g. X-CSRF-HEADER). The final step is to check its validity.
The key idea is that attacker cannot attach custom headers while performing a CSRF attack.
I am still not clear in regards to the JWT and CSRF working together. I understand the fundamentals for the JWT (what it is and how it works). And I also understand the CSRF when used with sessions. Similarly I understand that there are risks involved with storing the JWT in localStorage and that's why you need the csrf token. So my question is, how do I use them both. For simplicity say that I have a login page.
1) I have the user signing in and once the email and password are consumed if the user is authenticated the server will send a CSRF and will store a httpOnly cookie with the JWT (how do I set the cookie using PHP). What I understood is that you can use header('Set-Cookie: X-Auth-Token=token_value; Secure; HttpOnly;');please confirm if thats the way to do it.
2) Once I have set the cookie with the JWT. How I am sending the CSRF token with subsequent requests> From what I understood, you set them in the headers. So if I am making an Ajax request I will put them in the headers.
3) Once the request is made and the CSRF token is sent along with the request. How is the validation made. What am I comparing?
Last, is this safe to implement!
I would highly appreciate if you could include as much details as possible.
One approach that I've seen and used myself is to include the CSRF token inside the JWT as a claim. So when the user sends username and password, you can do the following:
If username and password are correct, proceed with the following listing.
Create a new JWT and include a generated CSRF token in the payload as a claim, then sign the JWT.
Respond to client's authentication request by setting an HTTPOnly cookie which contains the JWT. This ensures that only the browser (not the client side app and possibly malicious scripts) has access to the JWT. It's also a good idea to set the cookie to secure. This prevents the browser from sending the cookie if an unsecured communication channel is used (i.e. not https).
When setting the JWT cookie, you should also set an HTTP header which will also contain your generated CSRF token. Note that now you will have the CSRF token in two places—inside the JWT cookie and in an HTTP header.
In your client app, store the CSRF token from the header into localstorage.
For each request, take the CSRF token from localstorage and include it as a request header (the cookie containing the JWT is passed along automatically by the browser).
The server should read the JWT from the cookie, validate its signature and read the CSRF token from the JWT's payload. Then it should compare it against the CSRF token that's in the request header. If they match, the server can continue processing the request.
I suggest you to watch this talk about JWTs. It goes into more details about the same approach (also with nice diagrams). Feel free to watch the entire talk or if you're interested specifically in CSRF, start from 36:29.
The following is a slide (from the presentation linked above) that demonstrates how JWT and CSRF tokens could be used together. I annotated it with red numbers which correspond to the listing above.
The common paradigm to defend against CSRF it to generate a token for each "form", and validate that the token that was set for the specific form is correct.
That way, attacker can't guess the token therefore can't make an external form that sends to your server.
Usually, the method to set that token is via Cookie and the client app will attach it to some custom header, that will give you an additional protection, then, the server should compare between the cookie value and the header value.
It is important that the token will be valid only for one session, otherwise, an attacker can reuse the same token that he got in the attack vector.
JWT, is a method to authenticate the user to the system not to validate that the request was valid.
I will try to explain by example, assume you are didn't implemented any protection against CSRF, but you do have a mechanism to authenticate your users (with usage of JWT), so the user logged in with the correct user & pass, your server will send a JWT, the client will save it to localStorage / memory.
Now, the attacker can craft a form on his site that will point to your server, assume that he knows the users JWT token (he got it with other methods like MITM), all he needs to do is to trick the user into going his page with the form, and the form will be sent to you with any problem, your server will accept the request and the attack will succeed.
If you implement any CSRF mechanism, the attacker at the example will not be able to guess the current token, therefore your server will ignore his request.