Tricky question for good understanding of 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.
精彩评论