PHP Security – Are Sessions Secure for Captcha on Failed Login?

captchaPHPSecurity

I don't like writing open-ended questions but I have a quick security question. I have a PHP login script that shows a CAPTCHA on the third failed login attempts. The way I'm counting failed logins is by using session data. Is this secure? Is there a better way to do this? Maybe store the IP in a database table? I'm not really sure how bots and programs that try to use word list actually work.

Thanks

Best Answer

Every time you call session_start() php either creates or reads (if already exists) a cookie named PHPSESSID. This cookie stores a unique identifier for the browser session, its php's way of telling one session from the other. A bot can easily refresh this cookie with a new identifier on each request and mislead php into recognizing each failed login as a first time try, so no its not secure.

Exactly the same can be done with the IP, all $_SERVER variables can be manipulated. A clever bot can send different IP on each request. So, if you are battling a malicious bot, requests are unidentifiable.

Two solutions, an easy one and a paranoid one:

Easy solution

Add CAPTCHA by default on your login page.

Paranoid solution

Create a table in your database to log the timestamp of each and every request, regardless of IP or any other identifier. Whenever you get a request to your login page decide if you are going to show the CAPTCHA based on the elapsed time from the immediately previous request. Make sure to have a cron job (or manually) delete old rows from the table, so it won't get very big very soon.

You will have to chose a sane interval, based on the traffic of your site. Make sure the interval is configurable, cause hopefully your traffic will rise over time. The success or failure of the solution depends on choosing a balanced interval.

For extra paranoid points log and compare microtime().

Ordinarily a login script does not need a CAPTCHA, as the strain on the database to check two indexed fields against a table of a few thousand users shouldn't be much. But if your site does have more than a few thousand users, or you have valid reasons to suspect that a bot is targeting you the paranoid solution should be sufficient.

Update:

As Dean notes, faking the IP is not trivial, that's what I meant by a clever bot, didn't really thought it was valuable to elaborate further. There is a related question at serverfault.stackexchange with a detailed accepted answer on the matter. (Related articles at Symantec and Linux Security)

Of course it would be somewhat secure to go with an IP based solution, especially if your site is not likely to be an intended target (but how can you know that?). Extra things you have to factor in an IP based solution would be dynamic IPs and how to distinguish between firewalled users.

Personally, I always go with the paranoid approach, and never absolutely trust $_SESSION, $_COOKIE and $_SERVER variables.

Related Topic