Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP Verification Codes CAPTCHA

I run a game website so I have many users logged in and they can do certain things once every two minutes.

I have a CAPTCHA system in places, and for some things it will always ask for a code, and for other things, it will ask once every 10 minutes.

I have had some players use the auto submit feature on Opera, and my CAPTCHA system does stop them.

My question is, how can I minimise the amount of times I am asking for a code, but still stop people using this auto-submit?

like image 534
Juddling Avatar asked Apr 08 '10 12:04

Juddling


People also ask

How can I use CAPTCHA code in PHP?

In this PHP class, the getCaptchaCode() creates a 6 digit token. It is to display a random key in the captcha layer. I used PHP random_bytes(64) to get the random key. I used a PHP session to store the captcha and validate it with the user data.

How do I generate a CAPTCHA code?

To generate a unique CAPTCHA every time, a random number is generated using rand() function (rand()%62) which generates a random number between 0 to 61 and the generated random number is taken as index to the character array chrs[] thus generates a new character of captcha[] and this loop runs n (length of CAPTCHA) ...


2 Answers

If I understand correctly this task doesn't require a captcha. I assume You want to see if the user did click himself, sitting in front of his PC.

new idea

Put multiple image submits on Your form:

<input type="image" name="send1" src="buttons.php?i=1" />
...
<input type="image" name="send8" src="buttons.php?i=8" />

when generating a form get a random number between 1 and 8 and save it in $_SESSION['submitnumber']. create two same size images - one empty filled with Your default background in form, the other looking like a submit button. create buttons.php that will output images with this code:

header("Content-Type: image/jpeg");
flush();
readfile($filename);

and return empty image if the $_GET[i]!=$_SESSION['submitnumber'] else return the submit image.

Accept the form if the correct imagesubmit was clicked (the browser will send You coords like send1X when user clicks the button)

It's a type of captcha, but people won't know ;)

old idea

You need two things:

1 Generate tokens for forms that are quite unique.

put <input type="hidden" name="timertoken" value="someweirdstring" /> and generate the "someweirdstring" to be a md5 hash of some (username and time)-dependant thing. I can elaborate on this, but this is a basic form token for safety and CSRF attacks blocking. The token is verified after posting.

example:

This is not a typical implementation of the token mechanism, but it will be enough.

$token=generatesomerandomtext();
$_SESSION['token']=$token; 

//... somewhere later when outputing forms:    
echo '<input type="hidden" name="token" value="'.$token.'" />';

//and when it comes back:
if($_POST['token']==$_SESSION['token']) {
   //it's ok
   }

and that's all You need. this simple example creates a unique token for every page and puts in forms. It's not time dependant and doesnt use md5, but stores the token in session. To automatically send a form that would be accepted the person has to use the form You generated or copy the token.

The real form token example would be more like this: $token=md5($username.'some secret text'.$date.$timeRoundedTo10Minutes);

//... somewhere later when outputing forms:    
echo '<input type="hidden" name="token" value="'.$token.'" />';

//and when it comes back:
if(
 ($_POST['token']==md5($username.'some secret text'.$date.$timeRoundedTo10Minutes)) ||
 ($_POST['token']==md5($username.'some secret text'.$date.$timeRoundedTo10Minutes-10minutes)) ) {
   //it's ok
   }

Why usernames? Because it removes the possibility to use one user's tokens to hack another user Why secret text (called 'salt')? Because somebody could stick together other user's name with time and do md5, but without guessing the salt he can't. Why the two comparisons? Because if now is 22:44:59 - the token is generated with 22:40 and if user sends it it's 22:45:30 so it gets rounded to 22:50 and it matches the token only if You take it back 10 minutes.

That's it for a basic example. For reference see this question.

2 Change Your submit button into <input type="image" ... as it posts the x and y coordinates of where the button was clicked. I have no idea who came up with this in specification, but it's the first time it can be used! :)

Now to see if the user clicked himself You just have to see if the coordinates are present (classic submiting won't send them) and to block simple hacking this You can also remember the last x and y in player's session and compare. It's much harder to hack it to send different coords each time.

The form tokens are there to prevent users from preparing a copy of Your form with random fields that would simulate the click coordinates. If the token changes each time it's hard to override form fields.

This is still hackable by userscript functionality, but it's much harder. And If You added a captcha once in an hour nobody would bother writing scripts that would help only for an hour and break after that (and require some effort and knowledge).

like image 117
naugtur Avatar answered Oct 18 '22 02:10

naugtur


Depending on the data you receive you can gather evidents that the caller is a user. Only ask for the CAPTCHA, if the caller seems to be a bot.

Evidents can be:

  • the user agent (not reliable, because Opera can fake this)
  • the interval the submit is triggered (the more exact the call hits the i.e. every 2 minutes the more likely it is a bot)
  • if your data allows checking for returning patterns it can be an evident, too
  • ...
like image 25
Hinek Avatar answered Oct 18 '22 02:10

Hinek