Jump to content

Recommended Posts

Howdy - as I'm getting closer to having my web app finished, I realized I had nothing for CSRF prevention.

 

My admittedly limited understanding of CSRF is that the attacker forges a form submit and tricks a legitimate user into running it. Thus if the user has a valid session ID in their browser cookie, the server gets the post, reads the cookie, and trusts that the post is legitimate.

 

So - this is what I'm doing to try and mitigate it.

 

I modified my php sessions class (database driven) to add a CHAR(32) field. When a session is created, md5(microtime() . rand()); is inserted into that field.

 

Forms then have that value as a hidden input, and when a form is submitted, the input value is checked against what it is the database for the users session ID. If it doesn't match, a redirect header is sent and the script die();

 

If a cracker is targeting a specific user, he may be able to intercept the key that is specific to the users session by snooping the traffic (user login/prefs is over ssl but nothing else is) but since I only use session cookies - the cracker would have to sniff the key during the users existing session or he won't be able to forge a form that would validate.

 

If a cracker is not targeting a specific user, it's not an issue.

 

I went ahead and tried it myself - and it seems to work.

I don't want to rely on any of the referrer globals because those can be forged and some users for privacy reasons disable them.

 

Anyway, does my scheme work or are there other measures I should take?

Link to comment
https://forums.phpfreaks.com/topic/145462-csrf-protection/
Share on other sites

I suppose an even safer way to do it would be to generate the key when the form is created and put in a database with the session id, and check the key + session id pair on form submit - deleting the pair on submit and run some kind of garbage collection that deletes pairs from expired sessions.

 

That would pretty much eliminate the cracker targeting a specific user and snooping the network to try and catch a valid key.

Link to comment
https://forums.phpfreaks.com/topic/145462-csrf-protection/#findComment-763665
Share on other sites

The per form method is working extremely well. Here's the sql table -

CREATE TABLE csrf (
   id MEDIUMINT unsigned NOT NULL AUTO_INCREMENT,
   sid varchar(32) NOT NULL,
   mykey varchar(32) NOT NULL,
   PRIMARY KEY (id)
   );

 

Here are the two php functions - first sets the key, second checks the key that was passed on post:

<?php
function csrfkey($sid) {
   $random = md5(microtime() . $sid . rand());
   $sql = "INSERT INTO csrf (sid,mykey) VALUES ('$sid','$random')";
   mysql_query($sql);
   return($random);
   }
   
function checkcsrf($sid,$mykey) {
   $sql = "SELECT id FROM csrf WHERE sid='$sid' AND mykey='$mykey'";
   $result = mysql_query($sql);
   while ($somevar = mysql_fetch_object($result)) {
      $valid = $somevar->id;
      }
   if (! isset($valid)) {
      return false;
      } else {
      $sql = "DELETE FROM csrf WHERE id=$valid";
      mysql_query($sql);
      return true;
      }
   }
?>

 

I think that should do it, unless anyone more experienced than me has other advice.

Link to comment
https://forums.phpfreaks.com/topic/145462-csrf-protection/#findComment-763727
Share on other sites

The problem with using sessions is that with this application, it is certainly conceivable that one might have numerous forms open at the same time. I will when using the site. So either I need to have the same key for the duration of a session or use the database so I can have multiple keys that expire as soon as a they are used in a submit.

Link to comment
https://forums.phpfreaks.com/topic/145462-csrf-protection/#findComment-763748
Share on other sites

The session ID itself is too dangerous to ever send to the client since if intercepted it can be used to forge a cookie to allow login as the user.

 

But an md5 of the session ID + salt would probably be safe.

 

The reason I want it to change though with each form - even though I don't use persistent cookies, session cookies only, a session can be active for quite some time - I know sometimes I have my browser open on my desktop for weeks (I run Linux so rebooting is really only necessary with a kernel update, I use noscript so pages that do obscene things w/ js and flash that cause firefox to crash rarely impact me).

 

Every time a user requests a page, the clock for when their session expires server side is reset, so it is conceivable that a session could last for quite some time.

Link to comment
https://forums.phpfreaks.com/topic/145462-csrf-protection/#findComment-764093
Share on other sites

You still don't want to use the sid as the key.

 

Cracker just needs to write a malicious script that downloads form and sends it to him.

Cracker e-mail script to thousands of users.

Cracker then parses what comes back for session ID's - thus eliminating the need to sniff packets and increasing the potential victim base.

 

That would would work, btw, even if the server was https.

Link to comment
https://forums.phpfreaks.com/topic/145462-csrf-protection/#findComment-765159
Share on other sites

I think you'll find that it is not possible. The same origin policy protects against this. It prevents scripts from accessing data on websites it does not originate from. The origin is determined by the domain name (e.g. www.phpfreaks.com), application layer protocol (e.g. HTTP), and TCP port (e.g. 80). This means that a piece of Javascript running on http://example1.com is not able to access e.g. DOM http://example2.com because it's two distinct domain names and thus not the same origin.

 

If the browser contains a hole that lets an attacker circumvent the same origin policy then there is nothing, as server side developer, you can do to protect your user. If the user's machine has been compromised then there is nothing you can do about it either.

 

Using the SID is perfectly safe, but if you wish to tighten security then you can regenerate the SID every X requests for instance.

 

You can try it for yourself.

Link to comment
https://forums.phpfreaks.com/topic/145462-csrf-protection/#findComment-765195
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.