Introduction aux Captcha
Le captcha comme son nom l’indique (Completely Automated Public Turing test to tell Computers and Humans Apart) est un moyen simple de protéger son site de soumissions automatiques effectuées par des robots depuis l’autre bout du monde et ainsi de s’assurer que l’on a bien a faire à un utilisateur “humain”. Par exemple de nombreux blogs et forums sont la cibles de soumissions de post sans aucun rapport avec la discussion mais contenant des liens vers des sites d’ailleurs peu recommandables.
Le captcha est un système de question-réponse qui nécessite un minimum de réflexion pour ne pas pouvoir être automatisé.
La force du captcha réside donc d’une part dans l’impossibilité pour un algorithme de résoudre la question et d’autre part sa facilité d’interprétation pour que tout être humain puisse répondre à la question.
Plusieurs déclinaisons du Captcha existent (reconnaissance d’images, opérations arithmétiques, reconnaissances vocales) mais nous ne nous intéressons qu’au plus commun basé sur la reconnaissance de caractères dans une image. Pour constituer un bon captcha, l’image ne doit pas être décomposable facilement auquel cas un programme pourrait analyser l’image, découper les zones de texte et identifier les caractères. Voilà pourquoi ces captchas ont la particularité d’être écrits bizarrement voire parfois impossible à lire du fait des polices utilisés, des lettres qui se chevauchent ou encore à cause du fond de l’image.
Le principe du captcha réside également dans le découplage entre les informations serveurs et les informations clients : la réponse est stockée côté serveur et ne doit pas apparaitre côté client en dehors de la représentation de l’image : nom de l’image, champ caché, paramètre dans l’url, etc… sinon l’information est facilement accessible sans intervention humaine. Ensuite la réponse envoyée par le client est comparé à la réponse côté serveur.
Utilisation de JCaptcha pour vos sites web en Java
JCaptcha est un framework Java open source qui permet d’implémenter très rapidement une solution de Captcha et permet dans un deuxième temps de gérer plus finement des Captcha.
Je détaille ici la conception d’un formulaire d’enregistrement sur une page JSF utilisant JCaptcha 2.0 pour empêcher les inscriptions automatiques.
Par rapport au projet JSF vous devez ajouter 4 librairies disponibles sur le site officiel du projet JCaptcha :
* jcaptcha-api-1.0.jar
* jcaptcha-2.0-alpha-1-SNAPSHOT.jar
* jcaptcha-integration-simple-servlet-2.0-alpha-1-SNAPSHOT.jar
* filters-2.0.235.jar
Modifier votre fichier web.xml pour ajouter la servlet JCaptcha. Votre fichier doit ressembler en gros à ceci :
le fichier web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>Test App</display-name> <servlet> <servlet-name>jcaptcha</servlet-name> <servlet-class>com.octo.captcha.module. servlet.image.SimpleImageCaptchaServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>jcaptcha</servlet-name> <url-pattern>/faces/jcaptcha.jpg</url-pattern> </servlet-mapping> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsf</welcome-file> <welcome-file>index.xhtml</welcome-file> </welcome-file-list> </web-app> |
Comme vous le voyez la servlet jcaptcha est mappée sur le pattern /faces/jcaptcha.jpg, ainsi l’appel de cette ressource sera redirigé vers la servlet JCaptcha.
le formulaire d’enregistrement
La page register.xhtml est liée au backing bean registrationBean et contient le formulaire avec les champs à renseigner et en bas, l’insertion du captcha via l’appel à la servlet en appelant la ressource jcaptcha.jpg.
<h:form name="register"> <table> <tr> <td>Prénom</td> <td><h:inputText value="#{registrationBean.firstName}" required="true" /></td> </tr> <tr> <td>Nom</td> <td><h:inputText value="#{registrationBean.lastName}" required="true" /></td> </tr> <tr> <td>Nom d'utilisateur</td> <td><h:inputText value="#{registrationBean.username}" required="true" id="username" /></td> </tr> <tr> <td>email</td> <td><h:inputText value="#{registrationBean.email}" required="true" /></td> </tr> <tr> <td>password</td> <td><h:inputSecret value="#{registrationBean.password1}" required="true" /></td> </tr> <tr> <td>confirmer password</td> <td><h:inputSecret id="password2" value="#{registrationBean.password2}" required="true" /> <h:message for="password2" showSummary="false" showDetail="true" /></td> </tr> <tr> <td colspan="2">Code de vérification</td> </tr> <tr> <td colspan="2"><img src="jcaptcha.jpg" /><h:inputText name="jcaptcha" id="jcaptcha" required="true"> <f:validator validatorId="captchaValidator" /> </h:inputText> <h:message for="jcaptcha" styleClass="error" /></td> </tr> <tr> <td colspan="2"><h:commandButton value="Valider" action="#{registrationBean.register}" /></td> </tr> </table> </h:form> |
La vérification du captcha se fait grâce à un validator JSF (validatorId=”captchaValidator”).
Le validator du captcha
Nous allons définir un validator personnalisé qui implémente bien sûr l’interface Validator de JSF.
N.B. nous récupérons la requête via le SecurityContext car nous utilisons Spring-Security pour gérer l’identification. Il faudra remplacer cette variable par l’objet approprié si Spring-Security n’est pas utilisé.
package validator; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.validator.Validator; import javax.faces.validator.ValidatorException; import javax.servlet.http.HttpServletRequest; import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper; import com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet; public class CaptchaValidator implements Validator { public static final String MATCHING_ERROR_MESSAGE = "Code de validation incorrect"; @Override public void validate(FacesContext arg0, UIComponent arg1, Object arg2)throws ValidatorException { try { String userCaptchaResponse = (String)arg2; boolean captchaPassed = SimpleImageCaptchaServlet.validateResponse((HttpServletRequest) ((SecurityContextHolderAwareRequestWrapper)arg0.getExternalContext().getRequest()).getRequest(), userCaptchaResponse); if(!captchaPassed){ throw new ValidatorException(new FacesMessage(MATCHING_ERROR_MESSAGE, MATCHING_ERROR_MESSAGE)); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } |
Ajouter le validator à la configuration de JSF
Rajouter dans faces-config.xml entre les balises
<validator> <validator-id>captchaValidator</validator-id> <validator-class>validator.CaptchaValidator</validator-class> </validator> |
Et voilà, vous avez implémenté en seulement quatre étapes un captcha dans vos pages.
Hi thanks a lot for sharing !
I.was just implementing the same thing JSF+Spring+Hibernate+Spring security and I wanted to put something like a captcha in my site.
Regards,
hono
Merci pour votre aide, maintenant on peut choisir nous même les sites qu.on veut lier avec notre propre site.