随笔-57  评论-202  文章-17  trackbacks-0
      在网页编程中,经常需要使用到附加码这样的一个东西,防止黑客用程序用穷举法去破解密码。下面是我的一个附加码的Servlet实现。

  1import java.awt.*;
  2import java.awt.image.*;
  3import java.io.*;
  4import java.util.Random;
  5import javax.servlet.*;
  6import javax.servlet.http.*;
  7
  8import com.sun.image.codec.jpeg.*;
  9
 10public class KeyImage extends HttpServlet {
 11
 12  private static final String CONTENT_TYPE = "text/html; charset=GBK";
 13
 14  //Initialize global variables
 15  public void init() throws ServletException {
 16
 17  }

 18
 19  /**
 20   * 随机数生成器
 21   */

 22  private static Random random = new Random();
 23
 24  /**
 25   * 系统所有的字符
 26   */

 27  private static Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
 28
 29  /**
 30   * 排除的一些字体(这些字体会显示不正常)
 31   */

 32  private static java.util.Set excludeFonts = new java.util.HashSet();
 33
 34  static {
 35    excludeFonts.add("Cursor");
 36    excludeFonts.add("Marlett");
 37    excludeFonts.add("Symbol");
 38    excludeFonts.add("Webdings");
 39    excludeFonts.add("Wingdings");
 40    excludeFonts.add("Wingdings 2");
 41  }

 42
 43  /**
 44   * 图片的宽度
 45   */

 46  private static int imageWidth = 90;
 47
 48  /**
 49   * 图片的高度
 50   */

 51  private static int imageHeight = 30;
 52
 53  /**
 54   * 背景颜色
 55   */

 56  private static Color backgroundColor = Color.WHITE;
 57
 58  /**
 59   * 输出的字符数
 60   */

 61  private static int characterNumber = 4;
 62
 63  /**
 64   * 最终附加码的字符串
 65   */

 66  private StringBuffer keyBuf = null;
 67
 68  /**
 69   * 字符的颜色数组
 70   */

 71  private static Color[] colors = new Color[]{Color.BLACK, Color.BLUE,
 72      Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.MAGENTA,
 73      Color.RED}
;
 74
 75  /**
 76   * 获得随机的X值(范围在5到9之间变化)
 77   * @return int
 78   */

 79  private int randomX() {
 80    return random.nextInt(5+ 5;
 81  }

 82
 83  /**
 84   * 获得随机的Y值(范围在20到24之间变化)
 85   * @return int
 86   */

 87  private int randomY() {
 88    return random.nextInt(5+ 20;
 89  }

 90
 91  /**
 92   * 随机产生字符的大小
 93   * @return int 随机字符大小
 94   */

 95  private int randomSize() {
 96    return random.nextInt(5+ 20;
 97  }

 98
 99  /**
100   * 随机产生Font实例
101   * @return Font 随机Font实例
102   */

103  private Font randomFont() {
104    Font font = null;
105
106    if (fonts != null{
107      font = fonts[random.nextInt(fonts.length)];
108      font = font.deriveFont(random.nextInt(3), randomSize());
109    }
 else {
110      font = new Font("Arial Black", Font.PLAIN, 15);
111    }

112
113    while (excludeFonts.contains(font.getName())) {
114      if (fonts != null{
115        font = fonts[random.nextInt(fonts.length)];
116        font = font.deriveFont(random.nextInt(3), randomSize());
117      }
 else {
118        font = new Font("Arial Black", Font.PLAIN, 15);
119      }

120    }

121
122    log("Current Font: " + font.getName() + " Family: " + font.getFamily() + " Font Name: " + font.getFontName());
123
124    return font;
125  }

126
127  /**
128   * 随机生成一个Color实例(除了背景)
129   * @return Color 随机Color实例
130   */

131  private Color randomColor() {
132    int index = random.nextInt(colors.length);
133    log("Color index is: " + index);
134
135    return colors[index];
136  }

137
138  /**
139   * 写入一个字符
140   * @param g Graphics
141   * @param x int
142   * @param y int
143   */

144  private void drawCharacter(Graphics g, int x, int y) {
145    int ri = (int) (Math.random() * 10);    // 随机生成的数字
146    keyBuf.append(ri);
147    g.setColor(randomColor());
148    g.setFont(randomFont());
149    g.drawString(String.valueOf(ri), x, y);
150  }

151
152  /**
153   * 绘制背景
154   * @param g Graphics
155   * @param color Color
156   * @param x int
157   * @param y int
158   * @param width int
159   * @param height int
160   */

161  private void drawBackground(Graphics g, Color color, int x, int y, int width,
162                              int height) {
163    g.setColor(color);
164    g.fillRect(x, y, width, height);
165  }

166
167  /**
168   * 绘制干扰点,干扰线
169   * @param g Graphics
170   * @param width int
171   * @param height int
172   */

173  private void drawInterrupt(Graphics g, int width, int height) {
174    int numbers = random.nextInt(100+ 50;    // 50到149个干扰点
175    g.setColor(Color.BLACK);
176
177    for (int i = 0; i < numbers; i++{
178      g.fillRect(random.nextInt(width), random.nextInt(height), 11);
179    }

180
181    g.drawLine(0, random.nextInt(height), width, random.nextInt(height));
182  }

183
184  /**
185   * Process the HTTP Get request
186   * 随机生成数字的策略:
187   * 1.随机渐变色(包括文字和背景,暂时不实现)
188   * 2.所有可打印字符(这里暂时用数字)
189   * 3.字符大小随机变化
190   * 4.位置不固定
191   * 5.象素行或列随机错位
192   * @param request HttpServletRequest
193   * @param response HttpServletResponse
194   * @throws ServletException
195   * @throws IOException
196   */

197  public void doGet(HttpServletRequest request, HttpServletResponse response)
198      throws ServletException, IOException {
199
200    BufferedImage image = new BufferedImage(imageWidth, imageHeight,
201                                            BufferedImage.TYPE_INT_RGB);
202    Graphics g = image.getGraphics();
203
204    drawBackground(g, backgroundColor, 00, imageWidth, imageHeight);
205
206    keyBuf = new StringBuffer();
207    int offset = 0;   // 偏移量
208    for (int i = 0; i < characterNumber; i++{
209      drawCharacter(g, randomX() + offset, randomY());
210      offset += imageWidth / characterNumber;
211    }

212
213    drawInterrupt(g, imageWidth, imageHeight);
214
215    response.setHeader("Cache-Control""no-store");
216    response.setDateHeader("Expires"0);
217    response.setContentType("image/jpeg");
218
219    ServletOutputStream out = response.getOutputStream();
220
221    JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
222    encoder.encode(image);
223    out.close();
224
225    // 保存附加码
226    request.getSession().setAttribute("_key", keyBuf.toString());
227    log("The addtional code is: " + keyBuf.toString());
228  }

229
230  //Clean up resources
231  public void destroy() {
232  }

233
234  /**
235   * 改写服务器日志的输出
236   * @param msg String 要输出的信息
237   */

238  public void log(String msg) {
239    super.log(msg);
240  }

241
242  /**
243   * 改写服务器日志的输出
244   * @param message String 要输出的信息
245   * @param t Throwable 抛出的意外
246   */

247  public void log(String message, Throwable t) {
248    t.printStackTrace(System.out);
249    super.log(message, t);
250  }

251}

      附加码的效果图:
adcode.JPG
posted on 2005-05-12 15:33 小米 阅读(1408) 评论(4)  编辑  收藏 所属分类: Java

评论:
# re: 我的网页附加码实现 2008-08-22 12:07 | hjhgj
hgjhg  回复  更多评论
  
# 呵呵[未登录] 2008-12-11 09:56 | 呵呵
忿忿地说  回复  更多评论
  
# re: 我的网页附加码实现 2009-10-23 20:00 | 44
01  回复  更多评论
  
# re: 我的网页附加码实现 2010-04-09 16:26 | cqhongde
这类型附加码识别率应该在95%以上  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: