CodeIgniter Forums
MY_Form_Validation w/ spam and CSRF protection - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Archived Discussions (https://forum.codeigniter.com/forum-20.html)
+--- Forum: Archived Libraries & Helpers (https://forum.codeigniter.com/forum-22.html)
+--- Thread: MY_Form_Validation w/ spam and CSRF protection (/thread-31123.html)

Pages: 1 2


MY_Form_Validation w/ spam and CSRF protection - El Forum - 06-07-2010

[eluser]erik.brannstrom[/eluser]
Hey guys,

I extended the form validation library the other day to deal with some issues I had with spam by using nonce words. I realized while I was at it that I might also be able to prevent CSRF attacks using the same idea.

This might look like a shameless plug for my blog, but I really wish to get some input on this. If I get some support for this I'll add it to the wiki as soon as possible, since I believe this is a useful addition to the framework.

http://blog.streambur.se/2010/06/no-nonsense-protection-using-a-nonce/

UPDATE: New version at http://blog.streambur.se/2010/07/form-protection-revisited/

Best regards,
Erik


MY_Form_Validation w/ spam and CSRF protection - El Forum - 06-07-2010

[eluser]steelaz[/eluser]
Subscribed to this thread Smile Interested to hear what others think about this.


MY_Form_Validation w/ spam and CSRF protection - El Forum - 06-07-2010

[eluser]Buso[/eluser]
Me too, though I don't fully understand the hack yet

I understood the example from wikipedia, but that's it Tongue


MY_Form_Validation w/ spam and CSRF protection - El Forum - 06-08-2010

[eluser]n0xie[/eluser]
The first thing to acknowledge is that in my experience, most people do destructive things often via GET. This is inherently wrong but you should emphasize this: never do anything destructive via GET, always use POST. I would like to make this point clear since your 'library' only deals with POST data. Your site would still be easily exploitable if you had url's like http://domain.tld/user/delete/12345 which would delete user 12345. Always keep this in mind when talking about CSRF: most people don't know how it works and assume a 'library' like this will magically protect their site against any form of CSRF attack.

Code:
md5('nonce' . $this->CI->input->ip_address() . microtime());
This has way too low entropy to be effective. If I know what my target's IP is (which I can read with javascript) and I know this is the algorithm used to generate the nonce (which would be pretty obvious if it was an open source CI project), I can easily generate a matching nonce since microtime returns the current timestamp. I just have to generate every timestamp for the next minute (since the IP doesn't change) and one of those will most likely generate a match especially since the field you use always has the name 'nonce'. Basically this gives you about 60 different nonces per minute (1 for each second) which is way too low. Any modern computer takes less than a second to calculate these 60 MD5 hashes.

If you want an effective CSRF protection take a look at the example Controller of Ion Auth where I added a simple nonce implementation in the deactivate method.


MY_Form_Validation w/ spam and CSRF protection - El Forum - 06-08-2010

[eluser]erik.brannstrom[/eluser]
[quote author="n0xie" date="1276006650"]The first thing to acknowledge is that in my experience, most people do destructive things often via GET. This is inherently wrong but you should emphasize this: never do anything destructive via GET, always use POST. I would like to make this point clear since your 'library' only deals with POST data. Your site would still be easily exploitable if you had url's like http://domain.tld/user/delete/12345 which would delete user 12345. Always keep this in mind when talking about CSRF: most people don't know how it works and assume a 'library' like this will magically protect their site against any form of CSRF attack. [/quote]

I assumed anyone looking into using this extension would know that form validation works only on POST requests, but you are of course right.

[quote author="n0xie" date="1276006650"]This has way too low entropy to be effective. If I know what my target's IP is (which I can read with javascript) and I know this is the algorithm used to generate the nonce (which would be pretty obvious if it was an open source CI project), I can easily generate a matching nonce since microtime returns the current timestamp. I just have to generate every timestamp for the next minute (since the IP doesn't change) and one of those will most likely generate a match especially since the field you use always has the name 'nonce'. Basically this gives you about 60 different nonces per minute (1 for each second) which is way too low. Any modern computer takes less than a second to calculate these 60 MD5 hashes.[/quote]

Well, you are sort of right. I agree the entropy is too low and should include a more random element. Now correct me if I'm wrong, but microtime() does not only return the current timestamp as seconds since Jan 1st 1970, but also the microseconds (too be fair, it requires OS support for this, but I assume that's widespread). This means that for each second there are one million discrete time steps, which means for a full minute one would have to generate 60 million values.

Thanks for your input!


MY_Form_Validation w/ spam and CSRF protection - El Forum - 06-08-2010

[eluser]WanWizard[/eluser]
@n0xie:

If you also make the form field name random, how do you figure out which of the elements in the POST contains your nonce? Do you simply check the existence of the generated name (and if it exists, check the nonce)?

One of the issues I had with a simple key=>value session variable for the nonce was that a user can, within a session, have several screens open, all with forms. So you need to be able to track multiple issued nonces at once. I also use the nonce protection to protect against double posting (p.e. back button usage) by storing used nonces separately, with an expiry timestamp. If a form is posted with an invalid nonce, but the nonce exists in the used-list, I can issue an appropriate error message.

My template library automatically inserts nonce's in forms, and I've extended the form validation library so the run() method checks and validates the nonce as well. This way every form is automatically protected, and the developer doesn't have to worry about dealing with CSRF protection.


MY_Form_Validation w/ spam and CSRF protection - El Forum - 06-08-2010

[eluser]n0xie[/eluser]
[quote author="WanWizard" date="1276012351"]
If you also make the form field name random, how do you figure out which of the elements in the POST contains your nonce? Do you simply check the existence of the generated name (and if it exists, check the nonce)?[/quote]
Exactly.


MY_Form_Validation w/ spam and CSRF protection - El Forum - 06-08-2010

[eluser]WanWizard[/eluser]
Hmmm....

Have to think about how to incorporate this in my form validation extension and how that add this to the session (have to be a multi-dimensional array, as I'm already using an array for nonce=>timestamp pairs. Since I have multiple nonces active at any given time, it also means looping over them.

Not the most elegant of solutions...


MY_Form_Validation w/ spam and CSRF protection - El Forum - 07-09-2010

[eluser]mighty_falcon[/eluser]
Has anyone tested the new version Erik posted on his blog?

I am having issue setting the nonce in the form_helper...

Code:
$hidden['nonce'] = set_value('nonce', $value);
does not seem to be setting the value. I know from previous experience with the form_validation that set_value does not work unless you set a rule for that field, and in this case the rule is set...

Any ideas?


MY_Form_Validation w/ spam and CSRF protection - El Forum - 07-10-2010

[eluser]erik.brannstrom[/eluser]
Doesn't it get set the first time you load the form, or is it only after a POST it doesn't get reset? I don't really know what it could be, but perhaps if you could post a bit more of your code as well.

Are you using it out of the box or have you modified it in anyway, 'cause it's working for me?