Bad Information
I get really frustrated when I see bad information given out. On any topic, it doesn’t really matter, if I know its false, I hate to hear it get perpetuated. Today has been no different, except it has really torqued me because the subject is information security.
I read in another blog that the best way to prevent POST requests to your site from originating elsewhere is to review the value stored in $_SERVER['HTTP_REFERER'], and make sure that it matches the domain of the site itself before processing the POST request. Yes folks, its that simple. Or is it?
The last time I checked the PHP Language Documentation I recall it saying that this value was not to be trusted. In fact it still says just this, here is the relevant text from the PHP web-site:
The address of the page (if any) which referred the user agent to the current page. This is set by the user agent. Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. In short, it cannot really be trusted.
Hmm… so it seems that this is a bad idea all around. All I would need to do as an attacker would be to crank out a script using CURL, and set the CURLOPT_REFERER option to be my target’s web-site, and BANG, I’m golden, happily cranking away at POST requests to his contact book form and filling it with viagra spam.
Well, if this is a bad idea, what is a good way to prevent this?
Well, my first thought is to take advantage of PHP sessions to do this.
In the source form file, initiate a session, and store a secret value to the session data store. In the processing script, check this value for validity, clear it out (to prevent simply hijacking the session to send repeated posts), and then process the input only if valid. Further more, I would add abuse checking, to prevent repeated attempts at submitting the form. A simple counter variable, again stored in the session data store, or an array of time-stamps, with a threshold check to prevent more than X submissions in Y seconds for a given session, before the IP address is added to a block list and denied access to the processing form logic at all.
Now this won’t prevent a determined attacker, nor will it help you if someone just decides to use their pet bot-net to flood the site with POST requests simply to create a Denial of Service situation. But it should put a crimp in the operations of your basic comment spammer who simply wants to sell the world on the benefits of cheap, questionable-quality, pharmaceuticals.
June 28th, 2008 at 20:40
Another interesting approach I’ve seen is to use Javascript to populate a verification field in your form with some pre-computed value that you can reproduce server-side.
This of course is a problem for users who don’t have Javascript, but really, who doesn’t have Javascript these days?
June 29th, 2008 at 17:37
JavaScript is definately an option, and one that I commonly employ on client websites to prevent spam submissions. Though rather than use it as you have described I normally use it to re-write the submission form’s action attribute, from a bogus target to the normal one. This will foil just about all of the normal comment form spammers out there. The bots cant parse javascript and the sweatshops don’t normally to minimize bandwidth use. That combined with a session based approach will eliminate virtually all the spam comments currently. Though I imagine that it will only be a matter of time before we start seeing spam bots that can and will take the time to parse javascript.
July 2nd, 2008 at 08:32
Using the same Curl you “blame” that can be used to change REFERER , you can simulate session (capture cookie and use it). Your solution it’s not better than using REFERER variable: both are useless if someone really wants to get in. I found no solution for this issue, that’s why I read your post ;) - and still I have no solution.
July 3rd, 2008 at 05:16
@Dragos,
Yes session hijacking is still an issue, but so long as you destroy the session after processing, it makes the spammer’s job more difficult, they will have to repeatedly visit the initial page to generate a new valid session before hitting the processing page. Checking the submission count and rate will make it even harder. Getting around this version will be significantly more difficult that one that simply looks at the referrer string, which is much more trivial to bypass than stealing a cookie.
August 25th, 2008 at 17:36
Dragos is right, but the truth is that there’s no risk in someone using cURL instead of a regular browser, as long as you enforce good rules. Any good security practice considers the fact that a user can manipulate anything in the request.
The practice you describe is for preventing CSRF:
http://shiflett.org/articles/cross-site-request-forgeries
I hope this helps.