There is a lot of discussion lately about Cross-Site Request Forgery. Honestly, it's just an old and well known problem getting some media attention.Consider the following example. It's known that YouTube uses ajax to add a video to the currently-logged-in-user's favorites. For the sake of simplicity, say the endpoint url is: http://www.youtube.com/fave?id=1. Now let's say I'm an underdog director with a killer new indie movie that I want to promote. I go through flickr's explore pages and shove <img src="http://www.youtube.com/fave?id=1" width="1" height="1" /> as a comment to all popular photos. The next day I'm on YouTube's top directors, and the road to Hollywood is shorter than ever.
Of course the example above can be put to banking transactions, election votes and befriending strangers on social networks.
Working with POST instead of GET does not fix the problem, as javascript can create a form and submit it without user interaction.
So, how do you solve it?
global $user_id; # currently logged in user
global $video_id; # currently watched video
# a secret that is not shared outside the server
$secret = "here-be-a-secret-nobody-knows";
# url to be sent to browser
$auth = base64(sha1($secret . $user_id . $video_id));
$add_fave_url = "/fave?id=" . $video_id . "&uid=" . $user_id . "&auth= " . $auth;
When processing the ''fave'' request itself, just check that the auth signature matches the string you reconstruct from the parameters $user_id, $video_id and the server $secret. If they don't match, you have encountered an attempt of forgery.
By adding the id of the user that this url will affect, you are eliminating the possibility that Bob will add his video to other users' favorites but his own. You might also consider adding expiration (such as time()+86400) to your request, making it void after a certain period.
And an apology for all rising indie movie directors. You will just have to work harder. :)
0 comments:
Post a Comment