[SOLVED]Stop other sites POSTing to my forms, random token?

Discussions of secure PHP coding. Security in software is important, so don't be afraid to ask. And when answering: be anal. Nitpick. No security vulnerability is too small.

Moderator: General Moderators

Post Reply
User avatar
batfastad
Forum Contributor
Posts: 433
Joined: Tue Mar 30, 2004 4:24 am
Location: London, UK

[SOLVED]Stop other sites POSTing to my forms, random token?

Post by batfastad »

Hi everyone

I'm trying to work out the best way to stop other scripts/websites POSTing data to my forms.

I just tried to implement a random token as a hidden input in the form and saved to a session.
If the user opens a new window and goes and visits a different form on the site in the meantime then that generates a new random token and overwrites the random token stored in the session... meaning the original form is now invalid and the user gets an error.

Is there a way round this?

I thought about maybe storing 5 or so random tokens in the session in an array, then check the random token exists in the array of last 5.
Would that be a decent way of coping with that problem?

Or is there another way I'm missing out on?

The form random is an md5 hash because its fast yet still pretty unlikely to be guessed by a spammer. I realise md5 is not considered strong for crypto use now but I'm thinking its good enough for a random form token.

Cheers, B
Last edited by batfastad on Wed Nov 25, 2009 8:37 am, edited 1 time in total.
User avatar
timWebUK
Forum Contributor
Posts: 239
Joined: Thu Oct 29, 2009 6:48 am
Location: UK

Re: Stop other sites POSTing to my forms, random token?

Post by timWebUK »

I was just about to post a similar question. I'm glad I'm not the only one working on this.

However, I downloaded the reCAPTCHA PHP code to add that to my registration form, this comes equipped with a public and private key. So unless the spammer could get the private key, then they cannot use my PHP processing file that gets the POST data unless they use my form.

Maybe this could help you too?
User avatar
kaisellgren
DevNet Resident
Posts: 1675
Joined: Sat Jan 07, 2006 5:52 am
Location: Lahti, Finland.

Re: Stop other sites POSTing to my forms, random token?

Post by kaisellgren »

Is this about spamming or CSRF?

Note that you can generate per-form tokens or per-page tokens. For example, if the user accesses feedback.php, generate a token and place it in $_SESSION['feedback_token']. Every page (or even every form) could have its own token.
User avatar
batfastad
Forum Contributor
Posts: 433
Joined: Tue Mar 30, 2004 4:24 am
Location: London, UK

Re: Stop other sites POSTing to my forms, random token?

Post by batfastad »

Yeah CSRF mainly
I already have a captcha on our main contact page to try to stop automated spammers

I did change it to store the last 5 form_rand tokens, but actually making a multi-dimensional array in the session with PHP_SELF as the key would make much more sense!
Thanks for the suggestion Kai, that's what I will do :)

Cheers, B
User avatar
timWebUK
Forum Contributor
Posts: 239
Joined: Thu Oct 29, 2009 6:48 am
Location: UK

Re: [SOLVED]Stop other sites POSTing to my forms, random token?

Post by timWebUK »

Just a quick question... when you generate your random token, what are you generating it with? I understand how you pass the token from the form using a session, but what do you compare it with to check that the token is valid and your form has been used?

For example... form.php, the user fills this out, a session token is generated, when the user presses submit, this is then passed to your processing.php file, then what am I comparing this randomly generated token to? Probably a stupid question but can't get my head around it!
User avatar
batfastad
Forum Contributor
Posts: 433
Joined: Tue Mar 30, 2004 4:24 am
Location: London, UK

Re: [SOLVED]Stop other sites POSTing to my forms, random token?

Post by batfastad »

Well when someone loads up the form page, a random token is generated
This is stored in a session variable
And also hard-coded into a hidden form field

Then when the user presses the button you do a quick check to make sure that the random stored in the session and the random POSTed from the hidden form input, match!

Hope that clears it up
Cheers, B
User avatar
timWebUK
Forum Contributor
Posts: 239
Joined: Thu Oct 29, 2009 6:48 am
Location: UK

Re: [SOLVED]Stop other sites POSTing to my forms, random token?

Post by timWebUK »

Ah great, didn't think of it like that! Thanks.
User avatar
timWebUK
Forum Contributor
Posts: 239
Joined: Thu Oct 29, 2009 6:48 am
Location: UK

Re: [SOLVED]Stop other sites POSTing to my forms, random token?

Post by timWebUK »

Another quick question, if someone presses back in the browser, obviously the hard-coded token and session token go out of sync. Is there a way round this? I know I could put in a refresh header, but surely that would loop indefinitely? Or is it not a problem to worry about?
User avatar
batfastad
Forum Contributor
Posts: 433
Joined: Tue Mar 30, 2004 4:24 am
Location: London, UK

Re: [SOLVED]Stop other sites POSTing to my forms, random token?

Post by batfastad »

If someone presses back in the browser, then hopefully the random gets regenerated... updating the session and the value within the form!
So they should both still match! That's what I've found anyway :)
I'm not doing anything clever with cache/no cache headers

The only concern I had was if someone opened multiple tabs on my site and navigated to different forms.
But per Kai's solution above, I store a token per form so it only becomes a problem if someone opens the same form twice (unlikely)
If that does become a problem for me then I will change it to store an array of the last 5 randoms on a per-form basis which should stop that happening

Cheers, B
User avatar
timWebUK
Forum Contributor
Posts: 239
Joined: Thu Oct 29, 2009 6:48 am
Location: UK

Re: [SOLVED]Stop other sites POSTing to my forms, random token?

Post by timWebUK »

What's happening for me is (in Google Chrome, I have also echo'd the values of the token and session token to confirm this). But if I view the source to check the hard coded token, when I press submit on the form, the hard coded token is now different... is this due to the way Chrome view's the source of webpages... I can't imagine it is.

Also, when i press back on the browser, to the form before the form redirects, they definitely fall out of sync. Do you think I should use no cache headers?

Do you not experience this at all?
User avatar
kaisellgren
DevNet Resident
Posts: 1675
Joined: Sat Jan 07, 2006 5:52 am
Location: Lahti, Finland.

Re: [SOLVED]Stop other sites POSTing to my forms, random token?

Post by kaisellgren »

If the browser caches the page and supplies the old cached version of it when pressing the back button, then it surely breaks the CSRF check.

One thing you can do is to tell the browser not to cache the page.

On some JavaScript based large websites like Facebook, some developers use AJAX to request a .php file to generate the token and them place it on the form dynamically. Therefore, on each page load the AJAX call will make it sure the token is fresh.
User avatar
timWebUK
Forum Contributor
Posts: 239
Joined: Thu Oct 29, 2009 6:48 am
Location: UK

Re: [SOLVED]Stop other sites POSTing to my forms, random token?

Post by timWebUK »

I will try this. However, wouldn't it be an issue if Javascript was disabled within the browser, then a token would not be generated and it would fail.

EDIT: Also, once I've generated the random token and put it into the form dynamically, how can I get it into the session?

EDIT: Ok scratch that, got it working. IT's quite nice because if you view the source on the form you don't get to see the authentication token at all.

Thanks!
User avatar
kaisellgren
DevNet Resident
Posts: 1675
Joined: Sat Jan 07, 2006 5:52 am
Location: Lahti, Finland.

Re: [SOLVED]Stop other sites POSTing to my forms, random token?

Post by kaisellgren »

Sites like Facebook rely on JavaScript. Most of the features are inaccessible or not working well without JavaScript. I don't think it's so bad to require the user to enable JavaScript these days. It's your choice, though.
Post Reply