Implementando CAPTCHA com reCaptcha em aplicações WEB

Neste artigo será demonstrado como criar desafios CAPTCHA para ajudar a proteger aplicações WEB contra ataques computacionais utilizando a solução gratuita reCaptcha.

Marcelo Nascimento, Software Analyst, IBM Corporation

Marcelo NascimentoMarcelo Nascimento é pós graduado em Análise de Sistema pela Universidade Presbiteriana Mackenzie. Atualmente atua como analista de sistemas J2EE. Perfil My developerWokrs.



25/Set/2012

Introdução

Todos nós sabemos que o poder computacional nos possibilita realizar atividades que, para um ser humano, seriam impossíveis ou extremamente complexas. Infelizmente, algumas vezes este grande poder computacional é utilizado para atividades maliciosas, como derrubar servidores, tentativas de degradação de desempenho de serviços, SPAM, dentre outras. Estas investidas maliciosas podem ser realizadas através de robôs que executam atividades como se fossem humanos fazendo requisições a um serviço ou aplicação.

Se estes robôs fazem requisições como se fossem humanos, como as aplicações WEB podem identificar se o acesso está sendo feito por um humano ou por um robô?

A resposta foi dada pelos cientistas no ano 2000 com o termo CAPTCHA.

CAPTCHA é um acrônimo da expressão "Completely Automated Public Turing test to tell Computers and Humans Apart" (Teste público de Turing completamente automatizado para separar computador e humanos). A ideia é que seja lançado um desafio (challenge); se a resposta (answer) informada para o desafio estiver correta, considera-se que foi fornecida por um ser humano, e não por um computador.

Existe uma infinidade de maneiras diferentes de se apresentar um desafio CAPTCHA. De forma geral, estes desafios são apresentados através de imagens coloridas com textos distorcidos (e em alguns casos usando até mesmo fotos). Esta estratégia dificulta muito as tentativas de robôs responderem os desafios. As figuras 1 e 2 ilustram alguns exemplos de desafios CAPTCHA.

Figura 1. Desafio CAPTCHA.

Figura 2. Desafio CAPTCHA.

Para acessibilidade, também podem ser oferecidos desafios em áudio, que permitem a portadores de necessidades especiais visuais responderem ao desafio após ouvir uma mensagem.

Para ambientes Java™ e Java™ Enterprise Edition (Java EE) existem diversas alternativas para que se possa implementar CAPTCHA em aplicações. Dentre as opções, existe um serviço chamado reCAPTCHA que permite de uma forma rápida e simples implementar desafios CAPTCHA em aplicações.


O que é reCAPTCHA

Iniciado como um projeto da Escola de Ciência da Computação na Universidade Carnegie Mellon, hoje o reCAPTCHA é um serviço gratuito que permite a implementação de desafios CAPTCHA e também ajuda na digitalização de livros.

Isso mesmo, ajuda na digitalização de livros! Segundo o próprio portal do serviço, aproximadamente 200 milhões de CAPTCHAs são resolvidos por humanos todos os dias em sites, e as pessoas levam cerca de 10 segundos para respondê-los. Individualmente é pouco tempo, mas juntos podem consumir mais de 150.000 horas por dia.

Será que todo este tempo coletivo não poderia ser aproveitado?

A resposta é sim. O reCAPTCHA canaliza este esforço (de responder um desafio CAPTCHA) para ajudar na digitalização de livros que foram escritos antes da "era computacional", e estão sendo escaneados / transformados em texto usando programas de OCR (Optical Character Recognition).

Em outras palavras, enquanto o reCAPTCHA evita ações de robôs e SPAM, também ajuda a identificar palavras não reconhecidas corretamente por programas de OCR.

Portais como o Internet Archive foram beneficiados por esta ajuda colaborativa feita através do reCAPTCHA.

Vamos entender adiante o funcionamento do reCAPTCHA.


Como funciona o reCAPTCHA

Durante a visualização do desafio CAPTCHA, o reCAPTCHA apresenta duas palavras. Uma palavra é um texto que não foi reconhecido adequadamente por um programa de OCR, e uma segunda palavra também é apresentada, mas neste caso o reCAPTCHA conhece a palavra.

Uma curiosidade que você pode estar tendo é: Se uma das palavras (a primeira palavra) não foi reconhecida adequadamente por um programa de OCR, como o reCAPTCHA sabe avaliar se a resposta informada pelo usuário está correta?

Na verdade o reCAPTCHA avalia apenas a resposta da palavra conhecida (a segunda palavra) para determinar o resultado do desafio. A outra palavra, cuja resposta não é conhecida, é assumida como correta. Claro que o reCAPTCHA não assume a resposta de apenas uma pessoa. Para ter um maior grau de confiança, a mesma palavra é oferecida a outros usuários para determinar se a resposta informada é realmente correta.

Para um melhor entendimento, vamos analisar a figura 3 retirada do portal American Association for the Advancement of Science (AAAS).

Figura 3. Funcionamento do reCAPTCHA.

No exemplo acima, a palavra destacada "morning" não foi identificada por um programa de OCR. O reCAPTCHA então isolou a palavra, aplicou distorções e através de transformações aleatórias adicionou uma linha sobre a mesma para finalmente apresentá-la como um desafio CAPTCHA. Como já explicado anteriormente, uma segunda palavra também é apresentada, que neste caso é a palavra "overlooks", cuja resposta o reCAPTCHA já conhece.

Com este mecanismo, o reCAPTCHA protege páginas, portais e serviços WEB contra robôs e usa o conhecimento humano na identificação de palavras.


Como utilizar o reCAPTCHA

O reCAPTCHA é um serviço gratuito, mas para utilizá-lo é necessário que você tenha uma conta no Google®.

Com sua conta já criada, precisaremos gerar nossa chave, que também é conhecida por reCAPTCHA key. A reCAPTCHA key é fundamental para utilizar o serviço, e para criá-la necessitamos executar os seguintes passos:

  1. Acessar o portal do reCAPTCHA através do endereço www.recaptcha.net;
  2. Clicar em "MY ACCOUNT";
  3. Autenticar usando sua conta no Google® (caso já esteja autenticado, este passo será omitido automaticamente).

Com os passos acima você provavelmente visualizará a página da figura 4.

Figura 4. Criando chave (reCAPTCHA key).

Na figura acima, a chave será criada para o domínio meusitecomrecaptcha.net e seus subdomínios. Quando clicamos em "Create Key" (criar chave), será apresentada uma página conforme a figura 5:

Figura 5. Chave (reCAPTCHA key) criada com sucesso.

Na figura acima são apresentadas duas chaves:

  • Chave pública (public key) - Esta chave será utilizada no código JavaScript™ para apresentar o desafio reCAPTCHA. Esta chave geralmente poderá ser vista quando visualizamos o código fonte da página WEB onde é apresentado o serviço reCAPTCHA.
  • Chave privada (private key) - Esta chave será utilizada quando necessitamos realizar comunicação entre o servidor que utiliza o serviço reCAPTCHA (sua aplicação) e o servidor provedor do serviço reCAPTCHA. Esta chave deve permanecer com acesso restrito e protegido!

Ambas as chaves são únicas para o domínio e subdomínio criados, e poderão ser visualizadas sempre que for necessário através do link "MY SITES" (vide figura 4).

Apesar das chaves serem exclusivas para o domínio e subdomínios cadastrados, o "localhost" (ou "127.0.0.1") é liberado por padrão para o desenvolvimento e testes.


Escolhendo como utilizar o reCAPTCHA

Existem duas formas de se implementar o serviço reCAPTCHA, sem plugin ou com plugin.

Quando optamos pela utilização de plugin, na página do serviço é possível obter uma variedade de plugins para várias linguagens de programação, tais como: PHP, Perl, Java™, dentre outras.

Neste artigo abordaremos o uso de reCAPTCHA utilizando o plugin para Java™, contribuído por Soren Davidsen sob a licença Apache License, versão 2.0 (licença definida para a versão 0.0.7 utilizada neste artigo).

O plugin para Java™ é conhecido também por RECAPTCHA4J.


Instalação do RECAPTCHA4J

Primeiramente será necessário obter a biblioteca RECAPTCHA4J no site do reCAPTCHA.

A instalação da biblioteca RECAPTCHA4J depende de como o aplicativo será empacotado e como ele funcionará. Dentre as opções de instalação, podemos:

  • Incluir a biblioteca no diretório WEB-INF/lib da aplicação;
  • Disponibilizar a biblioteca em uma biblioteca compartilhada (shared library);
  • Configurar a biblioteca no caminho de classe (classpath) da aplicação.

Utilizando o RECAPTCHA4J

Vamos criar um exemplo de aplicação Java™ (WEB) para demonstrar o funcionamento da biblioteca RECAPTCHA4J. Não será foco no exemplo a aplicação de boas práticas de programação, pois o intuito é apresentar o funcionamento da biblioteca RECAPTCHA4J.

Para a elaboração do exemplo foi utilizado o Eclipse® Java EE IDE for Web Developers, com Apache Tomcat 7.0. A versão da biblioteca RECAPTCHA4J definida foi a 0.0.7.

Exemplo - Sistema de acesso restrito

Vamos elaborar uma aplicação onde requisitaremos que o cliente informe seu usuário e senha de acesso, mas para evitar que robôs tentem combinações de usuários e senhas, também utilizaremos o reCAPTCHA para aumentar a segurança. A figura 6 representa o formulário que criaremos para o acesso.

Figura 6. Formulário de acesso com reCAPTCHA.

Como pode ser visto no formulário acima, existem campos onde o cliente deve informar os seus dados de acesso (usuário e senha) e também deve responder o desafio CAPTCHA. Após os campos preenchidos, o cliente acionará o botão "ACESSAR!".

Vamos analisar o código fonte deste formulário.

Quando o endereço da aplicação é requisitado, a execução inicial é feita por um Servlet chamado ImageReCaptchaServlet. Vamos analisar o código fonte na listagem 1.

Listagem 1. Código fonte do Servlet ImageReCaptchaServlet.

01. protected void doPost(HttpServletRequest request,
02. 	     HttpServletResponse response) throws ServletException, IOException {
03.
04. 	//Chaves criadas.
05. 	final String publicKey = "6LdNl9QSAAAAAPeGVBtdUr7slwEDC1L94aYEcDv";
06. 	final String privateKey = "6LdNl9QSAAAAABJL1LDMrkxhEkNKktXHWlFTFtm";
07. 
08. 	//Obtemos uma instância da classe ReCaptcha.
09. 	ReCaptcha c = ReCaptchaFactory.newReCaptcha(publicKey, privateKey, true);
10.
11. 	//Obtemos o código HTML para apresentar o reCAPTCHA WIDGET.
12. 	String reCaptchaChallenge = c.createRecaptchaHtml(null, null);
13. 
14. 	//Armazenamos o HTML no escopo de request.
15. 	request.setAttribute("reCapchaChallenge", reCaptchaChallenge);
16.
17. 	//Acessamos nossa página com o formulário.
18. 	RequestDispatcher nextView = request.getRequestDispatcher("/entradaApp.jsp");
19.
20. 	nextView.forward(request, response);
21.
22. }

Acima, nas linhas 05 e 06 declaramos duas variáveis que armazenam as chaves (reCAPTCHA key) criadas anteriormente (vide figura 5). Na linha 09, utilizamos as chaves para criar uma instância da classe net.tanesha.recaptcha.ReCaptcha, através do método estático newReCaptcha, que está disponível na classe net.tanesha.recaptcha.ReCaptchaFactory. Na linha 12, invocamos o método createRecaptchaHtml que retornará um objeto do tipo java.lang.String contendo o código HTML (HyperText Markup Language) responsável pela apresentação do reCAPTCHA widget. Na linha 15, armazenamos o código HTML gerado no escopo de request, e por fim na linha 18 invocamos o JSP (JavaServer Pages) entradaApp.jsp com o formulário inicial.

Agora vamos analisar o código fonte do JSP entradaApp.jsp na listagem 2.

Listagem 2. Código fonte do JSP entradaApp.jsp.

01. <form id="frmAcesso" name="frmAcesso" method="post" action="ValidaAcessoServlet">
02.
03. 	Usu&aacute;rio:<input type="text" id="txtUsuario" name="txtUsuario" />
04. 	<br />
05. 	Senha:<input type="password" id="txtSenha" name="txtSenha" />
06. 	<br />
07. 	<br />
08. 	<c:out value="${requestScope.reCapchaChallenge}" escapeXml="false" />
09. 	<br />
10. 	<input type="submit" id="btAcessar" name="btAcessar" value="ACESSAR!" />
11.
12. </form>

No código fonte acima, criamos um simples formulário HTML contendo os campos previstos, e na linha 08 imprimimos o widget reCAPTCHA (que foi disponibilizado no escopo de request pelo Servlet ImageReCaptchaServlet).

O resultado do nosso formulário foi apresentado na figura 6.

Pronto! Já estamos utilizando o reCAPTCHA.

Note que para criar o desafio CAPTCHA em si, apenas necessitamos de duas classes da biblioteca RECAPTCHA4J. As classes net.tanesha.recaptcha.ReCaptcha e net.tanesha.recaptcha.ReCaptchaFactory.

Acredito que neste momento você esteja se perguntando: Como testo se a resposta fornecida pelo usuário para o desafio CAPTCHA está correta?

Ainda na listagem 2 (linha 01), podemos notar que o atributo action da tag form tem como valor ValidaAcessoServlet. Neste nosso exemplo, este Servlet será responsável por analisar os dados informados pelo usuário. O código desse Servlet está listagem 3.

Listagem 3. Código fonte do Servlet ValidaAcessoServlet.

01. protected void doPost(HttpServletRequest request,
02.       HttpServletResponse response) throws ServletException, IOException {
03.
04.       response.setContentType("text/html");
05.
06.       //Dados de acesso do cliente.
07.       String usuario = request.getParameter("txtUsuario");
08.       String senha = request.getParameter("txtSenha");
09.
10.       //Desafio e a resposta do cliente (reCAPTCHA).
11.       String challenge = request.getParameter("recaptcha_challenge_field");
12.       String uresponse = request.getParameter("recaptcha_response_field");
13.
14.       //IP para ser passado para os servidores do reCAPTCHA.
15.       String remoteAddr = request.getRemoteAddr();
16. 
17.       //Chave privada.
18.       final String privateKey = "6LdNl9QSAAAAABJL1LDMrkxhEkNKktXHWlFTFtm";
19.
20.       ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
21.
22.       //Inserimos nossa chave privada.
23.       reCaptcha.setPrivateKey(privateKey);
24.
25.       ReCaptchaResponse reCaptchaResponse = 
                reCaptcha.checkAnswer(remoteAddr, challenge, uresponse);
26.
27.       //Validamos se a resposta ao desafio CAPTCHA foi correta.
28.       if(reCaptchaResponse.isValid()) {
29.
30.         //Validamos se os dados do usuário estão corretos.
31.         if(isClienteValido(usuario, senha) == true) {
32.           response.getOutputStream()
             .print("O desafio reCAPTCHA e os dados de acesso 
                    foram respondidos adequadamente!!! :-)");
33. 		}  
34.         }
35.         else {
36.         response.getOutputStream().print("O desafio reCAPTCHA foi 
                                             respondido incorretamente! :-(");
37.         }
38. 
39.         response.getOutputStream().flush();
40. }

Acima, nas linhas 07 e 08, obtemos as informações de acesso ao sistema (usuário e senha). Nas linhas 11 e 12, obtemos o desafio CAPTCHA e a resposta ao desafio provida pelo usuário. Na linha 15 obtemos o endereço IP (Internet Protocol) do usuário. Novamente será necessária a chave privada, portanto, a declaramos novamente na linha 18. Na linha 20, instanciamos a classe net.tanesha.recaptcha.ReCaptchaImpl, e utilizamos o método setPrivateKey na linha 23 para definirmos a chave privada já criada (vide figura 5).

Antes de validar os dados de acesso ao sistema (usuário e senha), vamos verificar se a resposta ao desafio CAPTCHA está correta, assim evitamos o desperdício de recursos (como por exemplo, acesso a banco de dados) caso o desafio seja respondido incorretamente. Na linha 25, invocamos o método checkAnswer da classe net.tanesha.recaptcha.ReCaptchaImpl (com os parâmetros obtidos anteriormente) para validar a resposta (ao desafio) informada pelo usuário. O resultado da checagem é armazenado em uma instância da classe net.tanesha.recaptcha.ReCaptchaResponse, da qual o sucesso ou falha pode ser obtido através do método isValid, conforme a linha 28.

Só em caso de sucesso na verificação ao desafio CAPTCHA o nosso exemplo verificará os dados de acesso (linha 31). Caso o desafio seja respondido incorretamente, uma página de falha é apresentada, conforme a figura 7.

Figura 7. Resultado da execução com a resposta incorreta ao desafio CAPTCHA.

Note novamente que para validar o desafio CAPTCHA em si, apenas necessitamos de duas classes da biblioteca RECAPTCHA4J. As classes net.tanesha.recaptcha.ReCaptchaImpl e net.tanesha.recaptcha.ReCaptchaResponse. O restante do código foi criado para compor o nosso exemplo de utilização.


Customizando a aparência do reCAPTCHA

O reCAPTCHA também oferece um conjunto de recursos que permite a customização da aparência, língua, etc. As customizações são em código JavaScript™ e devem ser declaradas antes do elemento form que apresenta o reCAPTCHA.

Vamos customizar nosso reCAPTCHA widget com algumas das opções disponíveis.

Na listagem 4, podemos visualizar a inclusão de um código JavaScript™ dentro da tag HTML head.

Listagem 4. Código fonte do JSP entradaApp.jsp com customizações na aparência do reCAPTCHA.

Clique aqui para ver lista de códigos

01. <html>
02.
03. <head>
04.     <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
05.     <title>Exemplo de aplica&ccedil;&atilde;o com reCAPTCHA</title>
06. 	<script type="text/javascript">07. 		var RecaptchaOptions = {08. 			theme : 'white',09. 			lang : 'pt',10. 			custom_translations : {11. 				instructions_visual : "Por favor, digite as palavras:"12. 			}13. 		};14. 	</script>
15. </head>
16.
17. <body>
18.
19. <h3>Exemplo utilizando reCAPTCHA</h3>
20.
21. <form id="frmAcesso" name="frmAcesso" method="post" action="ValidaAcessoServlet">
22.
23. 	Usu&aacute;rio:<input type="text" id="txtUsuario" name="txtUsuario" />
24. 	<br />
25. 	Senha:<input type="password" id="txtSenha" name="txtSenha" />
26. 	<br />
27. 	<br />
28. 	<c:out value="${requestScope.reCapchaChallenge}" escapeXml="false" />
29. 	<br />
30. 	<input type="submit" id="btAcessar" name="btAcessar" value="ACESSAR!" />
31.
32. </form>
33.
34. </body>
35.
36. </html>

Acima, entre as linhas 06 e 14 incluímos algumas das customizações possíveis para o nosso reCAPTCHA widget. Na linha 08 definimos o tema (esquema de cores) como white. Na linha 09 definimos a tradução dos textos do reCAPTCHA para pt (português).

Se nas traduções pré-definidas não existir a língua desejada, é possível definir "manualmente" as mensagens. Apesar de ter disponível tradução para português, incluímos um texto manual ao nosso exemplo (linhas 10 a 12). O resultado das alterações pode ser visto na figura 8.

Podemos notar a alteração da cor e da frase logo acima do campo de digitação do desafio CAPTCHA, ao compara-lo com a figura 6.

Figura 8. Resultado do formulário após as alterações de aparência.

Neste exemplo apenas utilizamos algumas customizações possíveis. Para visualizar todas as opções de temas, línguas, traduções customizadas ou outras customizações, consulte o developer's guide na seção referências deste artigo ou através do link customizing the look and feel of reCAPTCHA.


Outras soluções estão por vir

O mais comum é nos deparamos com CAPTCHA em formato de texto desfigurados, mas de fato não podemos considerar que em 100% dos casos de CAPTCHA respondidos foram por humanos. Usando técnicas computacionais, robôs podem conseguir fazer a leitura do desafio e respondê-lo.

A fim de se aproximar mais do comportamento humano, outras formas de desafio CAPTCHA estarão no nosso dia a dia. Como, por exemplo, o projeto SQUIGL-PIX da Escola de Ciência da Computação na Universidade Caarnegie Mellon, onde o desafio oferecido necessita que as imagens sejam interpretadas e reconhecidas.

Nas figuras 9, 10 e 11 podemos ver um exemplo, que pergunta quais imagens são bandeiras.

Figura 9. Desafio apresentado pelo projeto SQUIGL-PIX.

Figura 10. Minha escolha definida foi a segunda figura (destacada em amarelo).

Figura 11. Após a submissão, o SQUIGL-PIX considerou a resposta correta.

O sistema avaliou corretamente, pois de fato nenhuma das outras figuras representam bandeiras (flags).

Outro projeto chamado ESP-PIX também da Escola de Ciência da Computação na Universidade Carnegie Mellon exige ainda uma maior interpretação humana, pois é necessário identificar o que as figuras têm em comum antes de responder ao desafio. Vejamos um exemplo nas figuras 12 e 13.

Figura 12. Desafio CAPTCHA proposto pelo ESP-PIX.

A caixa de seleção (a direita da imagem) apresenta uma série de respostas. Na minha análise, mesmo vendo uma mulher na primeira imagem, entendi que o contexto se tratava do animal cobra, por isso escolhi minha resposta (snake). Este tipo de interpretação seria muito complexa para um robô realizar, e isto faz com que se tenha uma maior certeza que a resposta veio de um humano.

Figura 13. Resultado da avaliação da minha resposta pelo ESP-PIX.

Acima podemos observar que o sistema considerou a minha resposta como correta.


Conclusão

Existem várias bibliotecas para se implementar CAPTCHA em aplicações WEB. O reCAPTCHA é uma alternativa que, além de possuir o diferencial de ajudar na digitalização de livros, é de fácil implementação.


Referências

CAPTCHA

CAPTCHA: Telling Humans and Computers Apart Automatically

Teste de Turing

reCAPTCHA WEB site

reCAPTCHA Blog

reCAPTCHA Wiki

reCAPTCHA: Human-Based Character Recognition via Web Security Measures

reCAPTCHA Developer's Guide

ScienCentral: Fight Spam and Save Shakespeare

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Tecnologia Java
ArticleID=837692
ArticleTitle=Implementando CAPTCHA com reCaptcha em aplicações WEB
publish-date=09252012