I am researching stuff I hear regularly that when doing a webapp in JSF 2.0 you are already protected from crossite - scripting and - request forgery. The following excerpt from a SO post confirms this:
In JSF 2.0 this has been improved by using a long and strong autogenerated value instead of a rather predictable sequence value and thus making it a robust CSRF prevention.
Can someone provide some more detail on this? How does this autogenerated value prevent CSRF? Thanks!
How does this autogenerated value prevent CSRF ?
Because it cannot be guessed. So the attacker cannot hardcode it in a hidden field in a form of the attack website (unless the target site has a XSS hole and thus the value can simply be obtained directly by XSS means). If the value is not valid for JSF, then the form submit from the attack website will simply not be processed but instead generate a ViewExpiredException. Please note that the attacker would still need to get the session ID so that it can be passed back through jsessionid URL attribute, so the originally "weak" CSRF protection would still require some XSS hole to obtain the session ID.
After all, I have the impression that you do not understand at all what CSRF is; the answer is rather self-explaining if you understand what CSRF is. In that case, please check the following question: Am I under risk of CSRF attacks in a POST form that doesn't require the user to be logged in?
One thing to remember is that the CSRF-protection in JSF 2.0 is implicit and is only valid for POST requests.
In JSF 2.2 there will be more explicit support for this. I briefly explained this here: http://arjan-tijms.omnifaces.org/p/jsf-22.html
Related
We recently received result from IBM AppScan DAST and some of the result don't make much senses.
2.Medium -- Cross-Site Request Forgery
Risk(s): It may be possible to steal or manipulate customer session and cookies, which might be used to impersonate a legitimate
user, allowing the hacker to view or alter user records, and to perform transactions as that user
Fix: Validate the value of the "Referer" header, and use a one-time-nonce for each submitted form
The following changes were applied to the original request:
Set header to 'http://bogus.referer.ibm.com'
Reasoning:
The test result seems to indicate a vulnerability because the Test Response is identical to the
Original Response, indicating that the Cross-Site Request Forgery attempt was successful, even
though it included a fictive 'Referer' header.
Request/Response:
POST /**/main.xhtml HTTP/1.1 -- **This xhtml only opens a default menu on page load**
User-Agent: Mozilla/4.0 (compatible; MS
The recommend fix
Validate the value of the "Referer" header, and use a one-time-nonce for each submitted form.
javax.faces.ViewState has an implicit CSRF protection.
https://www.beyondjava.net/jsf-viewstate-and-csrf-hacker-attacks
I could also do explicit CSRF protection using protected-views. This explicit CSRF protection adds a token for all cases, and additionally adds checks for the “referer” and “origin” HTTP headers. (Reference Bauke & Arjan Book Definitive Guide)
The report also marks /javax.faces.resource/ like CSS , JS , fonts which i believe are false positive in the report.
Looking for feedback and some insight.
This is indeed needless in JSF. This kind of attack is in JSF only possible when there's already an open remote code execution hole such as XSS (and thus the hacker has access to among others the session cookies and can therefore copy them via the phishing site), or when the view is stateless via <f:view transient="true"> (because you lose the javax.faces.ViewState hidden input field as implicit CSRF protection for the "normal" case when there's no remote code execution hole), or when you use HTTP instead of HTTPS (because a man-in-middle attacker can then plainly see all transferred bits and extract the session cookies from them).
All you need to make sure is that the enduser's session cookies are never in some way exposed to the world. The advised fix is not at all helpful in that. It only makes it the attacker more difficult to perform a successful CSRF attack when you sooner or later accidentally introduce a remote code execution hole. But then you have really way much bigger problems than only CSRF. All these efforts advised by this tool are only useful to give the hacker slightly less time to perform a successful attack, and to give yourself slightly more time to fix the remote code execution hole.
If all you want is to "suppress" this warning, then create a Filter which does the desired job. Here's a kickoff example, map it on /*.
if (!"GET".equals(request.getMethod())) {
String referrer = request.getHeader("referer"); // Yes, with the legendary typo.
if (referrer != null) {
String referrerHost = new URL(referrer).getHost();
String expectedHost = new URL(request.getRequestURL().toString()).getHost();
if (!referrerHost.equals(expectedHost)) {
response.sendError(403);
return;
}
}
else {
// You could also send 403 here. But this is more likely to affect real users.
}
}
chain.doFilter(request, response);
see also:
CSRF, XSS and SQL Injection attack prevention in JSF
So I just read this article by Jeff Atwood and I wanted to make sure I understand it correctly as to how it applies to my use case. I am trying to validate a session for silent login. For security purposes this should be done with a POST right? Does it matter? I am just passing the sessionID and username from the cookie.
When it comes to CSRF (Cross-site request forgery), you can cause a user to take any action on any site which they are logged in to provided that the action requires only a GET. Forcing this to be done over a POST request defeats the approach of embedding an image, script tag, whatever in another page.
Even POST isn't completely secure in this scenario. There are other ways to mount a CSRF attack on a site using POST. Clickjacking/UI-Redressing enables another site to trick a user into submitting a form to a different website.
Basically the best way to validate is to add an automatically generated, hidden form element. You can store this inside your session data (Example: $_SESSION for PHP) so that you only need to generate a token at the start of a session. Of course, an attack could try do something like clickjacking (mentioned above) in combination with a iframe pointing directly to your site and possibly some JS to hide things a little.
For anything important you should re-prompt the user for their password, thereby greatly diminishing the value of any successful CSRF attacks.
All the examples of CSRF exploits tend to be against pages which process the incoming request.
If the page doesn't have a form processing aspect do I need to worry about CSRF ?
The situation I'm looking # :
the page in question contains sensitive data
as such users need to establish a session to view the page
... my understanding is that a malicious page will be able to redirect a client to this page by embedding a link to it, however since there's no action on the target to perform there's no harm that can result, right ?
There's no way for said malicious site can view the sensitive page, correct ?
Why I ask: I want the url to the page with sensitive data to have a 'simple' URL which allows people to email the link to other people (who will in turn need a session to view the page). The token-based solution I've seen for most CSRF solutions remove this possibility, and so I'd like to avoid them if possible.
There's no way for said malicious site can view the sensitive page, correct ?
Correct in terms of CSRF.
The blog you linked is talking about Cross-Origin Script Inclusion, which is a different animal. To be vulnerable to XOSI your sensitive page would have to be interpretable as JavaScript, and you'd have to be either serving it without a proper HTML MIME type, or the browser would have to be an old one that didn't enforce type checking on scripts.
You might also potentially worry about clickjacking, where another site includes yours in a frame and overlays misleading UI elements. There are some sneaky ways that has been used to extract sensitive data (see the next generation clickjacking paper and this amusing info leak in Firefox) so you may wish to disallow framing with the X-Frame-Options header.
Why I ask: I want the url to the page with sensitive data to have a 'simple' URL which allows people to email the link to other people (who will in turn need a session to view the page). The token-based solution I've seen for most CSRF solutions remove this possibility
You definitely shouldn't be putting a CSRF token in a GET URL. Apart from the ugliness, and breakage of navigation, URLs are easy to leak from the browser or other infrastructure, potentially compromising the confidentiality of the token.
Normal practice is not to put CSRF protection on side-effect-free actions.
In general, CSRF is independent from whether the request causes any side effects or not. The CWE describes CSRF (CWE-352) as follows:
The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
So CSRF is a general request intention authenticity problem.
However, although CSRF is not really feasible without any effects other than data retrieval as the same-origin policy restricts the attacker from accessing the response, the attacker could exploit another vulnerability to profit from retrieval-only requests as well and gain access to sensitive data.
I have been looking into the OWASP recommendation to prevent CSRF attacks (https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet).
Now, what I do not understand is how this would prevent an attack that is a combination of an XSS and a CSRF attack. Let's say we have the following attack scenario:
Attacker is able to perform a stored XSS attack, so that the script that the attacker inserts on the website is executed everytime a user visits the page.
This script will completely redesign the DOM, for example instead of the original form where a user needs to give some irrelevant information, the attacker's script redesigns it so that this form will be redesigned to a form where a user with admin privileges is added. Note that the user will not see this, as the labels of the fields will remain the same. Only the POST will be different.
The attacker knows that this website uses anti-CSRF tokens. Looking at the OWASP recommendation: '(..)application should include a hidden input parameter with a common name such as "CSRFToken"', the attacker knows that most websites will have a hidden field with this id somewhere on the page.
the attacker makes sure the value of this field is also submitted in the fake POST. Even though the attacker doesn't know the value of this hidden field, it can specify in the POST that this value should be sent with the request. This is possible, as the user's DOM has been modified, the request will come from the user's browser, the user's cookies will also be sent with the request.
The user submits the form, and the fake user is created.
It seems to me this cannot be prevented by just using a CSRF token. Or is an implicit assumption of the synchronizer pattern that XSS attacks have been neutralized?
Or is an implicit assumption of the synchronizer pattern that XSS attacks have been neutralized?
Yes. If your website is attacked in this way then it is an XSS attack rather than CSRF. CSRF simply means the request is made "cross site", whereas in your example the request is on the same site - it is just the scripting that is "cross site".
Is it ok to put the CSRF token in a cookie? (and in every form, as a hidden input, so I can check if they match, of course) I heard someone say that doing so, beats the whole purpose of the token, though I don't understand why. It seems secure to me.
And if it is secure, is it any less secure than puting the token in the URL's ?
Is there any other method?
Where can I read more on the subject?
UPDATE: So far no one can tell me how is the cookie method insecure, if it still has to match the token from the form, which the attacker shouldn't be able to get, unless he uses another hack like XSS, which is a different matter, and still doesn't make a difference between using cookie and url token.
UPDATE 2: Okay, seems like some famous frameworks use this method, so it should be fine. Thanks
Using cookies works, and is a common practice (e. g. Django uses it). The attacker cannot read or change the value of the cookie due to the same-origin policy, and thus cannot guess the right GET/POST parameter.
Check out the Encrypted Token Pattern, which allows stateless CSRF protection without the need to store tokens on the server.
If you decide to put the CSRF-token in a cookie then remember to mark that cookie as HttpOnly. If your site has a cross-site scripting vulnerability the hacker won't be able to read the CSRF-token. You can check the cookies that can be read by JavaScript using the command console.log(document.cookie) in any modern browser console. If you have session cookies or other sensitive cookies these should also be marked as HttpOnly.
Further reading:
https://www.owasp.org/index.php/HttpOnly
"CSRF works because many sites use GET requests to execute commands.", so, many sites don't use the GET method as expected, because these request must be idempotent: see the rfc2616.
"The CSRF parameter is already there in the cookie and it gets sent along with the session.", so how?
The cookie is only used has a token storage, as the DOM when we set the token in a hidden input field. A piece of javascript must get the token value from this cookie, and set it as a parameter in the URL, the request body or in the request header. It will be check on the server with the value stored in the session. That's the Django way to handle the CSRF token.
Javascript can't access the cookie from another domain, due to the cross domain browser protection, so I don't know how a malicious user can force someone to send the correct token along a forged request. With an XSS, yes, but XSS defeat the common CSRF countermeasures.
I prefer giving this clarification, because I think it's an important question and not so easy to handle.
GET request must be used to get a resource and/or display its data, it must not be used to change its state (deletion, property incrementation or any changes).
The CSRF validation must be done server-side, it seems to be obvious, but I put it as a reminder. This method can't be a vector of attack if you observe this recommandations.
Using a cookie defeats the purpose of CSRF. Here's why:
CSRF works because many sites use GET requests to execute commands. So say Bob has some kind of administrative web account and he's logged into it. Some request could be made like:
http://somesite.com/admin/whatever.php?request=delete_record&id=4
So now Bob gets linked to an attack site (someone is trying to mess with his data). The attacker then loads the above URL in an image, probably with another ID and deletes some other record. The browser loads it because Bob is already logged into his admin site so he has a valid session.
CSRF seeks to eliminate this by adding a secure parameter to the transaction. That parameter should rotate on every request and then be resent by the browser. Making the URL look something like this:
http://somesite.com/admin/whatever.php?request=delete_record&id=4&csrf=<some long checksum>
The idea is that now the attacker has to guess "some long checksum" to create an attack. And if that checksum rotates on every request well it should be virtually impossible.
BUT if you store that checksum in a cookie you're back at square 1. The attacker no longer has to guess it. He just crafts the original URL. The CSRF parameter is already there in the cookie and it gets sent along with the session. It doesn't stop the insecure behavior from happening.