Tutorial de integración de reCaptcha y SpringMVC

Tutorial de integración de reCaptcha y SpringMVC

Historia: test de Turing

A mediados del siglo pasado, Alan Turing (famoso matemático y considerado uno de los padres de la informática) ideó el test de Turing, una prueba que consiste en certificar la habilidad de una máquina para exhibir un comportamiento humano centrada en un principio únicamente en la comunicación. De esta manera, una máquina superaba el test de Turing si la persona que se comunicaba con ella no sabía distinguir si lo que había realmente detrás era una máquina o un humano. Este test no fue superado hasta 2014. Además, tanto el test como su trasfondo han evolucionado tanto que a día de hoy podemos hablar de un test de Turing inverso, en el que un humano simula un comportamiento de máquina.

Captcha

Con el test de Turing en mente (de hecho sus siglas así lo indican: prueba de Turing completamente automática y pública para diferenciar ordenadores de humanos) nacen los Captchas, códigos informáticos cuya finalidad principal es evitar el acceso o suplantación de acceso de humanos por parte de máquinas. De esta manera validamos que el acceso a algún recurso (web principalmente) es realizado por una persona y no por una máquina.

Google-reCAPTCHA-example
Con múltiples implementaciones aquí estudiaremos una muy conocida y proporcionada por Google, ReCaptcha en su hasta ahora última versión publicada a finales de 2014.

Ejemplo de integración de recaptcha y SpringMVC

Antes de nada, será necesario crear nuestro proyecto registrándonos en Google Recaptcha, donde únicamente tendremos que dar un nombre al proyecto y establecer los dominios desde los que será accedido y obtendremos una clave pública y otra privada que utilizaremos a continuación.
Después de este paso, comenzaremos mostrando la vista. En nuestro caso utilizamos Thymeleaf como motor de plantillas integrado con Tiles, siendo el código de la vista:

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
28
29
30
31
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:th="http://www.thymeleaf.org"
  xmlns:tiles="http://www.thymeleaf.org"
  xmlns:spring="http://www.springframework.org/tags">
  <body>
    <div tiles:fragment="content">
        <div class="row">
            <form method="post">
                <div>
                    <fieldset class="form-group">
                        <label for="myfield" th:text="#{fields.list.source.myfield}"></label>
                        <div class="inputGroupContainer">
                            <div class="input-group">
                                <select id="myfield" name="myfield" class="c-select form-control"></select>                        
                            </div>
                        </div>
                    </fieldset>
				</div>
                <div class="g-recaptcha" data-sitekey="publickeyvalue"></div>
                <div id="send-form"><button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-send"></span>&nbsp;<span th:text="#{fields.list.submit}"></span></button></div>
            </form>
        </div>
        <script type="text/javascript" th:inline="javascript">
        /*<![CDATA[*/
        //different scripts here
        /*]]>*/
        </script>
        <script src="https://www.google.com/recaptcha/api.js"></script>
    </div>
  </body>
</html>

Los puntos clave de este código son:

  • definición del formulario en la línea 8
  • definición de inputs (parámetros de entrada) en las línas de 10 a 17. En este caso únicamente tenemos un input de tipo select
  • definición del captcha en la línea 20. En él indicamos la clave pública proporcionada.
  • definición de otros scripts de la página de la línea 23 a 27
  • integración de Google Recaptcha en la vista de nuestra web

A continuación vamos a ver el controlador:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RequestMapping(value = URLNamingProvider.USER_MY_URL, method = RequestMethod.POST)
public String myMethod(HttpServletRequest request, HttpServletResponse response, String myfield) throws Exception {
	try {
		String gRecaptchaResponse = request.getParameter("g-recaptcha-response");
		boolean verify = VerifyRecaptcha.verify(this.commonProperties.getGoogleCaptchaApiSecretKey(), gRecaptchaResponse);
		if (verify) {
			this.dataService.myservice(myfield);
			return "mynextwebnameintiles";
		}
		else {
			throw new Exception("captcha error");
		}
	} catch (Exception e) {
		throw e;
	}
}

Los puntos clave de este código son:

  • definición del entry-point en la línea 1
  • definición del parámetro de entrada (myfield) del método en la línea 2. Obviamente tiene que ser el mismo que el nombrado en la vista
  • recuperación de la respuesta del servidor de Google Recaptcha en la línea 4
  • servicio de verificación de la respuesta del captcha en la línea 5 (profundizaremos en esta clase)
  • en caso de superar el captcha, en la línea 7 hacemos lo que queramos con los datos de entrada del formulario y en la línea 8 devolvemos la siguiente vista de nuestra aplicación

Por último, veamos el servicio de verificación de Google Recaptcha en Java:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
 
import javax.net.ssl.HttpsURLConnection;
 
import org.apache.log4j.Logger;
import org.codehaus.jettison.json.JSONObject;
 
public class VerifyRecaptcha {
    private static final Logger logger = Logger.getLogger(VerifyRecaptcha.class);
    public static final String url = "https://www.google.com/recaptcha/api/siteverify";
    private final static String USER_AGENT = "Mozilla/5.0";
 
    public static boolean verify(String secretKey, String gRecaptchaResponse) {
        if (gRecaptchaResponse == null || "".equals(gRecaptchaResponse)) {
            return false;
        }
        try{
            URL obj = new URL(url);
            HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
 
            // add request header
            con.setRequestMethod("POST");
            con.setRequestProperty("User-Agent", USER_AGENT);
            con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
 
            String postParams = "secret=" + secretKey + "&response=" + gRecaptchaResponse;
 
            // Send post request
            con.setDoOutput(true);
            DataOutputStream wr = new DataOutputStream(con.getOutputStream());
            wr.writeBytes(postParams);
            wr.flush();
            wr.close();
 
            int responseCode = con.getResponseCode();
            BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            in.close();
            JSONObject jsonObject = new JSONObject(response.toString());
            return jsonObject.getBoolean("success");
        }catch(Exception e){
            logger.info(e);
            return false;
        }
    }
}

Donde los puntos claves son:

  • definición de URL destino en la línea 13, donde se verificará la respuesta al Captcha
  • firma del método de verificación en la línea 16, que acepta como primer parámetro la clave privada proporcionada en el registro de Google Recaptcha y como segundo parámetro la respuesta introducida por el usuario en el test
  • de la línea 21 a 46 se envía la respuesta del Captcha y se obtiene la respuesta del servicio de verificación
  • en la línea 47 traducimos todo el servicio de Captcha a un sencillo Boolean

Para más información, podemos consultar la documentación específica oficial u otros tutoriales como por ejemplo este.

Conclusiones

Hemos visto cómo integrar en SpringMVC el servicio de reCaptcha de Google. Así, podemos evitar de una menera eficaz el acceso a bots a los servicios proporcionados por nuestras aplicaciones.

Publicado en octubre 11, 2016

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

« »