The x-requested-with header is kind of confusing to me. I know it can be used to defend against CSRF attacks, and that it is used to identify Ajax calls...but what is it really?
It just tells you what the request was...requested with?
Could there ever be a reasonable situation in which the header is present but set to some value other than "XMLHttpRequest"? I would imagine so, but I've never seen it set to anything else.
Just like the User-Agent header, it is provided by the client and can contain literally anything.
It is not at all reliable for any server-side security check.
Android sets X-Requested-With to the package ID of the app, for third-party apps that use the WebView component to embed a browser into their UI.
Presumably this could be used for debugging and/or statistics, but the values cannot be trusted because it would be possible for an attacker to write a custom client that sets it to anything just to try to break your server.
Related
Some time ago I came across the option in one of the software I use at work, to turn off XSRF server-side protection by including a special HTTP header value on the client side. Therefore, I wonder:
How is this not a security vulnerability?
Why would you implement a security feature and allow clients to turn it off? Is there a use-case I am missing?
I am doubting my knowledge of XSRF protection at the moment and since we could not reach a consensus at work I decided to post my concerns here.
The product is Bamboo and they publicly report the option in https://confluence.atlassian.com/bamkb/rest-api-calls-fail-due-to-missing-xsrf-token-899447048.html#RESTAPIcallsfailduetoMissingXSRFToken-Workaround. I first mentioned this in an old answer here: https://stackoverflow.com/a/45090321/410939.
I can understand allowing the server to turn it off on a per API basis. However allowing the client to turn it off is a very bad idea... It's as good as not being there. The only reason I can think this is OK is for backwards compatibility. Maybe there is an older version of the client that relies on this way to mitigate CSRF, while newer clients use the new version, and switch off the older version (but one of them must be used).
I would turn the question around: Why would you implement security features and then ask users to turn them on? This is the opt-in model to security you will find everywhere, e.g. literally no one are forcing 2FA even though it is a huge security improvement.
If XSRF is session based and you run multiple tabs with the same application and you are forced to reauthenticate in one of them you will typically get a new XSRF token. Other tabs might then no longer pass the XSRF check with the risk of losing unsaved work. There could possibly be other similar scenarios.
There are sometimes trade offs between security and usability, in this case they make security default and let people who run into problems take an informed risk.
There are other ways to mitigate XSRF. So, if cookie is not an option (maybe the client doesn't support cookie), you might want to disable this cookie solution.
Some other ways to mitigate XSRF:
State Variable (Auth0 uses it) - The client will generate and pass with every request a cryptographically strong random nonce which the server will echo back along with its response allowing the client to validate the nonce. It's explained in Auth0 doc
Always check the referer header and accept requests only when referer is a trusted domain. If referer header is absent or a non-whitelisted domain, simply reject the request. When using SSL/TLS referrer is usually present. Landing pages (that is mostly informational and not containing login form or any secured content may be little relaxed and allow requests with missing referer header
Is CSRF possible with PUT or DELETE methods? Or does the use of PUT or DELETE prevent CSRF?
Great question!
In a perfect world, I can't think of a way to perform a CSRF attack.
You cannot make PUT or DELETE requests using HTML forms.
Images, Script tags, CSS Links etc all send GET requests to the server.
XmlHttpRequest and browser plugins such as Flash/Silverlight/Applets will block cross-domain requests.
So, in general, it shouldn't be possible to make a CSRF attack to a resource that supports PUT/DELETE verbs.
That said, the world isn't perfect. There may be several ways in which such an attack can be made possible :
Web Frameworks such as Rails have support for "pseudo method". If you put a hidden field called _method, set its value to PUT or DELETE, and then submit a GET or POST request, it will override the HTTP Verb. This is a way to support PUT or DELETE from browser forms. If you are using such a framework, you will have to protect yourself from CSRF using standard techniques
You may accidentally setup a lax response headers for CORS on your server. This would allow arbitrary websites to make PUT and DELETE requests.
At some point, HTML5 had planned to include support for PUT and DELETE in HTML Forms. But later, they removed that support. There is no guarantee that it won't be added later. Some browsers may actually have support for these verbs, and that can work against you.
There may just be a bug in some browser plugin that could allow the attacker to make PUT/DELETE requests.
In short, I would recommend protecting your resources even if they only support PUT and DELETE methods.
Yes, CSRF is possible with the PUT and DELETE methods, but only with CORS enabled with an unrestrictive policy.
I disagree with Sripathi Krishnan's answer:
XmlHttpRequest and browser plugins such as Flash/Silverlight/Applets
will block cross-domain requests
Nothing stops the browser from making a cross-domain request. The Same Origin Policy does not prevent a request from being made - all it does is prevent the request from being read by the browser.
If the server is not opting into CORS, this will cause a preflight request to be made. This is the mechanism that will prevent a PUT or DELETE from being used, because it is not a simple request (the method needs to be HEAD, GET or POST). Assuming a properly locked down CORS policy of course (or none at all which is secure by default).
No. Relying on an HTTP verb is not a way to prevent a CSRF attack. It's all in how your site is created. You can use PUTs as POSTs and DELETEs as GETs - it doesn't really matter.
To prevent CSRF, take some of the steps outlined here:
Web sites have various CSRF countermeasures available:
Requiring a secret, user-specific token in all form submissions and side-effect URLs prevents CSRF; the attacker's site cannot put the
right token in its submissions1
Requiring the client to provide authentication data in the same HTTP Request used to perform any operation with security
implications (money transfer, etc.)
Limiting the lifetime of session cookies Checking the HTTP Referer header or(and)
Checking the HTTP Origin header[16]
Ensuring that there is no clientaccesspolicy.xml file granting unintended access to Silverlight controls[17]
Ensuring that there is no crossdomain.xml file granting unintended access to Flash movies[18]
Verifying that the request's header contains a X-Requested-With. Used by Ruby on Rails (before v2.0) and Django (before v1.2.5).
This protection has been proven unsecure[19] under a combination of
browser plugins and redirects which can allow an attacker to
provide custom HTTP headers on a request to any website, hence
allow a forged request.
In theory it should not be possible as there is no way to initiate a cross-domain PUT or DELETE request (except for CORS, but that needs a preflight request and thus the target site's cooperation). In practice I would not rely on that - many systems have been bitten by e.g. assuming that a CSRF file upload attack was not possible (it should not be, but certain browser bugs made it possible).
CSRF is indeed possible with PUT and DELETE depending on the configuration of your server.
The easiest way to think about CSRF is to think of having two tabs open in your browser, one open to your application with your user authenticated, and the other tab open to a malicious website.
If the malicious website makes a javascript request to your application, the browser will send the standard cookies with the request, thus allowing the malicious website to 'forge' the request using the already authenticated session. That website can do any type of request that it wants to, including GET, PUT, POST, DELETE, etc.
The standard way to defend against CSFR is to send something along with the request that the malicious website cannot know. This can be as simple as the contents of one of the cookies. While the request from the malicious site will have the cookies sent with it, it cannot actually access the cookies because it is being served by a different domain and browser security prevents it from accessing the cookies for another domain.
Call the cookie content a 'token'. You can send the token along with requests, and on the server, make sure the 'token' has been correctly provided before proceeding with the request.
The next question is how do you send that value with all the different requests, with DELETE specifically difficult since it is not designed to have any kind of payload. In my opinion, the cleanest way is to specify a request header with the token. Something like this x-security-token = token. That way, you can look at the headers of incoming requests, and reject any that are missing the token.
In the past, standard ajax security restricted what could be done via ajax on the malicious server, however, now-a-days, the vulnerability depends on how you have your server set up with regards to accees-control configurations. Some people open up their server to make it easier to make cross domain calls or for users to make their own RESTful clients or the like, but that also makes it easier for a malicious site to take advantage unless CSRF prevention methods like the ones above are put in place.
What changes to the HTTP protocol spec, and to browser behaviour, would be required to prevent dangerous cases of cross-site request forgery?
I am not looking for suggestions as to how to patch my own web app. There are millions of vulnerable web apps and forms. It would be easier to change HTTP and/or the browsers.
If you agree to my premise, please tell me what changes to the HTTP and/or browser behaviour are needed. This is not a competition to find the best single answer, I want to collect all the good answers.
Please also read and comment on the points in my 'answer' below.
Roy Fielding, author of the HTTP specification, disagrees with your opinion, that CSRF is a flaw in HTTP and would need to be fixed there. As he wrote in a reply in a thread named The HTTP Origin Header:
CSRF is not a security issue for the Web. A well-designed Web
service should be capable of receiving requests directed by any host,
by design, with appropriate authentication where needed. If browsers
create a security issue because they allow scripts to automatically
direct requests with stored security credentials onto third-party
sites, without any user intervention/configuration, then the obvious
fix is within the browser.
And in fact, CSRF attacks were possible right from the beginning using plain HTML. The introduction of nowadays technologies like JavaScript and CSS did only introduce further attack vectors and techniques that made request forging easier and more efficient.
But it didn’t change the fact that a legitimate and authentic request from a client is not necessarily based on the user’s intention. Because browsers do send requests automatically all the time (e. g. images, style sheets, etc.) and send any authentication credentials along.
Again, CSRF attacks happen inside the browser, so the only possible fix would need to be to fix it there, inside the browser.
But as that is not entirely possible (see above), it’s the application’s duty to implement a scheme that allows to distinguish between authentic and forged requests. The always propagated CSRF token is such a technique. And it works well when implemented properly and protected against other attacks (many of them, again, only possible due to the introduction of modern technologies).
I agree with the other two; this could be done on the browser-side, but would make impossible to perform authorized cross-site requests.
Anyways, a CSRF protection layer could be added quite easily on the application side (and, maybe, even on the webserver-side, in order to avoid making changes to pre-existing applications) using something like this:
A cookie is set to a random value, known only by server (and, of course, the client receiving it, but not a 3rd party server)
Each POST form must contain a hidden field whose value must be the same of the cookie. If not, form submission must be prevented and a 403 page returned to the user.
Enforce the Same Origin Policy for form submission locations. Only allow a form to be submitted back to the place it came from.
This, of course, would break all sorts of other things.
If you look at the CSRF prevention cheat sheet you can see that there are ways of preventing CSRF by relying upon the HTTP protocol. A good example is checking the HTTP referer which is commonly used on embedded devices because it doesn't require additional memory.
However, this is weak form of protection. A vulnerability like HTTP response splitting on the client side could be used to influence the referer value, and this has happened.
cookies should be declared 'local' (default) or 'remote'
the browser must not send 'local' cookies with a cross-site request
the browser must never send http-auth headers with a cross-site request
the browser must not send a cross-site POST or GET ?query without permission
the browser must not send LAN address requests from a remote page without permission
the browser must report and control attacks, where many cross-site requests are made
the browser should send 'Origin: (local|remote)', even if 'Referer' is disabled
other common web security issues such as XSHM should be addressed in the HTTP spec
a new HTTP protocol version 1.2 is needed, to show that a browser is conforming
browsers should update automatically to meet new security requirements, or warn the user
It can already be done:
Referer header
This is a weaker form of protection. Some users may disable referer for privacy purposes, meaning that they won't be able to submit such forms on your site. Also this can be tricky to implement in code. Some systems allow a URL such as http://example.com?q=example.org to pass the referrer check for example.org. Finally, any open redirect vulnerabilities on your site may allow an attacker to send their CSRF attack through the open redirect in order to get the correct referer header.
Origin header
This is a new header. Unfortunately you will get inconsistencies between browsers that support it and do not support it. See this answer.
Other headers
For AJAX requests only, adding a header that is not allowed cross domain such as X-Requested-With can be used as a CSRF prevention method. Old browsers will not send XHR cross domain and new browsers will send a CORS preflight instead and then refuse to make the main request if it is explicitly not allowed by the target domain. The server-side code will need to ensure that the header is still present when the request is received. As HTML forms cannot have custom headers added, this method is incompatible with them. However, this also means that it protects against attackers using an HTML form in their CSRF attack.
Browsers
Browsers such as Chrome allow third party cookies to be blocked. Although the explanation says that it'll stop cookies from being set by a third party domain, it also prevent any existing cookies from being sent for the request. This will block "background" CSRF attacks. However, those that open full page or in a popup will succeed, but will be more visible to the user.
I have 2 security concerns that my client has come up with and I am stuck.
In order to avoid browsers caching sensitive information, the client's security guidlines require that POST requests do not return 200 response. Initially I set up a phaseListener to deal with this but the only requests that came through were GETs. I discovered that the POST request the client's security team were complaining about were ajax calls to the BlockingServlet. How can I set up something similar for this? I don't really understand how icefaces deals with the information stored on a form and how I can ensure that this info is not stored by the browser. I have implemented the no-cache headers but that's not exactly solid security.
The phaseListener I used was basically http://balusc.blogspot.com/2007/03/post-redirect-get-pattern.html
The client is also concerned that input parameters are not properly validated providing a entry point for XSS. The example they gave was also going through the blockingServlet. I suspect that ICEFaces has something built in to deal with this but I can't find any information about it. Can anyone help?
XSS is an output problem, you can't cram all input data though some magic function and expect your application to be 100% safe from xss. This will never work for any application, because XSS just doesn't work that way. Make sure you test your application for vulnerability like XSS and SQL Injection, there are free solutions like Sitewatch and the open source skipfish.
To prevent caching make sure this http header element is set:
Cache-Control: no-store
No other method should be used.
UPDATE : GWT 2.3 introduces a better mechanism to fight XSRF attacks. See http://code.google.com/webtoolkit/doc/latest/DevGuideSecurityRpcXsrf.html
GWT's RPC mechanism does the following things on every HTTP Request -
Sets two custom request headers - X-GWT-Permutation and X-GWT-Module-Base
Sets the content-type as text/x-gwt-rpc; charset=utf-8
The HTTP request is always a POST, and on server side GET methods throw an exception (method not supported).
Also, if these headers are not set or have the wrong value, the server fails processing with an exception "possibly CSRF?" or something to that effect.
Question is : Is this sufficient to prevent CSRF? Is there a way to set custom headers and change content type in a pure cross-site request forgery method?
If this GWT RPC is being used by a browser then it is 100% vulnerable to CSRF. The content-type can be set in the html <form> element. X-GWT-Permutation and X-GWT-Module-Base are not on Flash's black list of banned headers. Thus it is possible to conduct a CSRF attack using flash. The only header element you can trust for CSRF protection is the "referer", but this isn't always the best approach. Use token based CSRF protection whenever possible.
Here are some exploits that i have written which should shed some light on the obscure attack i am describing. A flash exploit for this will look something like this and
here is a js/html exploit that changes the content-type.
My exploit was written for Flex 3.2 and the rules have changed in Flex 4 (Flash 10) Here are the latest rules, most headers can be manipulated for requests POST only.
Flash script that uses navigateTo() for CSRF:
https://github.com/TheRook/CSRF-Request-Builder
GWT 2.3 introduces a better mechanism to fight XSRF attacks. See GWT RPC XSRF protection
I know I asked this question, but after about a days research (thanks to pointers from Rook!), I think I have the answer.
What GWT provides out-of-the-box will not protect you from CSRF. You have to take steps documented in Security for GWT Applications to stay secured.
GWT RPC sets "content-type" header to "text/x-gwt-rpc; charset=utf-8". While I didn't find a way to set this using HTML forms, it is trivial to do so in flash.
The custom headers - X-GWT-Permutation and X-GWT-Module-Base, are a bit more tricky. They cannot be set using HTML. Also, they cannot be set using Flash unless your server specifically allows it in crossdomain.xml. See Flash Player 10 Security.
In addition, when a SWF file wishes to
send custom HTTP headers anywhere
other than its own host of origin,
there must be a policy file on the
HTTP server to which the request is
being sent. This policy file must
enumerate the SWF file's host of
origin (or a larger set of hosts) as
being allowed to send custom request
headers to that host.
Now GWT's RPC comes in two flavours. There is the old, custom-serialization format RPC, and the new, JSON based de-RPC. AFAICT, client code always sets these request headers. The old style RPC doesn't now enforce these headers on server side, and thus a CSRF attack is possible. The new style de-RPC enforces these headers, and thus it may or may not be possible to attack them.
Overall, I'd say if you care about security, make sure you send strong CSRF tokens in your request, and don't rely on GWT to prevent it for you.
I'm not sure, if there's an easy way (I'd be extremely interested in finding that out, too!), but at least there seem to be some advanced ways to achieve arbitrary cross site requests with arbitrary headers: http://www.springerlink.com/content/h65wj72526715701/ I haven't bought the paper, but the abstract and introduction do sound very interesting.
Maybe somebody here already read the full version of the paper, and can expand a little bit?