There are quite a lot written about preventing CSRF.
But I just don't get it: why I can't just parse the csrf token in the target page form and submit it with my forge request?
If you are able to inject script code into the target page (XSS) then yes, you can do that thus rendering the CSRF prevention useless.
The CSRF token has to be stored in the page the end-user receives (or he won't know it either).
In fact, in security assessments, XSS usually evaluated not for its own damage potential but for its use in just such attacks.
CSRF attacks are blind. They do session riding and the attacker has no direct control unless he can extract the token via an XSS vulnerability. Normally a session wide token can be used. Rotating tokens per request might be an overkill and could lead to false alarms. I prefer to use tokens per resource with a master session token.
The CSRF token should be everytime for every user and for every request a totally different token, so it can never be guessed from an attacker.
For php, .net and javascript have a look in the OWASP CSRFGuard Project - if you are working with java and jsf 2.x its already save against CSRF (as long as you use POST and not GET - for this you will have to wait for JSF 2.2) else if you work without JSF the HTTPUtillities Interface from the OWASP ESAPI could be also very helpful!
Because the value of the CSRF token isn't known in advance.
Related
I'm making a Django Rest Framework application with a JWT authentication with tokens stored in HttpOnly cookies. Authentication is performed via reading the access cookie. I'm using a dj-rest-auth library for this purpose, but I'm a little confused of the security aspect of such method. Knowing that having authentication data stored in cookies can be used to perform CSRF attack, how can one protect their web against such attacks for a specific case I've described above? All cookies are set to be SameSite=Lex.
Do I need to also send X-CSRFTOKEN header obtained from the backend? That would mean that every request to the api will need to have that header. What should be the optimal setup having all those libraries?
The OWASP foundation has created a detailed cheat-sheet on how to prevent from CSRF attacks: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html
Two things worth remembering:
CSRF is a concern only for data-changing requests, so POST/PUT/PATCH/DELETE methods. An attacker performing a CSRF attack can't read the response from the server, so GET requests are not your concern.
The most common way of preventing CSRF is with a csrf token. The server should create the token for the user's session and the token is saved in frontend, but not in a cookie. Then you send that token either in a header or as part of the request body. The server then validates that the token is the same as the one it has for that user session.
If you don't want to persist the token in your server, you can additionally save it in a cookie. So the frontend will keep the token in two places - one in memory/in a hidden form field/etc. and another one in the cookie. Then the server can check if the value from the cookie matches the value from header/body.
All cookies are set to be SameSite=Lex.
Do I need to also send X-CSRFTOKEN header obtained from the backend?
SameSite is not supported by older browsers. As per caniuse, it is supported by 90% browsers in use globally.
Arguments AGAINST implementing CSRF tokens:
I think it's a low risk. If you think your users will be among those 90%, then don't bother with CSRF tokens.
Since you're using JWTs, I assume the frontend is going to be a modern SPA app. If you don't expect it to run on older browsers, then, again, don't bother with CSRF tokens.
Arguments FOR implementing CSRF tokens:
Lax offers no protection on GET requests. You'll have to make sure, today and in future as well, that you never modify server state in GET requests. If you implement CSRF tokens, you'll have one less thing to worry about. Or you can also use SameSite=Strict value.
My opinion:
Personally, I'd just implement CSRF tokens. It's a one time setup and most frameworks already take care of this. So, why not?
P.S.: I'm not sure if you've a typo there, but it is Lax, not Lex.
In Django world, CSRF token is generated in a way that doesn't involve any information known only to the server. It's perfectly possible to generate a valid CSRF token in javascript - Django will happily accept it.
In particular, one could have a piece of javascript that generates valid CSRF token and sets it as a cookie (and it will work fine because of the same origin).
Are there any security related drawbacks of doing that? The only thing I can think of is that such cookie cannot have the http-only flag set (for obvious reasons).
The short answer is No
CSRF is a solution to restrict CSRF attacks. So in the server, a code is generated (and signed) to check is user using built-in js codes or not. for example, a user can call a function without CSRF protection in the browser console or with a browser extension or with curl without any browser, in this condition, you cannot understand is user knows this function call or not!
On the other side, you want to make a new CSRFTOKEN and send it to the server with ajax and this service cannot protect with CSRF. So the hackers can use this ajax call for CSRF forgery! And the hacker can find your CSRF maker code in your js libraries.
For your Idea, you can use some user info and save it in session info such as use-agent, client-IP, and ...
I just read an article from this
https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/
In summary, they recommend to store JWT Access Token in memory (as a variable in JavaScript for example) and Refresh Token in HTTP-Only Cookie.
They said:
But by persisting our session indirectly via a refresh token, we
prevent a direct CSRF vulnerability we would have had with a JWT
token.
But is it store Refresh Token in a HTTP-Only cookie still vulnerable to CSRF Attack? For example, evilsite.com can make request to /refreshtoken endpoint to get new JWT access token. What I understand about HTTP-Only cookie is the cookie can't be read from JavaScript but it will automatically be sent whenever make a HTTP request like how the evilsite.com does. (Correct me if i'm wrong).
Refresh token in a cookie and access token in memory can be a good model if used with care. Hopefully some better guidance will be made available in standards such as BFF-TMI.
The cookie should have these properties and the SameSite property will mean evilsite cannot send it, so that it is good from a CSRF viewpoint.
HTTP Only
Secure
AES256 Encrypted
SameSite=strict
OWASP's CSRF Guidance seems to recommend using both SameSite and CSRF tokens together as the preferred option.
Out of interest here is how I'm implementing things in an SPA Code Sample at the moment - in case it is useful to borrow ideas from:
SPA OAuth Code
Back End API OAuth Code
I may change my mind a little as guidance in this area evolves.
HIGH SECURITY OPTION?
The current concensus is that the following option is preferred in terms of security, though I am hoping risks and mitigations become better documented over the coming year:
Keep access tokens out of the browser completely
Proxy all API calls via the 'back end for front end'
See this insightful 2021 video
This option may add complexity in some areas though, and could also limit capabilities in some scenarios.
As is often the case with security, there are trade-offs with other factors, and the solution chosen may depend on data sensitivity and what stakeholders care about.
Although there are many posts about this topic (or closely related) on SO, I did not find what I am looking for.
As the title suggests I am using Django Rest Framework as a backend, and React as a frontend.
Now I implemented token authentication, and it works perfeclty. The only problem is that the token is stored in React's state, and if the user refreshes the page, he is no longer logged in (the token is lost).
So, now I want to switch to session authentication, since the problem is solved then. But that will require me to do some research, and before I go there I'd like to know if that is the best choice.
My question:
Do I need to use session authentication to have users stay logged in, even when the React's state changes. Or can I also achieve the same thing with token authentication (in a safe and responsible way?)
I figure I can save the token in a cookie, but that doesn't seem safe to me.
EDIT:
Later I realized, why not just store the token in a session?
SessionAuthentication would be the most straightforward way to achieve what you want. The configuration is described at http://www.django-rest-framework.org/api-guide/authentication/#setting-the-authentication-scheme This will set a session id in a cookie that is handled by the browser.
Alternatively you can store a token in the browser's cookie but that is vulnerable to XSS attacks and other javascript attacks. For more security you can store the token in an HttpOnly cookie. The cookie would be persisted across tab/window closes by the browser.
Also to clarify cookie handling is built into most browsers. Your react state is in userland and lives in a different memoryspace than cookie storage.
More info:
Ask HN: Cookies vs. JWT vs. OAuth
https://developer.okta.com/blog/2017/08/17/why-jwts-suck-as-session-tokens
http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/
I have a Django Site that uses Django's csrf-token for protection against csrf attacks. One of the forms can be accessed by public, including people who have not logged in.
Csrf Token is supposed to give protection against cross domain requests.
Edit: (quote from my comment)
"But, in case of post requests that are allowed without requiring authorization, csrf is no better than a trival spam filter(captcha would do better here). In fact, it should be a security risk to include CSRF token(that expire after say, 30 mins) in pages that require no authentication what so ever.(but my site is doing it, which is why I made this post in the first place)"
Also, in this case, one could just fetch that page in browser js console, get the csrf token through some specific xpath and then post some arbitrary data with that csrf. Also, steps being easily reproducible, one could design a specific attack for the site, or any Django site for that matter cause you'll find csrf token besides 'csrfmiddlewaretoken' every time (and that includes sites like reddit, pinterest etc.).
As far as I can see, apart from making it a little difficult, csrf token didn't help much.
Is there an aspect to it I am missing? Is my implementation wrong? and If I'am correct is it dumb to have your csrf token flying around in your html source(esp. those not requiring any authentication)?
This question has a really good couple of answers about the same thing. Also, the last answer on there addresses the fact that it technically would be possible to scrape the form for the token (via javascript), and then submit a post request with it (via javascript). But that the victim would have to be logged in.
The point of the CSRF protection is to specifically prevent tricking a random user. It has nothing to do with client-side exploits. You also have to consider that part of the protection includes denying cross-site origin requests. The request would have to come from the same origin as the target site.
Bottom line, CSRF has value. Its a region of protection, but its not the end all be all. And you can't defend against everything.
Quote from a blog post about CSRF:
Secret hidden form value. Send down a unique server form value with
each form -- typically tied to the user session -- and validate that
you get the same value back in the form post. The attacker can't
simply scrape your remote form as the target user through JavaScript,
thanks to same-domain request limits in the XmlHttpRequest function.
... And comments of interest:
I'm not a javascript wizard, but is it possible to load a remote page
in a hidden iframe on the malicious page, parse it with javascript to
find the hidden token and then populate the form the user is
(presumably) about to submit with the right values?
David Goodwin on September 24, 2008 2:35 AM
#David Goodwin: No, the same-origin policy would prevent the malicious
page from reading the contents of the iframe.
Rico on September 24, 2008 3:03 AM
If your form is public and doesn't require authentication, then there is nothing stopping anyone (including malicious sites/plugins/people) from posting to it. That problem is called Spam, not CSRF.
Read this: http://en.wikipedia.org/wiki/Cross-site_request_forgery
CSRF involves a malicious site posting to your forms by pretending to be an authenticated user.