Why doesn't pre-flight CORS block CSRF attacks? - web-services

Everyone says CORS doesn't do anything to defend against CSRF attacks. This is because CORS blocks outside domains from accessing (reading) resources on your domain -- but doesn't prevent the request from being processed. So evil sites can send state-changing DELETE requests, without caring that they can't read back the result.
That's all well and good.
Except for pre-flight CORS.
In this case, CORS looks at the request BEFORE it is sent, and checks whether it's legitimate. If it's not, the request is rejected.
So the DELETE request that the CSRF attacker tries to send fails the pre-flight check, and thus is rejected. The CSRF attack fails.
What am I missing here?

Pre-flight requests don't prevent CSRF in general. For example not all cross-domain ajax calls generate a pre-flight request, plain POSTs don't. There may be specific cases when pre-flight requests do indeed help to reduce the risk though.
Another problem is the same as with checking the referer/origin. While it is not possible for an attacker to override referer or origin in plain Javascript on a malicious website, it may be possibble to do so using a suitable browser plugin, like an old version of Flash for instance. If a browser plugin allows to do that, the attacker might be able to send cross-origin requests without a pre-flight. So you don't want to rely on pre-flight requests only.

Related

Dj rest auth using JWT Token stored in HttpOnly cookies

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.

Using JWT stored in HTTPonly & secure cookie: Vulnerable to CSRF. but not to XSS?

I understood webstorage is vulnerable to xss
And Cookie to CSRF also makes sense
What makes me puzzled is that it seems like implicitly said that cookie is not vulnerable to xss, but isn't it also vulnerable to xss?
If I can run a script on other's browser, I think I might be able to just send request to server & get important data cause browser automatically attach cookies & I dont' need to do anything to get authenticated.
If a cookie is set with the httpOnly flag, it cannot be accessed from Javascript (injected js cannot read or write such cookies), so it is not possible to steal the cookie value if it's httpOnly. This is very relevant for a session cookie. In this case, this cookie is not affected by XSS. Note that this is solely because of the httpOnly flag - cookies without httpOnly are affected by XSS, because they are accessible to Javascript.
Any cookie (regardless of flags*) will still be sent with any request to the server it was received from, but that is the realm of csrf, actually, it is the fundamental problem in csrf. If anybody (from any website) makes a request to a server, any cookie for that server will be sent, and the attacker can exploit csrf if there is no protection. That's why you need protection against csrf if you have cookie-based authentication.
Also note that if the page is vulnerable to XSS, than any csrf protection is useless, because xss can be used to read the token, wherever it is stored.
*Sidenote: the new SameSite cookie flag changes this, but that is only supported by Chrome.

What Response Should Be Sent Back a When Cross-Site Request Forgery (CSRF) is Detected

What response should I send back when a Cross-Site Request Forgery (CSRF) is detected?
There is a scanning tool which I cannot get a hold of that is saying one of my pages is not protected against CSRF. But it is. The response I send back is a normal 202 with the sentence "REQUEST CANNOT BE PROCESSED". That's it, nothing informative is sent back to the attacker, and I log the attempt. But this software says it is still susceptible to CSRF. I could easily run tests myself and figure it out but it's a long time in between scans and tests and I can't get the same software, that's why I'm asking stackoverflow, so I can hopefully knock it out on the next scheduled scan. I'm thinking of sending back a statusCode of 404 or 410 instead of a 202. http://www.cfgears.com/index.cfm/2009/8/11/cfheader-404-status-codes-and-why-you-shouldnt-use-them
What do you recommend sending back when a CSRF is detected?
403 Forbidden as the user is technically authorized to access the site, it is just the specific action that is forbidden (HTTP POST without correct CSRF token).
A web server may return a 403 Forbidden HTTP status code in response to a request from a client for a web page or resource to indicate that the server can be reached and understood the request, but refuses to take any further action. Status code 403 responses are the result of the web server being configured to deny access, for some reason, to the requested resource by the client.
Bear in mind that the attacker will not be able to read this response, and for the most part the user will not see the message or HTTP response because a CSRF attack is not designed to be obvious to the victim that it is happening. If you have an effective CSRF mechanism, your site is not likely to be attacked in this manner anyway - the defense is also the deterrent.
How about:
401 Unauthorized
or
403 Forbidden

How does CORS provide at least some security to users?

First apologies: This feels to me like a "dumb" question, and I expect I'll soon regret even asking it ...but I can't figure it out at the moment as my mind seems to be stuck in the wrong rut. So please bear with me and help me out:
My understanding is that "Same Origin" is a pain in the butt for web services, and in response CORS loosens the restrictions just enough to make web services work reasonably, yet still provides decent security to the user. My question is exactly how does CORS do this?
Suppose the user visits website A, which provides code that makes web service requests to website Z. But I've broken into and subverted website Z, and made it into an attack site. I quickly made it respond positively to all CORS requests (header add Access-Control-Allow-Origin: "*"). Soon the user's computer is subverted by my attack from Z.
It seems to me the user never visited Z directly, knows nothing about Z's existence, and never "approved" Z. And it seems to me -even after the breakin becomes known- there's nothing website A can do to stop it (short of going offline itself:-). Wouldn't security concerns mandate A certifying Z, rather than Z certifying A? What am I missing?
I was investigating this as well, as my thought process was akin to yours. Per my new understanding: CORS doesn't provide security, it circumvents it to provide functionality. Browsers in general don't allow cross-origin requests; if you go to shady.com, and there is a script there that tries to access bank.com using a cookie on your machine, shady.com's script would then be able to perform actions on bank.com using that cookie to impersonate you. To prevent this, bank.com would not mark it's APIs as CORS enabled, so that when shady.com's script begins the HTTP request, the browser itself prevents the request.
So same-origin protects users from themselves because they don't know what auth cookies are laying around; CORS allows a server that owns resources on behalf of the user to mark APIs as accessible from other sites' scripts, which will cause the browser to then ignore its own cross-origin protection policy.
(anyone that understands this better, please add or correct as needed!)
CORS does nothing for security. It does allow someone selling web fonts to decide which websites get easy access to their fonts though. That's pretty much the only use case.
The user is just as unaware as they were before the introduction of CORS. And please remember that cross origin requests used to work before CORS (people often complain that you have to shim jQuery to get CORS support in IE... But in IE you could just make the request and get the response without any extra effort..it just worked).
Generally speaking the trust model is backwards. As others said you have implied trust by referencing some other site...so give me the freaking data!
CORS protects the website that receives the request (Z in your example) against the one that makes the request (A in your example) by telling the user's browser who is or is not allowed to see the response of the request.
When a JavaScript application asks the browser to make a HTTP request to an origin that's different than its own, the browser does not know if there is mutual agreement between the two origins to make such calls. For sure, if the request come from origin A then A agrees (and A is responsible to its users if Z is malicious), but does Z, the recipient, agrees ? The only way for the browser to know is to ask Z, and it does that by actually doing the request. Unless Z explicitly allows A to receive the response, the browser will not let A's application read it.
You are right that the only effect of CORS is to relax the same-origin policy. Before that, cross-origin requests were permitted, and the browser would automatically include the cookies it has for the destination, that is, it would send an authenticated request to Z. This means that, without same-origin policy, A could browse Z just as if it was the user, see it's data, etc. Same-origin fixes this very severe security vulnerability, but because some services still need to use cross-origin requests sometimes, CORS was created.
Note that CORS does not prevent the request from being sent, so if A's JS app sends a request to Z ordering it to send all the user's money to some account, Z will receive this request with all the cookies in it. This is called a Cross-Site Request Forgery (CSRF). Interestingly, the main defence against this type of attack is based on CORS. It consists in requiring some secret value in the request (a “CSRF token”) that can only be obtained through a cross-origin request, which A cannot obtain if it's not on the authorized list of Z. Nowadays, same-site cookies can be used as well, they are easier to manage but don't work cross-origin.

Are JAXRS restful services prone to CSRF attack when content type negotiation is enabled?

I have a RESTful API which has annotations like #Consumes(MediaType.JSON) - in that case, would the CSRF attack still be possible on such a service? I've been tinkering with securing my services with CSRFGuard on server side or having a double submit from client side. However when I tried to POST requests using FORM with enctype="text/plain", it didn't work. The technique is explained here This works if I have MediaType.APPLICATION_FORM_URLENCODED in my consumes annotation. The content negotiation is useful when I'm using POST/PUT/DELETE verbs but GET is still accessible which might need looking into.
Any suggestions or inputs would be great, also please let me know if you need more info.
Cheers
JAX-RS is designed to create REST API which is supposed to be stateless.
The Cross Site Request Forgery is NOT a problem with stateless applications.
The way Cross Site Request Forgery works is someone may trick you to click on a link or open a link in your browser which will direct you to a site in which you are logged in, for example some online forum. Since you are already logged in on that forum the attacker can construct a url, say something like this: someforum.com/deletethread?id=23454
That forum program, being badly designed will recognize you based on the session cookie and will confirm that you have the capability to delete the thread and will in fact delete that thread.
All because the program authenticated you based on the session cookie (on even based on "remember me" cookie)
With RESTful API there is no cookie, no state is maintaned between requests, so there is no need to protect against session hijacking.
The way you usually authenticate with RESTFul api is be sending some additional headers. If someone tricks you into clicking on a url that points to restful API the browser is not going to send that extra headers, so there is no risk.
In short - if REST API is designed the way it supposed to be - stateless, then there is no risk of cross site forgery and no need to CSRF protection.
Adding another answer as Dmitri’s answer mixes serverside state and cookies.
An application is not stateless if your server stores user information in the memory over multiple requests. This decreases horizontal scalability as you need to find the "correct" server for every request.
Cookies are just a special kind of HTTP header. They are often used to identify a users session but not every cookie means server side state. The server could also use the information from the cookie without starting a session. On the other hand using other HTTP headers does not necessarily mean that your application is automatically stateless. If you store user data in your server’s memory it’s not.
The difference between cookies and other headers is the way they are handled by the browser. Most important for us is that the browser will resend them on every subsequent request. This is problematic if someone tricks a user to make a request he doesn’t want to make.
Is this a problem for an API which consumes JSON? Yes, in two cases:
The attacker makes the user submit a form with enctype=text/plain: Url encoded content is not a problem because the result can’t be valid JSON. text/plain is a problem if your server interprets the content not as plain text but as JSON. If your resource is annotated with #Consumes(MediaType.JSON) you should not have a problem because it won’t accept text/plain and should return a status 415. (Note that JSON may become a valid enctype one day and this won’t be valid any more).
The attacker makes the user submit an AJAX request: The Same Origin Policy prevents AJAX requests to other domains so you are safe as long as you don’t disable this protection by using CORS-headers like e.g. Access-Control-Allow-Origin: *.