Validating reCaptcha with jQuery and AJAX
This example is well out of date. Please don’t use it as is until I have a chance to update it.
I recently did some work for one of my clients that involved securing some simple web forms. These forms were to request literature or request a call back, simple stuff. Incidentally they were getting hammered with spam. The clients didn’t seem to care for this so they asked me to stop it.
My first move was to setup some sort of Captcha. I settled on reCaptcha and got to work on implementing it. I’d be on a bit of a jQuery kick lately so I wanted to see if I could validate the Captcha fields dynamically and only submit the form if they matched. It turned out that this was much easier than I’d thought.
To make this work, we’ll be using the following files:
- recaptcha.php – The page that holds our form
- ajax.recaptcha.php – The file that handles the ajax requests and outputs the result
Prerequisites
- The first thing we’ll do is setup our form. I’m going to assume you already have your form in place and that you are merely trying to secure it.
- Next, you’ll want to download the newest version of jQuery. You can put this file wherever you normally store your js files and include this in your page.
- Now it’s time to get yourself a reCaptcha keyset. A keyset is nothing more than a public and private key that allows you to use the reCaptcha service. It’s free. Head on over to http://recaptcha.net and click “Get reCaptcha” and fill out the necessary fields. Under domain, either fill out your site’s domain or set this up as a global key if you plan on using reCaptcha on multiple domains. Make a note of your public and private keys.
Now it’s time to put this all together. First we have to get our form to display our reCaptcha challenge field so the user can actually submit the form. My site uses PHP so I’ve downloaded the reCaptcha PHP Library and stored it on my server. At the top of my page, I have included this PHP file and setup my public and private keys. On this page, you really only need the public key, but I went ahead and included both so I don’t lose one of them. Here is what the top of my recaptcha.php looks like (with my keys blanked out):
recaptcha.php
require_once('/inc/recaptchalib.php'); $publickey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // you got this from the signup page $privatekey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX"; |
Next, you will include this in your page where you want the reCaptcha box to appear in the form:
recaptcha.php
echo recaptcha_get_html($publickey); |
Next, we need to write our function that handles the dynamic/AJAX reCaptcha validation for us. I’ve done that already and you can see it below:
recaptcha.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | function validateCaptcha() { challengeField = $("input#recaptcha_challenge_field").val(); responseField = $("input#recaptcha_response_field").val(); //alert(challengeField); //alert(responseField); //return false; var html = $.ajax({ type: "POST", url: "ajax.recaptcha.php", data: "recaptcha_challenge_field=" + challengeField + "&recaptcha_response_field=" + responseField, async: false }).responseText; if(html == "success") { $("#captchaStatus").html(" "); // Uncomment the following line in your application return true; } else { $("#captchaStatus").html("Your captcha is incorrect. Please try again"); Recaptcha.reload(); return false; } } |
The above function grabs the reCaptcha data, submits it via a POST request to a file called ajax.recaptcha.php on our server, and waits for the repsonse. When it gets the response it either updates the status telling your user that the captcha didn’t match and then it reloads a new captcha for them, or it submits the form. The running demo code is slightly different to prevent the form from actually being submitted.
The last step to this part is to make sure your form runs this function when the user clicks that submit button. To do this, update the form’s opening tag and add an onsubmit event like this:
recaptcha.php
form name="loginform" id="loginform" action="#" method="post" onSubmit="return validateCaptcha()" |
You’ll notice that we return true or false from the validateCaptcha() function. This controls if the form is submitted or not and is important for making this work.
Our final step in this process is to build the ajax.recaptcha.php file that we mentioned earlier to handle the requests. I’ve done this already and here is the final product (again with my keys blanked out):
ajax.recaptcha.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | require_once('/inc/recaptchalib.php'); $publickey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // you got this from the signup page $privatekey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX"; $resp = recaptcha_check_answer ($privatekey, $_SERVER["REMOTE_ADDR"], $_POST["recaptcha_challenge_field"], $_POST["recaptcha_response_field"]); if ($resp->is_valid) { ?>success< ? } else { die ("The reCAPTCHA wasn't entered correctly. Go back and try it again." . "(reCAPTCHA said: " . $resp->error . ")"); } |
This file outputs only the word “success” if the captcha matches and a message and the response from reCaptchta if it fails. This is important because we are looking for the word success in our validateCaptcha() function.
You can see the functioning demo for this or download a zip file of the files used in the demo including full PHP source code.
15 Dec 2008 04:12 pm Chris 1,018 comments
Hi,
thank you for posting this… it has proven to be very insightful.
Unfortunatley making sync calls from firefox just freezes it up.. any ideas on how to get around it?
works fine in IE!
Hyder,
I dropped you an email, but if you could provide me a link to your form I’d be glad to look at it.
Hi,
I tried the same example on a different machine(IIS 6.0) and it all worked fine so I thought it must be local to my machine (IIS 7 Vista x64). I upgraded my firefox to the latest version (3.x) and it all works fine
Thanks for your email
Regards,
Hyder
Just wanted to note, I couldn’t get this to work using & for the ajax code, I could only get & to work.
that is &(nospace)amp; vs &
Thanks for posting.
I’ve adapted the php code for ASP.NET and C#:
Recaptcha.RecaptchaValidator v = new Recaptcha.RecaptchaValidator();
v.RemoteIP = Request.ServerVariables[“REMOTE_ADDR”];
v.PrivateKey = “XXXXXXXXXXXXXXXXXXXXXXXXXX”;
v.Challenge = Request[“recaptcha_challenge_field”];
v.Response = Request[“recaptcha_response_field”];
Recaptcha.RecaptchaResponse r = v.Validate();
Response.Write(r.IsValid);
It returns True or False in the html.
Nice tutorial! Thank you.
jQuery is all about unobtrusive javascript as far as im concerned. So shouldn’t the onsubmit be inside the javascript?
Like so:
$(function(){
function validateCaptcha(){ … };
$(“form”).submit(function(){
return validateCaptcha();
});
});
This way you don’t have to meddle with anything in the HTML part of the code. Just a small quirk just thought I’d point it out to others.
Good work!!
One little problem which is probably not caused by your solution:
typing the first word of the challenge returns success. No need to type both words. Does anyone else has this problem, too?
Hans.
Great work..
I’m also facing the same problem as Hans van Domselaar..
typing the first word of the challenge returns success..
If anybody have found the solution then please post it..
Thanks,
Mihir
hey there,
thanks for posting this, definitely a necessary part to using the re-captcha plugin. however i’m running into a problem with the this version of the captcha. it refreshes great if the captcha words are entered in wrong, but if they are correct it still supplies an error message. I un-commented the return true value that it says to do in the javascript, but still no luck.
And I set it up with the regular (non ajax/js) PHP code and it worked fine, so it’s not an issue with the public/private key values.
Any idea why this isn’t working?
Thanks!
@BeeDev You should be able to shuffle the JS around wherever you like and still have it work.
@Hans/Mihir I’m going to look at this and see if I can tell what is causing the issue.
@KM I’ll look at that too.
I’m having the same problem as KM. No matter what, it thinks that the recaptcha is incorrect. Any thoughts?
Sorry for double commenting but I’ve narrowed the issue down to the javascript code. If I direct the form to ajax.recaptcha.php and remove the onclick then the recaptcha works. It displays the “success” message if recaptcha is typed in correctly and it displays my error message if it is not. So, it seems that the problem is somewhere in the validateCaptcha javascript function.
function validateCaptcha()
OK, solved my problem. It only works if you use “&” instead of “&” in the recaptch.php file.
Just as Brandon said above, thats &(nospace)amp; doesn’t work, it needs to just be “&”. Maybe both ways work depending on your web host’s configuration, but again only “&” makes the code work for me.
@hans/mihir – it’s supposed to work that way, the first word is an actual word, the second word is one that has not been verified yet, but by typing it in, you are helping to verify it.
I am working on implementing this solution now, as I need a way to display multiple captchas on a page.
@Chris I wasn’t clear on this until recently.
Anyone using this should keep an eye on possible changes since Google has now acquired reCaptcha. I’m going to refresh this every few months or so just to make sure it still works.
Hi,
I’m not sure about this, but wouldn’t this require to validate the reCaptcha twice..
If some kind of attacker would like to avoid the captcha, the only thing he would have to do is create his own post data with a name field and send it to the script… If then there is no revalidation or any kind of saving mechanism for the ajax results, the data would just go through.
Or am I missing something there?
@Dominik
If you don’t properly secure your form yes. This tutorial doesn’t go into detail on methods you should be using to ensure that form data can only be sent from pages you’ve created. It merely touches on a way to validate captcha without having to handle prefilling form data for your users by using an ajax call.
Great article, but … it seems that recaptcha_check_answer() will only return valid once – if I call it a second time with the same data, it returns is_valid = false.
This makes client-side then server-side validation impossible!
Has reCaptcha changed something? Or am I missing something?
I think I was missing something … are you doing any server-side validation? How does the validation work if JavaScript is off?
Thanks, Chris
Using the above, I get the correct response, but my form doesn’t submit.
See: http://stackoverflow.com/questions/1681061/jquery-form-validation-problem
For more details.
The fix from Stack Overflow (link above). Was to make sure all other characters were stripped in JS:
if (html.replace(/^\s+|\s+$/, ”) == “success”)
Chris did you manage to get the server validation working after the client side validation, i have both working but not together, any help would be appreciated.
I’m unsure what the problem is, its almost as if the values are removed after the call is made?
Thanks
Derek
Why use:
$(“input#recaptcha_challenge_field”).val();
$(“input#recaptcha_response_field”).val();
When reCapcha AJAX API exposes:
Recaptcha.get_challenge()
Recaptcha.get_response()
?
Derek / Chris,
You can’t verify the same the same challenge/response more than once.
I think the documentation kind of mentions it here (second to last paragraph under “reCAPTCHA AJAX API”):
http://recaptcha.net/apidocs/captcha/client.html
What I’m going to do is handle the form operation in the same AJAX call as the captcha verification. That way I only need to verify it once and there’s no way to bypass captcha by messing with the request.
You are a life saver. I had the same problem with using jquery validate and the remote call — I wanted the result to send back true or false and either reload the recaptcha or recognize that it was filled out correctly. That worked, but then the form wouldn’t submit. Used your tip to finish it off. The form is in action at http://www.ontaponline.com/register.
If anyone wants the full code just let me know and I can post it or email it.
Cheers.
I got the recaptcha thing to work .. but its not submitting the form ? it just says … Success. Submitting form.
how do i get it to actually submit the form ?
@Alex
When I wrote this, reCaptcha didn’t have their own exposed AJAX API methods so I had to use alternate methods. I have finally cleared enough off my table at work to redo this article with a current version of reCaptcha.
@Chris
will you be posting the article that works with a current version of reCaptcha and incorporates all the comments and stuff? thanks
@nesh I will indeed.
Hello
I see that you use ajax.recaptcha.php to validate if a captcha is correct and then if it is, it is submited
But when someone hacks the page, he can force it to just post it anyway.
So I would like a more secure solution, that the check is done on the server and when the check is successful the filled in form is send to the database or whatever has to happen
So everything including the filled in form and captcha is send to the server.
So far as I can see this is not 100% waterproof
Could you please update me on this, since I’m looking for a solid solution to integrate a captcha in a jquery modal dialog.
gr
Jan
Re: the issue with bypassing the reCaptcha if the checking is built into the front end rather than the form-processing script: you definitely do need to take extra steps to handle that.
Alex mentioned that he is going to handle the processing during the validation operation, so in a sense there is no form-processing script, at least not one that does the ‘real’ work.
This week I implemented a two-stage form, where we needed to verify the user’s humanity at both stages, but didn’t want to put them though two reCaptchas. I implemented this by setting a random temporary ‘password’ on the user’s customer record in the backend database once they had passed the first stage, and then incorporated that password into a hidden field in the second-stage form. Seeing that password come back with the submission of the second-stage form proved the user’s humanity without requiring any extra action on their part.
PS If anyone else is getting as frustrated as me by trying to do all this in a single ajax operation talking directly the the reCaptch API server, you are almost certainly going to be defeated by browser security practices, preventing your page from directly loading the response from the reCaptcha domain.
No doubt that is why Chris used a separate local php script to do the checking in the first place.
Heya – I’m a bit of a hack, and seem to be having the same issue as Bobby above – The validation works gret, but the form never gets submitted. What am I missing? Can you help?
I fully plan to figure out a better way to do all of this, but I just haven’t had the time lately.
Note that you need to save the captcha validation result in the session. If you just use JavaScript, you essentially just have JavaScript validation, which bots ignore anyway.
So you just made it harder for humans to submit the form, and did nothing for the bots that visit it.
In the page that validates the captcha:
if ($resp->is_valid) {
session_start();
echo ‘success’;
$_SESSION[‘captcha’] = 1;
}
Then on the PHP page that processes the form:
if (!$_SESSION[‘captcha’]) {
// someone tried to bypass the captcha. Don’t waste your resources
die;
}
@Bucabay
As I was reading through the comments from this post I thought of the exact same solution. If you check the reCAPTCHA using Ajax, simply set a session variable if the check succeeded.
Then when you go to do the server-side validation, you will know if the person is already validated; just check the same session variable.
Don’t forget to unset your session variable after performing your actions, or a bot master could pass the test once, then spam like crazy subsequently because he is still validated.
Thank you for posting this!
is there any working for I can see, there is one posted link in the comments is no longer using this method .
Regards
Thanks for this – with a few tweaks I was able to implement it directly into my site.
how to build public key for my site?
Thanks Chris, this tutorial is exactly what I need!
I got the same error as KM and Billy that I got the “incorrect” error message no matter what.
I fixed this issue by modifying the ajax.recaptcha.php file.
I change
if ($resp->is_valid) {
?>successis_valid) {
?>success<?php
}
and everything works perfectly now!
Thank you, i found this is very useful. For easy understanding giving the demo file to download will be appreciated.
i have downloaded the demo,
i gave my keys,included jquery, tested in local host, unfortunately it always shows same error “Your captcha is incorrect. Please try again”
can you help me?
thank you…
THANKS for this! After spending ages trying to do it myself, I resorted to googling a way to do it 😉
As others have said, you MUST change the & amp; to just & in the validateCaptcha data part of the request for it to work.
@hamid :
You need to generate the public and private keys for your domain here : https://www.google.com/recaptcha/admin/create
People! Don’t actually use this asis on your site – you cannot use ajax validation for recaptcha without a lot more code. All you need to do is turn off javascript and submit the form – which is exactly what spammer do. Because recaptcha will only return valid once you must create additional code. For example: have your ajax php page create a one use code, store in user session and also return it in your form. Then on form post, check if token is valid (then discard it to stop multi post) – if no token then you can check recaptcha normally.
for people having problems with it constantly failing (even when the acutal check is returning success) make sure you’re not sending any whitespace. just spent some time trying to figure this out. “success” != ” success” x_X
Hello, i’m trying to do an insert in database of the form, but seems i cant post values of fields if captcha is correct in ajax.recaptcha.php, can someone tell me how i can do it or what i need to change?
I have a problem I used your code and i did some little changes and now i doesnt matter if a type a correct code i get the same error message
i did this since I am using the validate plug in too
submitHandler: function validateCaptcha()
{
challengeField = $(“input#recaptcha_challenge_field”).val();
responseField = $(“input#recaptcha_response_field”).val();
var html = $.ajax({
type: “POST”,
url: “/captcha/ajax.recaptcha.php”,
data: “recaptcha_challenge_field=” + challengeField + “&recaptcha_response_field=” + responseField,
async: false
}).responseText;
if(html == “success”)
{
$(“#captchaStatus”).html(“Success. Submitting form.”);
return false;
// Uncomment the following line in your application
//return true;
}
else
{
$(“#captchaStatus”).html(“Your captcha is incorrect. Please try again”);
Recaptcha.reload();
return false;
}
}
any ideas, thanks in advance
is this customizable?
Hi everyone,
I m trying a contact page form with ajax validation in php and using this way to add recaptcha. Everything is so far so good except recaptcha validation. Whether I type right or wrong even empty form submits and sends email. I get right message if I type right “Success. Submitting form” and form submits. I get right message if I type wrong or empty “Your captcha is incorrect. Please try again”.
How to validate if blank or wrong captcha just do nothing?
Thank you
Good, but if i have a lot of field and I enter an incorrect value in the captcha the fields are empty