JavaServer Pages Form CAPTCHA Code Example

The JSP Form Captcha code example shows how to add BotDetect CAPTCHA protection to a typical JSP form.

First Time Here?

Check the BotDetect JSP Captcha Quickstart for key integration steps.

Captcha validation is integrated with other form fields validation, and only submissions that meet all validation criteria are accepted.

If the Captcha is successfully solved but other field validation fails, the Captcha is hidden since the users have already proven they are human.

This kind of validation could be used on various types of public forms which accept messages, and are at risk of unwanted automated submissions.

For example, it could be used to ensure bots can't submit anything to a contact form, add guestbook entries, blog post comments or anonymous message board / forum replies.

Download the BotDetect Java library and run this example

Downloaded Location

The JSP Form CAPTCHA code example is included in the
examples/bdc4-jsp-form-captcha-example.war file of the download package. Deploying (unpacking) the file will create a standard JSP directory tree.

Running Example

This example's war file (in BotDetect download package) already embeds all dependencies.

In case you are making this example from scratch in your IDE, you need to ensure botdetect.jar, botdetect-servlet.jar, and botdetect-jsp20.jar are in the classpath.

index.jsp

<%@page trimDirectiveWhitespaces="true"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="botDetect" uri="https://captcha.com/java/jsp"%>
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>BotDetect Java CAPTCHA Validation: JSP Form CAPTCHA Code Example</title>
  <link rel="stylesheet" href="stylesheet.css" type="text/css" />
</head>
<body>
  <form method="post" action="captchaFormAction" class="column" id="form1">
    <h1>BotDetect Java CAPTCHA Validation:<br> JSP Form CAPTCHA Code Example</h1>
    <fieldset>
      <legend>CAPTCHA included in JSP form validation</legend>
      <div class="input">
        <label for="name">Name:</label>
        <input type="text" name="name" class="textbox" value="${param.name}" />
        <label class="incorrect" for="name">${messages.nameIncorrect}</label>
      </div>

      <div class="input">
        <label for="email">Email:</label>
        <input type="text" name="email" class="textbox" value="${param.email}" />
        <label class="incorrect" for="email">${messages.emailIncorrect}</label>
      </div>

      <div class="input">
        <label for="message">Short message:</label>
        <textarea class="inputbox" name="message" rows="5" cols="40">${param.message}</textarea>
        <label class="incorrect" for="message">${messages.messageIncorrect}</label>
      </div>

      <%
        if (request.getSession().getAttribute("isCaptchaSolved") == null) {
      %>
          <label for="captchaCode" class="prompt">Retype the characters from the picture:</label>

          <!-- Adding BotDetect Captcha to the page -->
          <botDetect:captcha id="formCaptcha" 
                userInputID="captchaCode"
                codeLength="3"
                imageWidth="150"
                imageStyle="GRAFFITI2" />

          <div class="validationDiv">
            <input id="captchaCode" type="text" name="captchaCode" />
            <label class="incorrect" for="captchaCode">${messages.captchaIncorrect}</label>
          </div>
      <%
        }
      %>

      <input type="submit" name="submitButton" id="submitButton" value="Submit" />
      <label class="correct">${messages.captchaCorrect}</label>
    </fieldset>
  </form>
</body>
</html>

Beside the Captcha code input textbox, the example form contains three other fields, which are all validated the same way in form processing code.

To hide the Captcha challenge after the user solves it (regardless of other field validation status), the Captcha object's Html value is only added to the page if not already solved
(if (request.getSession().getAttribute("isCaptchaValid") == null ...).

CaptchaFormAction.java

package com.captcha.botdetect.examples.jsp.form;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.captcha.botdetect.web.servlet.Captcha;

public class CaptchaFormAction extends HttpServlet {
  
  HttpSession session;

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    Map<String, String> messages = new HashMap<String, String>();
    request.setAttribute("messages", messages);
    
    Captcha captcha = Captcha.load(request, "formCaptcha");
    boolean messageValid = true;
    String destinationPage = "/index.jsp";

    session = request.getSession(true);

    if (session.getAttribute("isCaptchaSolved") == null) {
      // validate the Captcha to check we're not dealing with a bot
      boolean isHuman = captcha.validate(request.getParameter("captchaCode"));
      if (isHuman) {
        // Captcha validation passed, perform protected action
        session.setAttribute("isCaptchaSolved", true);
      } else {
        // Captcha validation failed, show error message
        messages.put("captchaIncorrect", "*");
        messageValid = false;
      }
    }

    if (!isValidName(request.getParameter("name"))) {
      messages.put("nameIncorrect", "*");
      messageValid = false;
    }

    if (!isValidEmail(request.getParameter("email"))) {
      messages.put("emailIncorrect", "*");
      messageValid = false;
    }

    if (!isValidMessage(request.getParameter("message"))) {
      messages.put("messageIncorrect", "*");
      messageValid = false;
    }

    if (messageValid) {
      saveMessage(request.getParameter("name"), request.getParameter("email"), request.getParameter("message"));
      session.removeAttribute("isCaptchaSolved");
      destinationPage = "/messages.jsp";
    }

    RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(destinationPage);
    dispatcher.forward(request, response);
  }

  private boolean isValidName(String name) {
    if (name == null) {
      return false;
    }
    return name.length() > 2 && name.length() < 30;
  }

  private boolean isValidEmail(String email) {
    if (email == null) {
      return false;
    }
    return email.matches("^[\\w-_\\.+]*[\\w-_\\.]\\@([\\w]+\\.)+[\\w]+[\\w]$");
  }

  private boolean isValidMessage(String message) {
    if (message == null) {
      return false;
    }
    return (message.length() > 2) && (message.length() < 255);
  }

  private void saveMessage(String name, String email, String messageText) {
    Date timeStamp = new Date();
    String message = name + " (" + email + ") says: " + messageText;
    session.setAttribute("Message_" + timeStamp.getTime(), message);
  }
}

Form submission validation is performed in this file, which checks all required fields. We use simple request.setAttribute() method to pass validation results.

Captcha validation is treated similar to other fields validation, and will work as long as we initialize the Captcha object with the same id ("formCaptcha") and retreive user code from the same userInputID ("captchaCode") we used on the form page to add the Captcha.

Once form validation succeeds, the submitted values are saved and the Captcha challenge is reset (session.removeAttribute("isCaptchaValid");). This means each individual message requires Captcha validation, which helps prevent attacks where a malicious user could solve the Captcha once and then automate further form posts within the same Session.

messages.jsp

<%@page import="java.util.Enumeration"%>
<%@page trimDirectiveWhitespaces="true"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>BotDetect Java CAPTCHA Validation: JSP Form CAPTCHA Code Example</title>
  <link rel="stylesheet" href="stylesheet.css" type="text/css" />
</head>
<body>
  <div class="column">
    <h1>BotDetect Java CAPTCHA Validation:<br> JSP Form CAPTCHA Code Example</h1>
    <h2>View Messages</h2>
    <%
      int count = 0;
      Enumeration attributes = request.getSession().getAttributeNames();
      while (attributes.hasMoreElements()){
        String attribute = (String)attributes.nextElement();
        if (attribute.startsWith("Message_")) {
          out.println("<p class=\"message\">" + session.getAttribute(attribute) + "</p>");
          count++;
        }
      }
      
      if (count == 0) {
        out.print("<p class=\"message\">No messages yet.</p>");;
      }
    %>

    <p class="navigation"><a href="index.jsp">Add Message</a></p>
  </div>  
</body>
</html>

This page displays all successfully submitted messages, and the user is automatically redirected here after validation of all form fields (including Captcha) is passed.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <session-config>
    <session-timeout>
      30
    </session-timeout>
  </session-config>
  
  <servlet>
    <servlet-name>BotDetect Captcha</servlet-name>
    <servlet-class>com.captcha.botdetect.web.servlet.CaptchaServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>BotDetect Captcha</servlet-name>
    <url-pattern>/botdetectcaptcha</url-pattern>
  </servlet-mapping>
  
  <servlet>
    <servlet-name>CaptchaFormAction</servlet-name>
    <servlet-class>com.captcha.botdetect.examples.jsp.form.CaptchaFormAction</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>CaptchaFormAction</servlet-name>
    <url-pattern>/captchaFormAction</url-pattern>
  </servlet-mapping>
  
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

In WEB-INF/web.xml file we register CaptchaServlet used for BotDetect Captcha requests and register CaptchaFormAction servlet used for validating form data.


Please Note

BotDetect Java Captcha Library v4.0.Beta1 is an in-progress port of BotDetect 4 Captcha, and we need you to guide our efforts towards a polished product. Please let us know if you encounter any bugs, implementation issues, or a usage scenario you would like to discuss.