I have an website where people can place a vote like this:
http://mysite.com/vote/25
This will place a vote on item 25. I want to only make this available for registered users, and only if they want to do this. Now I know when someone is busy on the website, and someone gives them a link like this:
http://mysite.com/vote/30
then the vote will be places for him on the item without him wanting to do this.
I have read the explanation on the OWASP website, but i don't really understand it
Is this an example of CSRF, and how can I prevent this. The best thing i can think off is adding something to the link like a hash. But this will be quite irritating to put something on the end of all the links. Is there no other way of doing this.
Another thing can someone maybe give me some other example of this, because the website seems fairly fugue to me.
This could become an example of CSRF if :
<img>
tag, for example) : forgeryFor example, if I could inject this
<img>
tag in the HTML source-code of stackoverflow (and I can, as stackoverflow allows one to use<img>
tags in his posts) :You would just have voted for that item ;-)
The solution that is generally used is to place a token, that has a limited life-time, in the URL, and, when the URL is fetched, check that this token is still valid.
The basic idea would be :
http://mysite.com/vote/30?token=AZERTYUHQNWGST
The idea there is :
Also, note that the shorter the user's session remains active after he has left your site, the less risks there are that it's still valid when he visits the bad website.
But here, you have to choose between security and user-friendly...
Another idea (that's not perfectly secure, but helps against guys would don't know how to force a POST request), would be to only accept POST requests when people are voting :
But note that this is not perfectly safe : it's (probably ? ) possible to force/forge a POST request, with some bit of Javascript.
There are 3 players in a CSRF attack
CSRF attacks depend on 2 facts
setcookie("sessionID", "0123456789ABCDEF", time()+3600);
)If an attacker could by away or another make a logged-in user requests this
for example by putting the link on the attacker website or send it in an email, the logged in client browser will send the identifying cookies(sessionID) along with this request, which will make the victim website think that his logged-in user really wants to vote!
But if the victim's website more clever and verifies the requests of his logged-in users with additional GET or POST parameter (not cookies), the attacker now is in a problem because GET and POST parameters are not sent automatically by browsers, and he has to guess it.
The attacker doesn't know the
csrfSecret
parameter which is a secret between the victim website and his client (just like the session token), so the attacker has no way to build the URL that he wants forge a request by.Similarly, if the vote is done by POST requests, the attacker will not be able to make the form on his website(or third party website) because he doesn't know the secret between the victim's website and his users.
OWASP has a CSRFGuard for PHP, and ESAPI for PHP that I wrote a long time ago for XMB -> UltimaBB -> GaiaBB.
http://code.google.com/p/gaiabb-olpc/source/search?q=function+get_new_token&origq=function+get_new_token&btnG=Search+Trunk
It seems some others have cleaned up that code and allowed for stronger tokens:
https://www.owasp.org/index.php/PHP_CSRF_Guard
thanks, Andrew
First, GET request shouldn't be used to alter states on the server, so for your vote service I would recommend POST/PUT. This is only a guideline, but a cleaver one.
So to your question, CSRF is a client issue so it doesn't matter what kind of server language you use (PHP in your case). The standard fix is the same and goes like this: Have a random value in the URI/POST-data and the same value in the Cookie header. If those matches you could be sure there is no CSRF. There are a lot of info about how this could be done here on StackOverflow eg. this one.
Good luck!