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".
Related
This isn't a language specific question, but I am using PHP5.
I am working on a project that has some amount of PII. Legally we are required to secure this data from hacking attempts, and because of that I have been researching best practices for defending common attack types. Obviously all database calls are using parameterized queries, and all data provided by the user is sanitized to prevent injection. I have also implemented sessions and methods to prevent session hijacking.
When it comes to defending against XSS attacks on forms, best practice seems to be to include a hidden input with a form token, then after the post to check the tokens match. There are further ways to make this more secure.
I have imagined one type of attack and haven't found a solution for it. What if a malicious site loads a hidden iframe pointed at my site (eg, view-member.php?id=1234) and because the victim user is logged into my site, their session continues in that iframe. What is stopping this malicious site from iterating through the IDs and ripping the data to get ahold of PII? Should I be creating a unique token for each page view, and checking that token when the page loads?
I am not 100% sure, but assuming my site is using HTTPS, the browser should warn the user and/or prevent the connection. Is that correct? Is that enough security?
In fact, everytime you present a form or any kind of interaction, you should include a randomized, verifiable piece of information that changes every time. This is not for preventing XSS but CSRF: https://en.wikipedia.org/wiki/Cross-site_request_forgery
The main problem is: An attacker can just send automated requests to your input-handling script without going through the "pain" of filling in your form manually (or even visit your page).
However, you won't prevent XSS attacks with this technique, as XSS attacks are mainly user input containing executable code (javascript) that is not filtered by the input validation. So to prevent XSS as well, you should always make sure not to deliver unfiltered user-generated content anywhere.
HTTPS won't help you in either case unless you use client-side certificates that allow access to your website only from trusted clients. HTTPS mainly acts as a transmission scrambler and identity verifier but does not prevent a bot from sending valid (but malicious) data to your form.
Hosting a website in an iFrame does not grant the attacker the permission to read cookies or information from the target page (that would be awful) as long as you follow the same-origin policy: https://en.wikipedia.org/wiki/Same-origin_policy
With this, only domains you whitelist will get access to information hosted on your page.
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'm currently learning more about CSRF and I have a basic question about cookies. From Jeff Atwood's article on CSRF:
"When a POST request is sent to the
site, the request should only be
considered valid if the form value and
the cookie value are the same. When an
attacker submits a form on behalf of a
user, he can only modify the values of
the form. An attacker cannot read any
data sent from the server or modify
cookie values, per the same-origin
policy. This means that while an
attacker can send any value he wants
with the form, he will be unable to
modify or read the value stored in the
cookie."
If cookies are a piece of text stored on a users computer, how can they not modify/read the value of a cookie?
If they knew the value of the cookie and can see a pseudorandom value hidden in a form, wouldnt they have all they need to perform an attack?
Thanks,
Same origin policy means that an attacking website is unable to read the cookies from another domain. See http://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_cookies
We're not talking about an attacker who has a rootkit or something of the sort on a user's computer, what CSRF protects from is a malicious server having a user submit a form via a POST request to a domain that the malicious server wants to attack. Because the malicious server can't read the cookie from the target domain, they can't properly fill out the CSRF field for the POST request they're making.
What this is referring to is the synchroniser token pattern. What it usually means is that a form contains a hidden field with a value that is unique to that user's session. The same value is stored in a cookie in the user's machine. When the form is submitted, both values are checked for a match.
The advantage of this approach is that if a malicious website attempts to construct a post request to the legitimate website it won't know that hidden form value. It's an altogether more complex process to obtain this.
The attacking site can't read or manipulate the cookie value because it was issued from another domain. More on this (including a worked example) here: OWASP Top 10 for .NET developers part 5: Cross-Site Request Forgery (CSRF)
My friend and I have a pari for beer.
From wikipedia:
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 submissions
The atacker can use browser cookies indirectly, but he can't use them directly!
That's why he can't put the cookies into the link using document.write()
Let us look how the logout link is generated. Is it secure way? Can this GET request be faked?
function logout(){
echo '<a href="?action=logout&sid='.htmlspecialchars($_COOKIE['sid']).'>Logout</a>';
}
sid is a session ID, generated for every session
on the server side, the following checking is performed:
$_GET['sid']==$_COOKIE['sid']
Absolutely not! Never use session identifiers for CSRF protection.
As far as why? Well, the answer is simple. Doing so opens the door for session hijacking attacks. Imagine someone copies and pastes the link for some reason into an email or onto the web. Now, the person on the other end of the email has the session identifier of that session. Sure, if they click the link it won't activate the session, but someone who knows what they are doing will still be able to use it.
And don't use a secret cookie either. Cookies are transmitted on every request. So the mere existence of a cookie does not verify that the user intended to make the request.
How to do it instead? Follow the OWASP recommendations. Use a unique, random token that's issued on each request and is associated with the session. Then verify that the token is valid on submission and then invalidate the token! It should be a one-time-use token only. Have it submitted by the form, and not attached to a link directly...
This prosed security system is immune to CSRF. The reason why this works is because in a CSRF attack the browser keeps track of the cookie, so the attacker doesn't need to know the cookie value when he is building the request. If this proposed security system where vulnerable to CSRF an exploit like the following Proof of Concept would log out a browser:
<img src=http://victim_site/index.php?action=logout&sid= />
Clearly in this case sid needs a value, and an attacker cannot obtain this value without using XSS, which makes this a moot point. Using xss an attacker can read a CSRF token to forge requests. This was used in the MySpace worm Sammy.
The use of the cookie a valid, however weaker form of CSRF protection. One problem is that it totally undermines http_only cookies. Ideally a CSRF token and a session id should be a Cryptographic nonce. However, it is more secure to have them be separate values.
Edit: This answer is at least partially wrong. Using the session ID as a CSRF token could lead to session hijacking if, eg, links are copy+pasted around. See ircmaxell's answer and comments.
Yes, because the session ID is both random and associated with the user, it would be an acceptable form of CSRF protection.
That said, it would be even safer to use a different random number, on the off chance that malicious JavaScript is able to grab the session cookie (and session ID)… But if I had to choose between “no CSRF token” and “session ID as a CSRF token”, I'd always pick the session as a CSRF token.
The only potential problem with using session IDs as CSRF tokens is: if someone was able to steal a CSRF token, they would also be able to hijack the associated session… But I can't think of a sensible scenario where that would be an issue.
Now, from the discussion on Marc B's answer, below: using a nonce would provide other benefits (like preventing duplicate form submissions)… But it isn't any more secure against CSRF attacks than the session ID (with the one caveat I mention in the first second paragraph).
See also: CSRF Validation Token: session id safe?
And what's to stop someone from editing the HTML that you send them, as well as the cookie, which you've also send them? Both are are under the control of the user.
With firebug I can trivially change the contents of any page, as well as any cookie.
Now, if you'd modified your version so that the SERVER stores that ID, then it would be harder to hack...
$_SESSION['form_token'] = 's33krit valu3';
if ($_POST['form_token'] == $_SESSION['form_token']) {
... everything's ok ...
}
Since the session data is kept on the server, out of the attacker's hands, this is far more secure than trusting the attacker won't think to modify the cookie.
You owe your friend a beer.
I have a question about XSS
Can forms be used as a vector for XSS even if the data is not stored in the database and used at a later point?
i.e. in php the code would be this:
<form input="text" value="<?= #$_POST['my_field'] ?>" name='my_field'>
Showing an alert box (demonstrate that JS can be run) on your own browser is trivial with the code above. But is this exploitable across browsers as well?
The only scenario I see is where you trick someone into visiting a certain page, i.e. a combination of CSRF and XSS.
"Stored in a database and used at a later point": the scenario I understand about CSS is where you're able to post data to a site that runs JavaScript and is shown on a page in a browser that has greater/different privileges than your own.
But, to be clear, this is not wat I'm talking about above.
Yes, it's still an attack vector.
What you need to consider is:
Can an authenticated user be tricked into viewing this page with maliciously-crafted data?
The answer is this case is yes (assuming you have authenticated users). Because it's possible to direct someone to your site and pass in malicious variables to that field.
Yeah, it's still an attack vector, although impact is more situational.
Here's a contrived scenario that expands on previous answers if the form requires authentication to reach (and is easier if the site doesn't care if forms are submitted via POST or GET):
1) Attacker uses CSRF to login the victim using the attacker's credentials (e.g. <iframe src=http://../login?id=...&pass=..."></iframe>). This way the attacker brings the form to the victim and it doesn't matter if the victim doesn't have an account.
2) Attacker uses another CSRF to execute XSS against the form, which asks the victim for some credentials, etc. (This is where some convincing social engineering needs to occurr or the attacker has some useful JavaScript to use within the browser's Same Origin for the site.)
Another contrived scenario in which the vulnerable form performs some important action, like transfer money between accounts:
0) Vulnerable form uses hidden form fields with random values to prevent CSRF. The attacker doesn't know what the values are and can't set up a proper attack.
1) Attacker creates a CSRF payload that includes JavaScript to read a form's random csrf tokens (i.e. pull them from the browser's DOM).
2) Victim logs into site.
3) Attacker lures victim to CSRF payload, CSRF bootstraps the form request with the correct csrf tokens because it's executing in the victim's browser, within the victim site's Same Origin, and using the victim's auth session. The attacker doesn't need to know the csrf tokens, just be able to manipulate the form fields that store them.
4) Attacker benefits from having the victim submit the form -- no pop-ups or social engineering necessary aside from luring the victim to the CSRF payload, but the form needs to do something "useful" for the attacker.
i think what you are mean is, since User 2 cannot be showing previous data added by User 1, so can the XSS happen? So if User 1 hack the URL so that some $_GET params got displayed on the webpage as well (and then even, change it to a tinyurl), and spread this URL saying that it is really worthwhile to see this page, etc, then it might be possible.
So it is still better to escape all params when displaying the page.
That is absolutely a valid form of XSS. XSS comes in two forms - stored and reflected. Reflected is much more common, but stored has the potential to be more damaging. Reflected XSS is usually used as part of a social engineering attack. An attacker creates a URL like the following:
http://host.com/page.php?my_field=malicious_code
They will often shorten the URL with tinyutl or bit.ly, and get it out with the usual social engineering methods (email, message board, twitter, hijacked facebook accounts, etc.)