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.
Related
I am planning to do automated testing of post requests with various parameters on a link. The problem that I face is the link has a sso authentication. When I do a normal post in vbscript or java it directs me to the sso page.
Any idea how it can be done?
since you are working with http-post, I assume that SSO is performed by using Cookies.
In that case, everything you have to do is add those Cookies to your request.
This is done by adding a Header with name 'Cookie' to your request.
This headers value may be of the format 'CookieName=CookieValue'.
In case you have multiple Cookies, you can either add multiple Cookie Headers, or separate them by using a ';'.
In case you fetch those Cookies with a previous request, you can get a hold of the Cookies by evaluating the 'Set-Cookie' Header.
Additional Informations about basic Cookie Handling may be found here
In case you use Apaches HTTP-Components, you can also use its integrated Cookie Store to automatically add Cookies to new Requests.
A good example as how to basically use Apaches HTTP-Client can be found here
The part of how to use Cookies can be found in section 3
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
I am doing a Java web site. I hope to make the web site safer.
In my web site, all the forms are supposed (by design) to be opened in a page through a GET link from my website. I hope to check whether the referer is my web site in my server-side form submission handler. The idea is to avoid taking data from attacker-locally-generated form submission.
I feel that the key to this approach is whether the referer the server detects is reliable.
I understand that there are other ways to improve security. Let's just focus on the approach in my post.
Thanks for any input!
UPDATE
Specifically, I am doing a Spring MVC web site. I am using an interceptor to examine all traffic, especially the form submission.
No, it is not reliable. Some browsers may allow removing the referrer, or might not send it at all. And a naughty person can easily just add the referrer to the requests, so by itself it will not give any extra security except from random people trying random things.
Not the best way, but referer checking can help prevent Cross Site Request Forgery attacks:
Although it is trivial to spoof the referer header on your own
browser, it is impossible to do so in a CSRF attack. Checking the
referer is a commonly used method of preventing CSRF on embedded
network devices because it does not require a per-user state.
[snip]
...checking the referer is considered to be a weaker from of CSRF
protection. For example, open redirect vulnerabilities can be used to
exploit GET-based requests that are protected with a referer check and
some organizations or browser tools remove referrer headers as a form
of data protection.
Remember here that the attacker is not the one sitting at the keyboard - it is harder for them to spoof the referer from the victim's machine.
The strongest way of preventing CSRF though is the Synchronizer Token Pattern.
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.
Is there any web language that allows the client itself to create HTTP posts to external sites.
I know that JavaScript does this with XMLHttpRequest, but it does not allow cross-domain posting, unless the recipient domain wants to allow the sending domain.
I want to post data to an external site (that I don't control) and have the request be authenticated with what the client's browser already has (cookies, etc).
Is this possible? I tried cURL but it seems to make a server HTTP post, not a client HTTP post.
Edit:
A bit more insight of what I am trying to do:
I am trying to POST JSON to the website using the user's session (I said cookies but I believe they are PHP sessions, which I guess I still consider cookies).
The website does NOT check the referral (poor security #1)
I can execute javascript and html on the webpage using my personal homepage (poor security #2)
The JSON code will still work even if the content-type is form (poor security #3)
There is no security checking at all, just PHP session checking.
The form idea is wonderful and it works. The probably again is that its JSON. So having sent postdata as foo={"test":"123", "test2":"456"} the whole foo= part messes it up. Plus forms seem to turn JSON into form encoding, so its sending:
foo=%7B%22
test%22%3A+%22
123%22%2C+%22
test2%22%3A+%22
456%22%7D
when i need it to send;
{"test":"123", "test2":"456"}
So with everything known, is there a better chance of sending JSON or not?
I don't think so: You won't get hold of the user's auth cookies on the third party site from server side (because of the Single Origin Policy) and you can't make Ajax requests to the third party site.
The best you can do is probably create a <form> (maybe in an <iframe>), point it to the third party site, populate it with data, and have the user submit it (or auto-submit it). You will not be able to get hold of the request results programmatically (again because of the Single Origin Policy), but maybe it'll do - you can still show the request results to the user.
I think for obvious reasons this is not allowed. If this was allowed what would stop a malicious person from posting form data from a person's browser to any number of sites in some hidden iframe or popup window.
If this is a design of your application you need to rethink what you are trying to accomplish.
EDIT: As #Pekka was pointing out I know you can submit a form to a remote site using typical form submits. I was referring to using some client side ajax solution. Sorry for the confusion.
You should follow the way OpenID and other single-sign-on system works. How openID works is your website POSTs some token to openID service and in return gets authentication result. Refer How Does it Work? section here
Yes, you can use a special flash library that supports cross-domain calls: YUI connection manager
Added: not sure about the cookie authentication issue though...
The client cannot post to an external site directly; it's a breach of basic cross-domain security models. The exception is accessing javascript with JSONP. What you describe would require access to a user's cookies for another website, which is impossible as the browser only allows cookie access within the same domain/path.
You would need to use a server-side proxy to make cross-domain requests, but you still cannot access external cookies: http://jquery-howto.blogspot.com/2009/04/cross-domain-ajax-querying-with-jquery.html