Voici une application capable de faire la difference entre un humain et un bot. Les formulaires d’inscription ont souvent besoin de ce genre d’outils afin de securiser les serveurs. l’idée est de generer une image contenant un texte, et de le comparer à une valeur saisie par l’utilisateur.
Il est en effet très difficile de faire un script capable de passer ce genre de securité simple à mettre en oeuvre.
Voici un exemple d’image générée par notre programme :
Voici le principe de fonctionnement :
Pour fonctionner l’application est composée de :
Mon exemple tourne actuellement sur une architécture TomCat 5.5.7, JDK 5.0.
1) Le code de ma servlet :
/* * Created on 28 mars 2005 * */
package com.utils.dynimage;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.util.*;
import java.awt.*;
import java.io.*;
import java.awt.image.*;
import java.awt.font.*;
import javax.imageio.*;
import java.awt.geom.*;
/** * @author Eric * */
public class GetDynImage extends HttpServlet {
public void init() throws ServletException {
//System.out.println("Servlet started");
}
public void destroy() {
//System.out.println("Servlet is stopping now");
}
protected void doPost(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
doGet(arg0, arg1);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String text = getRandomText();
// Sauvegarde de la string en session
HttpSession session = request.getSession(true);
session.setAttribute("dynImageTxt", text);
String font_file = getServletContext().getRealPath ("WEB-INF/ttf/acmesa.ttf" );
float size = 50.0f;
Color background = Color.white;
Color color = Color.black;
try {
Font font = Font.createFont(Font.TRUETYPE_FONT, new FileInputStream(font_file));
font = font.deriveFont(size);
BufferedImage buffer = new BufferedImage(1,1,BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = buffer.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
FontRenderContext fc = g2.getFontRenderContext();
Rectangle2D bounds = font.getStringBounds(text,fc);
// Calcul de la taille du texte
int width = (int) bounds.getWidth();
int height = (int) bounds.getHeight();
// Preparation de la sortie
buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
g2 = buffer.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setFont(font);
g2.drawString(text,0,(int)-bounds.getY());
// Set content type et get de l'output stream
response.setContentType("image/jpeg");
OutputStream os = response.getOutputStream();
// Output en PNG de l'image
ImageIO.write(buffer, "jpg", os);
os.close();
} catch (Exception e) {
// Traitement Erreur
}
}
/***
*
* Method used to get a random UpperCase text of 5 letters.
*
* @return String text.
*/
private String getRandomText () {
// Génération d'un texte aléatoire
int length = 5;
char[] array = new char[ length ];
char[] chars = new char[26];
//for (int i = 0; i < 26; i ++) {chars[i] = (char) (97 + i);chars[i + 26] = (char) (65 + i);}
// Creation d'une table avec les majuscules de l'alphabet.
for (int i = 0; i < 26; i ++) {
chars[i] = (char) (97 + i);
}
Random random = new Random ();
for (int i = 0; i < length; i ++) {
array[i] = chars[random.nextInt (chars.length)];
}
// Parametres par défaut
return new String (array);
}
}
2) La vérification de la valeur :
// Lecture de la session, de l'attribut captcha
HttpSession session = request.getSession(true);
String value = (String) session.getAttribute("dynImageTxt");
// lecture de la valeur du champs nommé imgValue du formulaire de saisie.
String formValue = request.getParameter("imgValue");
if (formValue.toLowerCase().equals(value.toLowerCase())) {
// Valeur exacte !!!!
} else {
// Valeur fausse !!!!
}
Attention : Si votre serveur est positionné derriere un load-balancer, vous devez prendre garde à le configurer de sorte que l’utilisateur tombe systématiquement sur la même machine, dans le cas contraire, la valeur en session ne correspondrait a rien.
Bonjour,
J’aurai une question,
J’ai 4 serveurs load-balancer. Je souhaitre integrer un Captcha. Je ne peux malheureusement pas utiliser de session.
Comment puis-je faire pour implementer un CAPTCHA, sachant que je ne sais pas sur quel serveur va aller ma requete.
Merci
Il faut utiliser les sitcky session avec le load balancer, c’est le seul moyen d’etre sur que vos utilisateurs vont utiliser le meme serveur au fur et à mesure de leurs navigation.
http://www.howtoforge.com/load_balancing_apache_mod_proxy_balancer
Eric