Integrating CAPTCHA Into Spring MVC Web Applications
Integrating CAPTCHA in an application involves two simple steps:
- Display CAPTCHA Widget
- Validate CAPTCHA Reponse
In this blog post, I will be using Google’s reCAPTCHA. Before we can start using reCAPTCHA, we need to sign up for API keys.
Obtaining reCAPTCHA keys
1. Go to the reCAPTCHA Key Signup Page and login using your Google Account.
Enter the your domain name and hit “Create Key”. The generated keys by default are restricted to the specified domain. However, all keys will work on the localhost domain, making it easy to test during development.
Make a note of the generated public and private keys. We need both keys in order to generate CAPTCHA and verify response.
Display CAPTCHA Widget
reCAPTCHA provides a Java Library wrapper that makes CAPTCHA generation/verification easier. Maven users can get the jar file with the following dependency:
<dependency> <groupId>net.tanesha.recaptcha4j</groupId> <artifactId>recaptcha4j</artifactId> <version>0.0.7</version> </dependency>
With the dependency added, generating the CAPTCHA Widget simply involves placing the below scriptlet in a JSP page:
<% ReCaptcha captcha = ReCaptchaFactory.newReCaptcha("PUBLIC_KEY", "PRIVATE_KEY", false); out.print(captcha.createRecaptchaHtml(null, null)); %>
In the above code, we first create an instance of ReCaptcha by passing in the generated public and private key. The third parameter instructs if a noscript tag should to be placed around the generated HTML.
Since, I don’t like using Scriptlets in my JSP pages, I will create a reusable JSP tag that wraps the above code. We start out by creating a CaptchaTag class as shown below:
package com.inflinx.blog.web.tag; import java.io.IOException; import java.util.Properties; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.SimpleTagSupport; import org.apache.commons.lang.StringUtils; import net.tanesha.recaptcha.ReCaptcha; import net.tanesha.recaptcha.ReCaptchaFactory; public class CaptchaTag extends SimpleTagSupport { private String publickey; private String privatekey; private String themeName; @Override public void doTag() throws JspException, IOException { ReCaptcha captcha = ReCaptchaFactory.newReCaptcha(publickey, privatekey, false); Properties properties = new Properties(); if(StringUtils.isNotEmpty(themeName)) { properties.put("theme", themeName); } String captchaHtml = captcha.createRecaptchaHtml(null, properties); getJspContext().getOut().write(captchaHtml); } public String getThemeName() { return themeName; } public void setThemeName(String themeName) { this.themeName = themeName; } public String getPublickey() { return publickey; } public void setPublickey(String publickey) { this.publickey = publickey; } public String getPrivatekey() { return privatekey; } public void setPrivatekey(String privatekey) { this.privatekey = privatekey; } }
The above tag takes has three attributes: public key, private key and theme name. The theme option can be used to control the reCAPTCHA widget’s look and feel. Possible values include: “red”, “white”, “blackglass” or “clean”. The default is the red.
To complete the implementation of the tag, lets create a captcha.tld file under WEB-INF/tlds folder with the following contents:
<taglib xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.1"> <tlibversion>1.0</tlibversion> <jspversion>2.1</jspversion> <shortname>CaptcahTags</shortname> <uri>http://blog.inflinx.com</uri> <info>Captcha Tags</info> <tag> <name>captcha</name> <tagclass>com.inflinx.blog.web.tag.CaptchaTag</tagclass> <bodycontent>empty</bodycontent> <info>Generates Captcha Widget</info> <attribute> <name>publickey</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>privatekey</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>themeName</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
With all this in place, update the JSP page with the following code to display the CAPTCHA Widget:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <%@ taglib prefix="captcha" uri="/WEB-INF/tlds/captcha.tld" %> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <html> <head> <title>Home</title> </head> <body> <form method="post"> <captcha:captcha themeName="clean" publickey="YOUR_PUBLIC_KEY" privatekey="YOUR_PRIVATE_KEY"/> </form> </body> </html>
Upon running the code, you should see a CAPTCHA similar to the image below:
Validate CAPTCHA Reponse
In order to valdiate the CAPTCHA response, we need to modify the POST method of the receiving controller as shown below:
@RequestMapping(method = RequestMethod.POST) public String processSubmit(HttpServletRequest request, Model model) { ReCaptchaImpl reCaptcha = new ReCaptchaImpl(); reCaptcha.setPrivateKey("YOUR_PRIVATE_KEY"); String remoteAddr = request.getRemoteAddr(); String challengeField = request.getParameter("recaptcha_challenge_field"); String responseField = request.getParameter("recaptcha_response_field"); ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(remoteAddr, challengeField, responseField); if(!reCaptchaResponse.isValid()) { model.addAttribute("invalidCaptcha", "Captcha Is Invalid"); return "home"; } return "success"; }
In the above code, we start by creating a ReCaptchaImpl instance and pass in the Private key. The reCaptcha widget generates two fields “recaptcha_challenge_field”, “recaptcha_response_field” that are needed to verify the response. We pass in those two fields along with the IP Address of the client to get a response.
For invalid responses, we set a model attribute to indicate the error. Now, in a Spring MVC application where you are using a command object for the form, you can add an error instance instead:
if(!reCaptchaResponse.isValid()) { errors.reject("captcha.invalid"); }