We're building an app with a Java Spring/Hibernate backend running in JBoss. The frontend is AngularJS.
We haven't yet done anything to setup XSRF tokens on the server end. We also don't (not yet anyway) have a requirement to allow other domains access to our web resources.
I figured I'd try to see if our site was vulnerable to an XSRF attack so I set up a malicious webapp to post to one of our real app's urls using Angular's $http.post(). I logged in to the real app, then I tried posting from the malicious app.
In the browser I got a 401 response and saw the error:
XMLHttpRequest cannot load http://localhost:8080/user/delete. No
'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:6543' is therefore not allowed access. The response
had HTTP status code 401.
The server side isn't setup to set Access-Control-Allow-Origin on the response thus the above error.
So my question is, is simply omitting Access-Control-Allow-Origin from the response header adequate to prevent XSRF attacks?
Is there a way I could still do an XSRF attack on my site even though Access-Control-Allow-Origin is not set? If so how? I'd like to demo this attack.
Thanks.
No, this is not sufficient. Even though the browser gives the 'Access-Control-Allow-Origin' error, the request has still been made by the browser. If withCredentials is specified by the attacking page:
$http.post(url, {withCredentials: true, ...})
then this request will be sent to your domain with the victim's authentication cookies, meaning that the request to http://www.example.com:8080/user/delete will succeed.
Also, this request could also be made without XHR using a standard HTML form:
<form method="post" action="http://www.example.com:8080/user/delete">
and JavaScript would just be used to submit the form rather than making the request itself.
An easy way to protect your system against CSRF is to check for a custom header such as X-Requested-With or the Origin header. X-Requested-With cannot be sent cross domain without enabling CORS server-side. However, the Synchronizer Token Pattern is still the strongest method of CSRF prevention as this is not subject to flaws in browser plug-ins such as a previous flaw in Flash that allowed headers to be sent that weren't normally possible from a browser.
Related
I'm a bit confused from the online information.
I'm using CSRF protection using Spring security on my back-end.
I wanted to ask is it safe to send CSRF token from my angular front-end, while I'm passing the token within HTTP header using Ajax GET method?
Because according to Spring docs I shouldn't use GET method, but on the other hand it doesn't say anything about if it's okay to use GET Ajax when I pass it in HTTP header.
Second,
If I shouldn't use GET, how do I use REST service & CSRF protection? should I give up GET method or CSRF protection?
Since GET requests should not modify any state on the server and should be "read-only" usually CSRF protection should not be needed for GET requests.
The problem about leakage is mostly related to browser usage because GET requests usually do not contain a body and thus the token is sent as request parameter. Thus the CSRF token could be visible through shoulder surfing, stored as a bookmark, appear in the browser history or logged on the server (altough logging also applies to AJAX requests).
Since you are talking about AJAX requests most of this leakage does not apply, although setting it in header may help in case of URLs appearing in the logs, but logs could also contain headers.
But actually using a custom header (with or without token) is often used to prevent CSRF attacks because AJAX requests cannot set custom headers cross-domain other than
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type
Thus using a custom header like X-Requested-With: XMLHttpRequest which is e.g. set by jQuery and verifying this header on the server can prevent CSRF attacks.
Last but not least there is one interesing article about having the same token for GET and POST requests and having same-origin access to the GET request via an XSS vulnerability of a separate web application in the same origin where the token can be leaked from the GET request and used for a POST. The solution there is to either not use CSRF tokens for GET or use different tokens for GET and POST.
Basically regarding your questions, if your GET does not have any side-effects, a CSRF token is not really needed but would not hurt. On the other hand, if your GET request changes something on the server, you should think about using another verb (e.g. POST) depending on what you want to do and then protect your POST requests with a CSRF token or a custom header.
I wrote this trivial method to handle CORS in a simple server proxy of mine.
private void handleCors(HttpServletRequest req, HttpServletResponse resp) {
final String origin = req.getHeader("Origin");
if (Strings.isNullOrEmpty(origin)) {
return;
}
if (!origin.startsWith("http://localhost:")) {
return;
}
resp.setHeader("Access-Control-Allow-Origin", origin);
resp.setHeader("Access-Control-Allow-Credentials", "true");
resp.setHeader("Access-Control-Expose-Headers", "Authorization");
resp.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
}
It's not needed for the real application, it's only used when testing manually (with ionic serve). I guess, it is safe because of doing nothing except when the origin is localhost, but better safe than sorry.
Moreover, findbugs complains about response splitting vulnerability. Should I simply use URLEncoder.html#encode or is there more to it?
Would in general removing spaces or adding no CORS headers in case of contained spaces do?
CORS is safer and more flexible than earlier techniques such as JSONP.
WebAPI works great straight out of the box for GET requests. However, once you start using it for POST, PUT or DELETE operations, then CORS kicks in and drops requests from hitting the server. CORS stops any cross domain requests so if your api is running at www.myapi.com and a request from www.mywebsite.com comes in, the request will be dropped. This is a security feature to ensure that requests from unknown domains cannot hit the server.
If you are using a web client to execute ajax calls, then there is one more thing you need to add to your ajax call to ensure that CORS words on all browsers.
$.support.cors = true
crossDomain: true
Resource Link:
How to Implement Cross Domain Requests (CORS) in WebAPI, old school?
But in a single line, if we want to say then CORS handler is not safe.
Already #zapl has given info about this.
Now I am trying to give you some attack type with some scenerios. Hope it will give you clear information.
CORS (In)security?
Several security issues arise from the improper implementation of
CORS, most commonly using a universal allow notation (*) in the
server headers.
Clients should not trust the received content completely and eval or
render content without sanitization which could result in misplaced
trust.
The application that allows CORS may become vulnerable to CSRF
attacks.
Prolonged caching of Preflight responses could lead to attacks
arising out of abuse of the Preflight Client Cache.
Access control decisions based on the Origin header could result in
vulnerabilities as this can be spoofed by an attacker.
CORS Security - Universal Allow
Setting the 'Access-Control-Allow-Origin' header to *
Effectively turns the content into a public resource, allowing
access from any domain.
Scenarios:
An attacker can steal data from an intranet site that has set this header to * by enticing a user to visit an attacker controlled site
on the Internet.
An attacker can perform attacks on other remote apps via a victim’s browser when the victim navigates to an attacker controlled site.
CORS Security – Misplaced Trust
Data exchange between two domains is based on trust
If one of the servers involved in the exchange of data is
compromised then the model of CORS is put at risk
Scenarios:
An attacker can compromise site A and host malicious content knowing site B trusts the data that site A sends to site B via CORS
request resulting in XSS and other attacks.
An attacker can compromise site B and use the exposed CORS functionality in site A to attack users in site A.
CSRF with CORS
Server may process client request to change server side data while
verifying that the Origin header was set
An attacker can use the .withCredentials = “true” property of XHR to
replay any cookies to the application on which the victim is logged
in
Scenarios:
An attacker sets the Origin header or uses a trusted site A to send a non idempotent request to site B.
The victim who is logged into site B when he is viewing the trusted site A causes site B to create a user account without his knowledge
via a CSRF attack.
CORS – Caching of Preflight responses
The Access-Control-Max-Age header is set to a high value, allowing
browsers to cache Preflight responses.
Caching the preflight response for longer duration can pose a
security risk.
If the COR access-control policy is changed on the server the
browser would still follow the old policy available in the Preflight
Result Cache.
CORS – Access Control based on Origin
The Origin header indicates that the request is from a particular
domain, but does not guarantee it.
Spoofing the Origin header allows access to the page if access is
based on this header
Scenarios:
An attacker sets the Origin header to view sensitive information that is restricted
Attacker uses cURL to set a custom origin header:
curl --header 'origin:http://someserver.com' http://myserver.com:90/demo/origin_spoof.php
Here is an example is given. You can go through this link :
https://www.owasp.org/index.php/Test_Cross_Origin_Resource_Sharing_(OTG-CLIENT-007)
Some Security Impacts of HTML5 CORS or How to use a Browser as a
Proxy
response.setHeader("Access-Control-Allow-Origin", "https://example.com");
I only wanted to allow 'https://example.com' to access my Java servlet with POST request. How do I can enable CORS in IBM WebSphere 7.0.0.27
Thanks
I cannot provide specific informations about Websphere 7, but it is not complicated to write a servlet filter, which handles the CORS preflight requests. Here are two resources that explain the protocol:
http://www.html5rocks.com/en/tutorials/cors/
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
The filter needs to do 2 tasks:
Recognize if the http request is a CORS preflight request.
If it is a CORS preflight request:
set Access-Control-Allow-Origin: https://example.com
set other Access-Control-* header
Hope it helps a bit.
Please have a look at https://www.owasp.org/index.php/CSRFProtector_Project or the CSRF information in General. There is a J2EE filter as well on their page.
You have to build a filter which checks the origin header (if you do it on your own) it is no rocket science, but some browsers do implement the spec differently. Chrome does always set the origin header.
Even with CORS you would still need to protect against the old CSRF attack like auto form submit as this would not set origin header as far as I know.
I have a GWT appilcation in which the client makes a request to another domain.
I wrote the request using RequestBuilder in GWT.
On executing the code, I get an error in my browser :
No 'Access-Control-Allow-Origin' header is present on the requested resource.
So I google and I found that the domain to which I am making the request should add this header in the response that it sends. Now I dont't have control over the other domain's server, so I can't do any modification there.
My question is, can I intercept the response and the Access-Control-Allow-Origin header to the response that is being sent by the other domain's server at my server, before I send it to my client?
I tried using Filters but the Filter doesn't get called for responses coming from another domain.
Is this possible to do, am I missing something or is it just not possible?
Vivek's answer that cross domain requests aren't allowed by the browser is true, except for the CORS mechanism, whereby newer browsers that support it can try in a cross origin way to servers that also support it.
However, unless that remote server support it itself, there is nothing you can do. If I server my app from A, and want to connect to B, only B can authorize that. If A were allowed to permit my app to connect to B via some filter or servlet, then I could write an app that makes calls to gmail or facebook or twitter and read/write your settings and personal data at those other urls.
So instead, it is the cross origin server that you are contacting that must approve the connection with the header you mentioned. In lieu of that, you can still use your own server as a proxy for the cross origin server.
Cross-domain requests are forbidden by web browsers as per the same origin security policy. These restrictions are limited to browser based applications and hence you can definitely use your own server application as a filter between the GWT based client side application and the external server.
I have small ajax problem related to cross domain as i see it.
On localmachine i created html example with some ajax:
in registration text field user types 'username',
on every keystroke ajax sends it to
local Tomcat, where servlet checks if that username is already used
and sends 'taken' reponse back.
No problem on localhost at all.
As soon as i type used 'username' servlet sends 'taken' response
and browser displays it.
But, when i put test html page with ajax
on remote machine (some free hosting on remote network)
that sends validation request on my localhost Tomcat,
connection is made,
in Tomcat console i see request comming,
and in firebug in Mozzila this is Console ouput:
GET http://89.216.182.25:8080/Dinamicki1/UsernameServlet?username=zik 200 OK
...but in response tab
there is not servlet response 'taken'
and message in firebug is in red color
So servers communicate well, no firewall problems, response is 200 OK
But response body is empty.
Any ideas what this red messages in firebugs are?
Thank you very much in advance.
And if anyone can recommend a some serious ajax tutorial for java
it will be highly appreciated :)
You need to use a domain-relative URL in your Ajax request:
/Dinamicki1/UsernameServlet?username=zik
Or a context-relative URL (assuming that the page is served from /Dinamicki1):
UsernameServlet?username=zik
With regard to "Ajax tutorial for Java", start here: How to use Servlets and Ajax?
You cannot use AJAX to read replies from other domains.
Your HTML must be on the same server (and same domain, port, and protocol) as the AJAX servlet.
The 200 status reported in Firebug does not indicate the validity of the cross-domain ajax call, be it successful or not.
You might want to try using a proxy method to perform the call.
E.g. JavaScript: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls
I figured out how to solve it from this site:
"To allow directory browsing via Apache Tomcat change the parameter "listings" in the file conf/web.xml from false to true."
Call your page not as C:/Documents and Settings/.../page.html but as localhost:8080/your_servlet_name (page is better named index.html).
This way, you will be able to make AJAX requests to localhost:8080/your_servlet_name/something_else.
A solution that worked for me was that I had to add "www" to the url! I was using URL Rewrite, so every URL that I had (image, js, get, load, post), I needed to use full url, but it was missing "www"!
For me, It was web api(c# .NET) request and cors was not enabled.
Added header for cors on controller and it solved the problem.
[EnableCors(origins: "*", headers: "*", methods: "*")]