Episode 15: Using a CAPTCHA in your Google App Engine Application
December 2017: Please note that this post has not been updated for a while and there could be differences in terms of commands, screenshots and problems in running the code.
Welcome to Episode 15. In this episode, we shall cover how to incorporate a CAPTCHA in your application. The CAPTCHA solution that I will be demonstrating over here is the ReCAPTCHA project found here. To quote from its Wikipedia entry, a CAPTCHA is a type of challenge-response test used in computing to ensure that the response is not generated by the computer. Usually, one sees one or two words shown to us that we need to enter and they need to match before our request submission is accepted by the server.
See it in Action
Let us first see the application that we shall be developing in its final form. The main screen is a dummy form that accepts one field and displays the CAPTCHA to the user as shown below:
If the CAPTCHA response is entered correctly and the submit button is clicked, the response is sent to the server. The server side validates the CAPTCHA challenge-response and will display an “all is well” message as shown below:
If the CAPTCHA response is not entered correctly, the server side will display an “all is not well” message as shown below:
ReCAPTCHA Project
We shall be using the ReCAPTCHAProject present at http://recaptcha.net/. The ReCAPTCHAproject is comprehensive and provides support for a variety of server side platforms, hence I have gone with it. I do not have a particular preference for it, except that most people recommended this to me and hence I decided to try it out. I was able to integrate it easily and quickly into a recent App Engine application that is currently live, so I can vouch for its ease of integration and which is what I shall demonstrate in this experiment.
To get started with ReCAPTCHA, we need to do 2 things:
1. Get your private/public keys for the site name hat your application will be running on.
Follow these steps:
- First get yourself a ReCAPTCHAaccount. Go to http://recaptcha.net/whyrecaptcha.html and click on the Sign up Now! button.
- This will bring up a login form, but you click on the “New to reCaptcha? Sign up” link. Here you can register by giving a username/password/email . Click on the Sign up now button.
- On successful registration, you will signed in automatically and led to a Create a reCAPTCHA key page. Here you need to enter the site name that you will be using ReCAPTCHAon. Remember you can get ReCAPTCHAkeys for more than 1 site and you can manage it all from your account itself. For e.g. you can get a key for localhost since that will be what we need to test on first before deploying to the Google App Engine cloud. And then you will atleast need one based on the Application ID of your Google App Engine application. So for e.g. if my application ID is gaejexperiments, then my full site url is http://gaejexperiments.appspot.com. So you will need to enter gaejexperiments.appspot.com in the Domain form field.
- Click on Create Key. For e.g. shown below is the series of screens that I got when I wanted keys for localhost. You will need to do the same if you wish to test the code first on your local system i.e. localhost.
Then when you click Create Key, you will be presented the Public Key and Private Key as shown below:
Please note down the Public and Private Key since you will need to use them in your application. The usage is straightforward and mentioned on the screen and I will be repeat it here:
- Use the Public Key in your HTML page (Javascript) to communicate with the ReCAPTCHA server to get the challenge (image).
- Use the Private Key in your server side Java code that will be used to communicate with the Server to verify the challenge + response submitted by the form in the above step.
2. Download the JAR file that we shall be using at the Server side to verify the CAPTCHA challenge and response.
To do the server side validation, you need to download a JAR file that is available from the following url : http://code.google.com/p/recaptcha/downloads/list?q=label:java-Latest. Go to the URL and you shall be presented with a screen as shown below:
The JAR file is required and it encapsulates all communication between our application and the ReCAPTCHA Servers.
Download the zip file, expand it in an appropriate folder and you will find the recaptcha4j-0.0.7.jar present in that. We will need it later on to be referenced in your App Engine Eclipse Project.
Developing our Application
The first thing to do is to create a New Google Web Application Project. Follow these steps:
1. Either click on File –> New –> Other or press Ctrl-N to create a new project. Select Google and then Web Application project. Alternately you could also click on the New Web Application Project Toolbar icon as part of the Google Eclipse plugin.
2. In the New Web Application Project dialog, deselect the Use Google Web Toolkit and give a name to your project. I have named mine GAEJExperiments. I suggest you go with the same name so that things are consistent with the rest of the article, but I leave that to you. In case you are following the series, you could simply use the same project and skip all these steps altogether. You can go straight to the Servlet Development section.
3. Click on Finish.
This will generate the project and also create a sample Hello World Servlet for you. But we will be writing our own Servlet.
Add the recaptcha4j-0.0.7.jar file to your Project classpath
The recaptcha4j-0.0.7.jar file that we downloaded needs to be added to the runtime and compile time CLASSPATH of your App Engine Eclipse Project. Follow these steps:
a) Copy recaptcha4j-0.0.7.jar to the WEB-INFlib folder of your project. This folder is present in the war sub folder of your main project structure.
b) Go to Project properties → Java Build Path and reference the JAR file (recaptcha4j-0.0.7.jar) in the Java Build Path of your application as shown below:
The Front end HTML form [captcha.html]
<html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>" lang="en" xml:lang="en">
<head>
<title>ReCaptcha Integration</title>
<script type="text/javascript" src="<a href="http://api.recaptcha.net/js/recaptcha_ajax.js%22%3E%3C/script">http://api.recaptcha.net/js/recaptcha_ajax.js"></script</a>>
<script type="text/javascript">
function PreloadCaptcha() {
showRecaptcha();
}function showRecaptcha() {
Recaptcha.create("YOUR_PUBLIC_KEY", "dynamic_recaptcha_1", {
theme: "white",
callback: Recaptcha.focus_response_field
});
}var xmlhttp;
function submitFormData(name)
{//alert("Message");
xmlhttp=null;
if (window.XMLHttpRequest)
{// code for IE7, Firefox, Opera, etc.
xmlhttp=new XMLHttpRequest();
}
else if (window.ActiveXObject)
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
if (xmlhttp!=null)
{
xmlhttp.onreadystatechange=state_Change;
var url = "postformdata";
var params = "name="+name+"&recaptcha_challenge_field=" + Recaptcha.get_challenge() + "&recaptcha_response_field="+Recaptcha.get_response();
var status = document.getElementById("status");
status.innerHTML = "<img src='img/ajax-loader.gif'><b>Submitting your data. Please wait...</b>";
xmlhttp.open("POST",url,true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.setRequestHeader("Content-length", params.length);
xmlhttp.setRequestHeader("Connection", "close");
xmlhttp.send(params);
}
else
{
alert("Your browser does not support XMLHTTP.");
}
}function state_Change()
{
if (xmlhttp.readyState==4)
{// 4 = "loaded"
if (xmlhttp.status==200)
{
// 200 = "OK"
var status = document.getElementById("status");
status.innerHTML = xmlhttp.responseText;;
Recaptcha.reload();
setTimeout(function() {
status.innerHTML = "";
}, 3000);
}
else {
var status = document.getElementById("status");
status.innerHTML = xmlhttp.responseText;;
Recaptcha.reload();
setTimeout(function() {
status.innerHTML = "";
}, 3000);
}
}
}
</script>
</head><body onload="PreloadCaptcha()">
<FORM NAME="dataform">
<TABLE>
<TR>
<TD><b>Your name:</b></TD>
<TD><INPUT NAME="txtName"/></TD>
</TR>
<TR>
<TD colspan="2"><div id="dynamic_recaptcha_1"></div></TD>
</TR>
<TR>
<TD colspan="2"><INPUT type="button" value="Submit Data" name="btnSubmitData" onClick="submitFormData(txtName.value); return true"></TD>
</TR>
<TR>
<TD colspan="2"><div id="status"/></TD>
</TR>
</TABLE>
</FORM>
</body>
</html>
Let us go through the important parts of the code:
1. The first part to notice is that I have referenced the javascript file for the ReCAPTCHA code as shown :
<script type="text/javascript" src="http://api.recaptcha.net/js/recaptcha_ajax.js"></script>
2. There is a javascript function call being made on the load of the body (<body onload="PreloadCaptcha()">). This invokes the function showRecaptcha() that is shown below:
Recaptcha.create("YOUR_PUBLIC_KEY", "dynamic_recaptcha_1", {
theme: "white",
callback: Recaptcha.focus_response_field
});
The Recaptcha class is available from the javascript file and we use the create method. The first parameter is the PUBLIC_KEY that you get when you registered at ReCaptcha for your site name. If you are testing it locally, this will be the Public Key for your localhost site. The second parameter is a DIV element that is present in the form.
The create() method on successful invocation will populate the DIV element with the CAPTCHA challenge/response fields.
3. The rest of the code is standard AJAX stuff. The submit button invokes the submitDataForm() that does the following:
- It will invoke the URL : /postformdata that will be our servlet that does the verification. The servlet code is discussed in the next section
- It will form the request parameter string as shown below:
var params = “name=”+name+”&recaptcha_challenge_field=” + Recaptcha.get_challenge() + “&recaptcha_response_field=”+Recaptcha.get_response(); - Note the two fields : recaptcha_challenge_field and recaptcha_challenge_response_field. We get the two values from the Recaptcha class methods, get_challenge() and get_response() respectively. The get_challenge() is what was provided by the ReCAPTCHA Server and the get_response() is what was entered by the user.
- Finally we do a POST to the server and collect the response. The response is that displayed in another DIV element “status”.
Please note that the code is just for demonstration purpose and may not represent the best practices or most efficient way of writing JavaScript, AJAX, etc.
The Servlet [PostFormDataServlet.java]
package com.gaejexperiments.captcha;import java.io.IOException;import javax.servlet.http.*;//RECAPTCHA
import net.tanesha.recaptcha.ReCaptchaImpl;
import net.tanesha.recaptcha.ReCaptchaResponse;
@SuppressWarnings("serial")
public class PostFormDataServlet extends HttpServlet {public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
String strResponse = "";
try {/*
* CAPTCHA CHECK
*
*
*/
//First validate the captcha, if not -- just get out of the loop
String challenge = (String) req.getParameter("recaptcha_challenge_field");
String response = (String) req.getParameter("recaptcha_response_field");
if ((challenge == null) || (response == null)) {
throw new Exception("Your words did not match. Please try submitting again.");
}String remoteAddr = req.getRemoteAddr();
ReCaptchaImpl reCaptcha = new ReCaptchaImpl();reCaptcha.setPrivateKey("YOUR_PRIVATE_KEY");ReCaptchaResponse reCaptchaResponse =
reCaptcha.checkAnswer(remoteAddr, challenge, response);if (!reCaptchaResponse.isValid()) {
//RECAPTCHA VALIDATION FAILED
throw new Exception("Your words did not match. Please try submitting again.");
}strResponse = "Your record has been accepted and you did a good job entering the two words. Thank you";
}
catch (Exception ex) {
strResponse = "You record was not accepted. Reason : " + ex.getMessage();
}
resp.getWriter().println(strResponse);
}
}
Let us go through the important parts in the code:
1. Notice that we are importing 2 classes : net.tanesha.recaptcha.ReCaptchaImpl and net.tanesha.recaptcha.ReCaptchaResponse at the beginning. These are the implementation classes that encapsulate the verification with the ReCAPTCHA Server and the response from the ReCAPTCHA Server respectively.
2. We first extract out the challenge and the response fields as passed by our form.
String challenge = (String) req.getParameter("recaptcha_challenge_field");
String response = (String) req.getParameter("recaptcha_response_field");
3. We also need the Remote IP Address that is making the request.
String remoteAddr = req.getRemoteAddr();
4. We then instantiate an instance of the ReCaptchaImpl class. We set the Private Key that we got during our registration for the site localhost. Please use your key over here. And then we make a call to their server by invoking the checkAnswer method. The checkAnswer method takes 3 parameters : challenge, response and the Remote Address.
ReCaptchaImpl reCaptcha = new ReCaptchaImpl();reCaptcha.setPrivateKey("YOUR_PRIVATE_KEY");ReCaptchaResponse reCaptchaResponse =
reCaptcha.checkAnswer(remoteAddr, challenge, response);
5. We will receive an instance of the ReCaptchaResponse class. We simply use a utility method isValid() to determine if the response entered for the challenge was correct. And depending on that we send back an appropriate response back to the browser, which is then displayed to the user.
Servlet Configuration
To complete our Servlet development, we will also need to add the <servlet/> and <servlet-mapping/> entry to the web.xml file. This file is present in the WEB-INF folder of the project. The necessary fragment to be added to your web.xml file are shown below. Please note that you can use your own namespace and servlet class. Just modify it accordingly if you do so.
<servlet>
<servlet-name>PostFormDataServlet</servlet-name>
<servlet-class>com.gaejexperiments.captcha.PostFormDataServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PostFormDataServlet</servlet-name>
<url-pattern>/postformdata</url-pattern>
</servlet-mapping>
Running the application locally
I am assuming that you have already created a new Google Web Application Project and have created the above Servlets, web.xml , etc. We shall be running this episode within our local development server only since the keys that I have used are for localhost. Before you deploy the application to the actual Google App Engine infrastructure using your Application ID, do remember to get yourself the appropriate public/private ReCAPTCHA keys for your site name.
So assuming that all is well, we will run our application, by right-clicking on the project and selecting Run As –> Web Application. Launch the browser on your local machine and navigate to http://localhost:<YourLocalPort>/captcha.html
Conclusion
In this episode, we saw how to incorporate a CAPTCHA in our Google App Engine application. Please remember that you will need to determine if you really need a CAPTCHA in your application. There are some good points mentioned in this article on various other techniques that can be used to address the same problems.
Read more Episodes on App Engine Services
- Writing Google Talk Bots with App Engine
- Write your first Google Chrome Extension, powered by App Engine
- Scheduling Background Tasks in App Engine: Learn about the Cron Scheduler in App Engine
- Asynchronous Processing in App Engine: Learn about tasks / queues in App Engine
- Handling Email in App Engine Applications: Sending and Receiving incoming Email in your App Engine applications
- Blobstore Tutorial : Use the App Engine Blobstore service to store data in GB
- Datastore Tutorial : Basic database programming in App Engine
- Captcha Tutorial: How to integrate a Captcha in your App Engine application
- Location Services: Learn how to detect Location (Latitude & Longitude) in your App Engine Application. Part 1 and Part 2.
- Memcache: Learn how to use the cache to speed up your App Engine applications
- Networking: Learn how to make calls to external Web Services using URLFetch service in App Engine.
- Download the eBook: All the episodes packaged for you in a free eBook. Enjoy and thanks for downloading.