1

I think I understand CSRF and how using form keys can prevent that, but this is can only be useful for POST data coming from a form, right? In my website I let logged in users delete some items by clicking on a Delete button which sends them to delete.php?id={item_id}.

On delete.php I check if the item belongs to the user, if it does than the script deletes it. How can I stop some other site posting a link like www.mysite.com/delete.php?id=3. I understand that the attacker will have to guess the id in my case.

But in general, how do you stop CSRF for GET data or data in a url?

Also what is the difference between an attacker using an img tag or a anchor tag for doing CSRF and how do they relate to Get and Post data?

Thank you very much in advance and I will really appreciate any advice on this.

Sameer Zahid
  • 553
  • 1
  • 9
  • 20
  • 1
    When the user clicks the delete button, have a special hash also sent `?id=3&confirm=d41d8cd98f00b204e9800998ecf8427e`, then have the server confirm that. The attacker has no way of knowing the hash. – Dave Chen Jun 08 '13 at 18:23
  • So on the page where I have a delete button, I can store that hash in the Session of the user. On delete.php I can check the hash in the url with the hash in the session. However, is it a good idea to use the PHPSESSID in the delete.php url? Like delete.php?id=4&session_id=2w1edasda This way I will not have to create a hash on the page where the Delete button is. – Sameer Zahid Jun 08 '13 at 18:29
  • Check my answer, I wrapped session_id around md5. It works without using md5 as well. – Dave Chen Jun 08 '13 at 18:30

2 Answers2

1

A great example of the intended difference between $_POST and $_GET. $_GET should be for reading data, while $_POST should be used for acting upon it. Instead of a link, you could use a form with one submit button, and your token as a hidden input. You can even use CSS to style the button to look like a link if desired.

Leigh
  • 28,765
  • 10
  • 55
  • 103
Jessica
  • 7,075
  • 28
  • 39
  • Thanks for your input, but do you think this method is used by programmers? – Sameer Zahid Jun 08 '13 at 18:40
  • Considering that's how the two methods were meant to be used, yes, I think programmers (I am one by the way...) do it that way. Which specific part are you questioning? – Jessica Jun 08 '13 at 19:01
  • I meant using a form for this instead of a button; but yeah u've answered my question. – Sameer Zahid Jun 08 '13 at 19:05
  • I can only assume you mean instead of a link, as the button would be used when you do use a form. Without a form element, the button won't be very useful for this purpose. ;) – Jessica Jun 08 '13 at 19:08
  • Yeah sorry, I meant a link and not a button :) But yeah, using a form instead of a link will be too bothersome for me as I am pure programmer and hate trying to do tricky stuff like that with Css. But still you've taught me something here about Get and Post data and I will keep that in mind for other things. So thanks again. – Sameer Zahid Jun 08 '13 at 19:14
  • 1
    It's not a link, it doesn't link anywhere - the correct markup for this is a form button. Having a destructive action such as a delete on a GET request is not how the web is supposed to work. Go learn the CSS - it's really not hard. – bobince Jun 08 '13 at 20:44
1

Expanding on my comment,

Assuming you are using a cookie/session to keep track of user login. Simply md5 again on the hash and let that be your confirm.

if (isset($_GET['delete'] && md5($_COOKIE["PHPSESSID"])==$_GET['confirm'])) {
    //delete something
}

Then for the HTML you could state:

<a href="www.mysite.com/delete.php?id=3&confirm=<?php echo md5($_COOKIE["PHPSESSID"]);?>">Delete</a>
Dave Chen
  • 10,887
  • 8
  • 39
  • 67
  • umm... no. CSRF tokens should be one-use. Otherwise, they provide no additional advantage over just a session ID. – John Dvorak Jun 08 '13 at 18:29
  • But is it entirely safe to use PHPSESSID of the user in a url, even if it is hashed? – Sameer Zahid Jun 08 '13 at 18:31
  • Not really @JanDvorak. CSRF is something else than session. Attackers already use the session (the user is logged in), but they cannot send a valid request when they don't know the CSRF token. I agree it is better to refresh the thing though :) – PeeHaa Jun 08 '13 at 18:31
  • No he's saying that it could fall to a replay attack, which I agree. It's just an example :) – Dave Chen Jun 08 '13 at 18:31
  • What do you mean by the replay attack? please explain that. – Sameer Zahid Jun 08 '13 at 18:32
  • 1
    The best method is to generate a new token every time the page is viewed. – Dave Chen Jun 08 '13 at 18:32
  • So we all agree on generating a new token? but do you think it would be unsafe to use the PHPSESSID instead? – Sameer Zahid Jun 08 '13 at 18:35
  • I don't want to get bombarded with -1s but it's safe to use PHPSESSID. The attackers don't know the session and therefore also don't know the confirm token. When they setup an attack link such as `delete.php?id=3`, it will be rejected by the server because there is no confirm token. The token is just the session, and since the session is unknown it's safe. – Dave Chen Jun 08 '13 at 18:37
  • This is a poor man's CSRF token. Tokens don't have to be single-use (in fact, they probably *shouldn't* be as it breaks navigation and multi-tab use), but they *are* supposed to remain secret, and in that case putting them in the URL makes them more likely to leak out (eg through logs, proxies and referrers). Secrets in the URL is a Bad Thing, which is why CSRF protection is not used on GET requests - and should never normally be needed on GET requests since they are supposed to be free of active effects (aka 'idempotent'). The mistake is having a delete operation on GET - it should be POST. – bobince Jun 08 '13 at 21:04
  • In terms of security, why do you think it is a bad idea to use a secret in the URL. The secret key will randomly generated and when using tokens and form keys, it will only be valid for one request and will be useless later. So even if it goes into logs and proxies or referrers, why do you think it will matter, if we are not showing the user's session information or anything like passwords – Sameer Zahid Jun 09 '13 at 19:35