现在大多数网站都采用了验证码来防止暴力破解或恶意提交。但验证码真的就很安全吗?真的就不能被机器识别??
我先讲讲我是怎么实现站外提交留言到一个网站的程序。 这个网站的留言版大致如下: 我一看这种简单的4位数字验证码,马上就感觉到有戏了。直觉告诉我让电脑来识别这些图片验证码据对简单o(∩_∩)o... 首先我马上在这个页面用右键菜单看源代码 知道验证码获取页面后 你可以直接用 http://www.XXXX.com/imgchk/validatecode.asp 这样去访问你会发现你打开的就是一个验证码图片。 对的其实返回的就是图片文件的2进制流而已。接着先用右键保存一张验证码的图片。因为要开始分析这张图片了,什么用什么工具?PhotoShop????不用就一般的画图工具就可以了。我们要搞清楚的是这几个数字分别占几个像素就可以了。 可以看出 一个数字5*9
也就是45个像素。恩 这就可以了 另外我们可以看出默认区域就是白色 (姑且说是白色因为我们肉眼看就是白色) 那么我的程序识别原理就是固定去扫描这45个像素点。看每个点的颜色是不是和默认的颜色一致 一致的话就标记为0 ,不一致就标记为1 。 如一个数子是2 那么我的程序扫描出来的图像就应该是: 011110 100001 000001 000001 000010 000100 001000 010000 100000 111111 如果一个数字是7那么扫描出来的图像就是: 111111 100001 000010 000010 000100 000100 001000 001000 010000 010000 恩,就这么简单呵呵。下面给出图像 扫描的java类 (不好意思,在我会的语言里面除开java就剩sql了) package com.util; // ~--- JDK imports ------------------------------------------------------------ import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGEncodeParam; import com.sun.image.codec.jpeg.JPEGImageEncoder; import java.awt. * ; import java.awt.image. * ; import java.io. * ; import java.io.FileOutputStream; import java.io.OutputStream; import java.net. * ; import javax.imageio. * ; import javax.imageio.ImageIO; public class ImgIdent { // 数字字符比特表 private final long [][] NUMERIC = { { 512104545 , 562436190 } , // '0' { 148931080 , 136348222 } , // '1' { 511971394 , 69273663 } , // '2' { 511971406 , 17045598 } , // '3' { 35168914 , 586948743 } , // '4' { 1065486398 , 17045598 } , // '5' { 239208494 , 830871646 } , // '6' { 1065623684 , 69239824 } , // '7' { 512104542 , 562436190 } , // '8' { 512104547 , 486805660 } } ; // '9' // 字框高 private int intCharHeight = 10 ; // 字框横向间隙 private int intCharSpaceH = 5 ; // 字框纵向间隙 private int intCharSpaceY = 1 ; // 字框宽 private int intCharWidth = 5 ; private int IntImgHeight; private BufferedImage img; private int intBgColor; private int intCharColor; private int intImgWith; private int intMaxX; private int intMaxY; private int intMinX; private int intMinY; // 座标原点 private Point pOrigin; private String strNum; public ImgIdent(BufferedImage img) throws IOException { this .img = img; init(); } public ImgIdent(File file) throws IOException { img = ImageIO.read(file); init(); } public ImgIdent(URL url) throws IOException { img = ImageIO.read(url); init(); } private void init() { // 得到图象的长度和宽度 intImgWith = img.getWidth(); IntImgHeight = img.getHeight(); // 得到图象的背景颜色 intBgColor = img.getRGB( 7 , 4 ); // System.out.println(intBgColor); // 初始化图象原点座标 pOrigin = new Point( 0 , 0 ); } private void getBaseInfo() { System.out.println(intBgColor + " | " + intCharColor); System.out.println(intMinX + " | " + intMinY + " | " + intMaxX + " | " + intMaxY); } private Point[] getCharRange( int intNo) { // 左上右下点座标 Point pTopLeft = new Point( 0 , 0 ); Point pBottomRight = new Point( 0 , 0 ); // 左上点 pTopLeft.x = pOrigin.x + intCharWidth * (intNo - 1 ) + intCharSpaceH * (intNo - 1 ); pTopLeft.y = pOrigin.y; // 右下点 pBottomRight.x = 1 + pOrigin.x + intCharWidth * intNo + intCharSpaceH * (intNo - 1 ) - 1 ; pBottomRight.y = pOrigin.y + intCharHeight - 1 ; return new Point[] { pTopLeft, pBottomRight } ; } private char getBit( int x, int y) { int intCurtColor; intCurtColor = img.getRGB(x, y); // System.out.println("[" + x + "," + y + "]" + intCurtColor + "==" + intBgColor + "==>" + (Math.abs(intCurtColor) >7308252)); // return (Math.abs(intCurtColor) >= 5689325) // ? '0' // : '1'; return (intCurtColor == intBgColor) ? ' 0 ' : ' 1 ' ; // 5689325 6008535 } private String getCharString( int intNo) { // 本字符的左上右下点座标 Point[] p = getCharRange(intNo); Point pTopLeft = p[ 0 ]; Point pBottomRight = p[ 1 ]; // 换算边界值 int intX1, intY1, intX2, intY2; intX1 = pTopLeft.x; intY1 = pTopLeft.y; intX2 = pBottomRight.x; intY2 = pBottomRight.y; // System.out.println("intX1=" + intX1); // System.out.println("intY1=" + intY1); // System.out.println("intX2=" + intX2); // System.out.println("intY2=" + intY2); // 在边界内循环取象素 int i, j; String strChar = "" ; for (i = intY1; i <= intY2; i ++ ) { for (j = intX1; j <= intX2; j ++ ) { System.out.print(getBit(j, i)); strChar = strChar + getBit(j, i); } System.out.println(); } System.out.println(); return strChar; } public int getNum( int intNo) { // 取得位字符串 String strChar = getCharString(intNo); // System.out.println(intNo+"=="+strChar); // 取得串高位串和低位串 String strCharHigh = strChar.substring( 0 , strChar.length() / 2 ); String strCharLow = strChar.substring(strChar.length() / 2 ); // 计算高位和低位值 long lCharHigh = Long.parseLong(strCharHigh, 2 ); System.out.println(lCharHigh); long lCharLow = Long.parseLong(strCharLow, 2 ); System.out.println(lCharLow); // 在数字中循环比较 int intNum = ' * ' ; for ( int i = 0 ; i <= 9 ; i ++ ) { if ((lCharHigh == NUMERIC[i][ 0 ]) && (lCharLow == NUMERIC[i][ 1 ])) { intNum = i; break ; } else { if ((lCharHigh == 834533329 ) && (lCharLow == 242870177 )) { intNum = 6 ; } // 834533329 242870177 else { intNum = 1 ; } // 默认为1 低位为 937393609 937393601 } } return intNum; } public String getValidatecode( int length) { String strNum = "" ; for ( int i = 1 ; i <= length; i ++ ) { synchronized ( this ) { strNum += String.valueOf(getNum(i)); } } return strNum; } public void saveJPEG(BufferedImage iag, String savePath) throws FileNotFoundException, IOException { OutputStream jos = new FileOutputStream(savePath); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(jos); JPEGEncodeParam jpegEP = JPEGCodec.getDefaultJPEGEncodeParam(iag); jpegEP.setQuality(( float ) 1 , true ); encoder.encode(iag, jpegEP); jos.flush(); jos.close(); } } package com.util; // ~--- non-JDK imports -------------------------------------------------------- import org.apache.commons.httpclient. * ; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.params.HttpClientParams; import org.apache.commons.httpclient.params.HttpMethodParams; // ~--- JDK imports ------------------------------------------------------------ import java.awt.image.BufferedImage; import java.io.InputStream; import javax.imageio.ImageIO; public class MyHttpClient { public synchronized void doSomeThing(String title, String name, String Content, String proIP, int port, boolean usePro) { // 构造HttpClient的实例 HttpClient httpClient = new HttpClient(); HttpClientParams clientParams = new HttpClientParams(); // 隐藏自己请求相关的信息 clientParams.setParameter( " http.useragent " , " Mozilla/4.0 (compatible; FIREFOX 9.0; IBM AIX 5) " ); // httpClient.getHttpConnectionManager().getParams().setSoTimeout(30 * 1000); clientParams.setHttpElementCharset( " GBK " ); HttpState httpState = new HttpState(); httpClient.setParams(clientParams); httpClient.getParams().setParameter(HttpClientParams.HTTP_CONTENT_CHARSET, " GBK " ); httpClient.setState(httpState); clientParams.setVersion(HttpVersion.HTTP_1_1); // httpClient.getHostConfiguration().setProxy("148.233.159.58", 3128); if (usePro) // 使用代理 { httpClient.getHostConfiguration().setProxy(proIP, port); } // 创建GET方法的实例 GetMethod getMethod = new GetMethod( " http://www.XXXcom/Guestbook/imgchk/validatecode.asp " ); // 使用系统提供的默认的恢复策略 getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler()); try { // 执行getMethod int statusCode = httpClient.executeMethod(getMethod); // System.out.println(statusCode); if (statusCode != HttpStatus.SC_OK) { System.err.println( " Method failed: " + getMethod.getStatusLine()); } // 读取内容 InputStream inStream = getMethod.getResponseBodyAsStream(); // 处理内容 // System.out.println(new String(responseBody)); BufferedImage iag = ImageIO.read(inStream); ImgIdent imgIdent = new ImgIdent(iag); // imgIdent.saveJPEG(iag, "C:/ddd.jpg"); String validate = imgIdent.getValidatecode( 4 ); System.out.println(validate); PostMethod method = new PostMethod( " http://www.XXX.com/Guestbook/add_msg.asp " ); String connect = Content; String Title = title; method.setParameter( " subject " , Title); method.setParameter( " g_name " , name); method.setParameter( " companyname " , "" ); method.setParameter( " mail " , "" ); method.setParameter( " homepageurl " , " http:// " ); method.setParameter( " pic " , " p5.gif " ); method.setParameter( " validatecode " , validate); method.setParameter( " content " , connect); // if (todo) { int code = httpClient.executeMethod(method); // String Stringresponse = new String(method.getResponseBodyAsString().getBytes("8859_1")); // 打印返回的信息 // System.out.println(Stringresponse); // } method.releaseConnection(); // System.out.println(iag.getHeight()); // System.out.println(iag.getWidth()); // // 背景 颜色 // intBgColor = iag.getRGB(38, 0); // System.out.println("intBgColor=" + intBgColor); // // // intBgColor = iag.getRGB(0, 0); // System.out.println("intBgColor=" + intBgColor); } catch (Exception e) { // 发生网络异常 e.printStackTrace(); } finally {} // 释放连接 getMethod.releaseConnection(); } getMethod.releaseConnection(); } } |