This could become an example of CSRF if :
- that link is fetched (via an
<img>
tag, for example) : forgery
- from another site : cross-site
For 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) :
<img src="http://mysite.com/vote/30" />
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 :
- When generating the page :
- generate a unique token
- store it in the user's session
- and place it in the links of the page -- which would look like this :
http://mysite.com/vote/30?token=AZERTYUHQNWGST
- When the voting page is called :
- Check if the token is present in the URL
- Check if it's present in the user's session
- If not => do not register the vote
The idea there is :
- Tokens don't have a long life-time, and are hard to guess
- Which means your attacker :
- has only a window of a few minutes during which his injection will be valid
- will have to be good at guessing ^^
- will have to generate a different page for each user.
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 :
- The browser is sending GET requests for injected tags
- As this URL is modifying some data, anyway, it should not work with GET, but only with POST
But note that this is not perfectly safe : it's (probably ? ) possible to force/forge a POST request, with some bit of Javascript.