实现图片验证码,其实就是简单的验证码实现,记录一下
今天一個小網站被黑了,本來就是一個臨時做了一兩天的小網站,因為不需要登陸,所以只是在后臺加入了一個ip過濾,沒想那么復雜。但是持續(xù)被黑,經過將近一個上午的修改,終于暫時避免被黑。
1、首先昨天被黑,想到的是ip過濾機制出現(xiàn)了問題,查看數(shù)據(jù)庫,果然發(fā)現(xiàn)ip不對勁,它是一個真實ip加上了一個隨機生成的數(shù)字,我看可能是他模擬了ip,把這個真實ip過濾掉了。相安無事。
2、今天上午又被黑了,發(fā)現(xiàn)他可以模擬ip,沒有規(guī)律可查,所以想到了使用驗證碼,首先是生成一個隨機數(shù)存放在cookie中,1分鐘后又被黑掉。
3、把隨機驗證碼存放在session中,2分鐘后被黑掉。
4、把隨機驗證生成圖片,然后數(shù)字存放在session中。2分鐘后又被黑掉了。
5、查看后臺日志,發(fā)現(xiàn)程序本身是存在bug的,因為黑網站的人并不是通過瀏覽器訪問,而是通過程序實現(xiàn)的,所以程序修改了下。暫時沒有被黑了。
下面是我實現(xiàn)的,漏洞肯定還是有的。只是我不知道罷了。
一個驗證碼生成器:
public class Scaptcha {
?? ?// 圖片的寬度。
?? ?private int width = 120;
?? ?// 圖片的高度。
?? ?private int height = 40;
?? ?// 驗證碼字符個數(shù)
?? ?private int codeCount = 4;
?? ?// 驗證碼干擾線數(shù)
?? ?private int lineCount = 50;
?? ?// 驗證碼
?? ?private String code = null;
?? ?// 驗證碼圖片Buffer
?? ?private BufferedImage buffImg = null;
?? ?private char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
?? ??? ??? ?'I', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
?? ??? ??? ?'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9' };
?? ?// 生成隨機數(shù)
?? ?private Random random = new Random();
?? ?public Scaptcha() {
?? ??? ?this.createCode();
?? ?}
?? ?/**
?? ? *
?? ? * @param width
?? ? *??????????? 圖片寬
?? ? * @param height
?? ? *??????????? 圖片高
?? ? */
?? ?public Scaptcha(int width, int height) {
?? ??? ?this.width = width;
?? ??? ?this.height = height;
?? ??? ?this.createCode();
?? ?}
?? ?/**
?? ? *
?? ? * @param width
?? ? *??????????? 圖片寬
?? ? * @param height
?? ? *??????????? 圖片高
?? ? * @param codeCount
?? ? *??????????? 字符個數(shù)
?? ? * @param lineCount
?? ? *??????????? 干擾線條數(shù)
?? ? */
?? ?public Scaptcha(int width, int height, int codeCount, int lineCount) {
?? ??? ?this.width = width;
?? ??? ?this.height = height;
?? ??? ?this.codeCount = codeCount;
?? ??? ?this.lineCount = lineCount;
?? ??? ?this.createCode();
?? ?}
?? ?public void createCode() {
?? ??? ?int codeX = 0;
?? ??? ?int fontHeight = 0;
?? ??? ?fontHeight = height - 5;// 字體的高度
?? ??? ?codeX = width / (codeCount+3);// 每個字符的寬度
?? ??? ?// 圖像buffer
?? ??? ?buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
?? ??? ?Graphics2D g = buffImg.createGraphics();
?? ??? ?// 將圖像填充為白色
?? ??? ?g.setColor(Color.WHITE);
?? ??? ?g.fillRect(0, 0, width, height);
?? ??? ?// 創(chuàng)建字體
?? ??? ?ImgFontByte imgFont = new ImgFontByte();
?? ??? ?Font font = imgFont.getFont(fontHeight);
?? ??? ?g.setFont(font);
?? ??? ?// 繪制干擾線
?? ??? ?for (int i = 0; i < lineCount; i++) {
?? ??? ??? ?int xs = getRandomNumber(width);
?? ??? ??? ?int ys = getRandomNumber(height);
?? ??? ??? ?int xe = xs + getRandomNumber(width / 8);
?? ??? ??? ?int ye = ys + getRandomNumber(height / 8);
?? ??? ??? ?g.setColor(getRandomColor());
?? ??? ??? ?g.drawLine(xs, ys, xe, ye);
?? ??? ?}
?? ??? ?StringBuffer randomCode = new StringBuffer();
?? ??? ?// 隨機產生驗證碼字符
?? ??? ?for (int i = 0; i < codeCount; i++) {
?? ??? ??? ?String strRand = String.valueOf(codeSequence[random
?? ??? ??? ??? ??? ?.nextInt(codeSequence.length)]);
?? ??? ??? ?// 設置字體顏色
?? ??? ??? ?g.setColor(getRandomColor());
?? ??? ??? ?// 設置字體位置
?? ??? ??? ?g.drawString(strRand, (i + 1) * codeX,
?? ??? ??? ??? ??? ?getRandomNumber(height / 2) + 25);
?? ??? ??? ?randomCode.append(strRand);
?? ??? ?}
?? ??? ?code = randomCode.toString();
?? ?}
?? ?/** 獲取隨機顏色 */
?? ?private Color getRandomColor() {
?? ??? ?int r = getRandomNumber(255);
?? ??? ?int g = getRandomNumber(255);
?? ??? ?int b = getRandomNumber(255);
?? ??? ?return new Color(r, g, b);
?? ?}
?? ?/** 獲取隨機數(shù) */
?? ?private int getRandomNumber(int number) {
?? ??? ?return random.nextInt(number);
?? ?}
?? ?public void write(String path) throws IOException {
?? ??? ?OutputStream sos = new FileOutputStream(path);
?? ??? ?this.write(sos);
?? ?}
?? ?public void write(OutputStream sos) throws IOException {
?? ??? ?ImageIO.write(buffImg, "png", sos);
?? ??? ?sos.close();
?? ?}
?? ?public BufferedImage getBuffImg() {
?? ??? ?return buffImg;
?? ?}
?? ?public String getCode() {
?? ??? ?return code;
?? ?}
?? ?/** 字體樣式類 */
?? ?class ImgFontByte {
?? ??? ?public Font getFont(int fontHeight) {
?? ??? ??? ?try {
?? ??? ??? ??? ?Font baseFont = Font.createFont(Font.TRUETYPE_FONT,
?? ??? ??? ??? ??? ??? ?new ByteArrayInputStream(hex2byte(getFontByteStr())));
?? ??? ??? ??? ?return baseFont.deriveFont(Font.PLAIN, fontHeight);
?? ??? ??? ?} catch (Exception e) {
?? ??? ??? ??? ?return new Font("Arial", Font.PLAIN, fontHeight);
?? ??? ??? ?}
?? ??? ?}
?? ??? ?private byte[] hex2byte(String str) {
?? ??? ??? ?if (str == null)
?? ??? ??? ??? ?return null;
?? ??? ??? ?str = str.trim();
?? ??? ??? ?int len = str.length();
?? ??? ??? ?if (len == 0 || len % 2 == 1)
?? ??? ??? ??? ?return null;
?? ??? ??? ?byte[] b = new byte[len / 2];
?? ??? ??? ?try {
?? ??? ??? ??? ?for (int i = 0; i < str.length(); i += 2) {
?? ??? ??? ??? ??? ?b[i / 2] = (byte) Integer.decode(
?? ??? ??? ??? ??? ??? ??? ?"0x" + str.substring(i, i + 2)).intValue();
?? ??? ??? ??? ?}
?? ??? ??? ??? ?return b;
?? ??? ??? ?} catch (Exception e) {
?? ??? ??? ??? ?return null;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?// 字體文件的十六進制字符串
?? ??? ?private String getFontByteStr() {
?? ??? ??? ?return "字段很長,就不放進來了";
?? ??? ?}
?? ?}
}
然后是生成驗證碼的servlet
public synchronized void doPost(HttpServletRequest request, HttpServletResponse response)
?? ??? ??? ?throws ServletException, IOException {
?? ??? ?response.setCharacterEncoding("UTF-8");
?? ??? ?ArticleDao articleDao = new ArticleDao();
?? ??? ?// 組裝圖片的路徑
?? ??? ?Scaptcha instance = new Scaptcha();
?? ??? ?/*Cookie cookie = new Cookie("scaptcha", instance.getCode());
?? ??? ?cookie.setMaxAge(1800);
?? ??? ?response.addCookie(cookie);
?? ??? ?String code=instance.getCode();*/
?? ??? ?String code=instance.getCode();
?? ??? ?request.getSession().setAttribute("scaptcha", code);
?? ??? ?System.out.println(code);
?? ??? ?String temp=request.getRealPath("/upload");
?? ??? ?instance.write(temp+"//ss.jpg");
?? ??? ?final String bitmapUrl = "upload/upload/";
?? ??? ?List<Article> articles= articleDao.findArticleAll();
?? ??? ?for(int i = 0 ; i<articles.size() ; i++){
?? ??? ??? ?String bitmap = bitmapUrl+articles.get(i).getPhotoUrl();
?? ??? ??? ?articles.get(i).setPhotoUrl(bitmap);
//?? ??? ??? ?System.out.println("圖片路徑?????????????????????????????????????????? "+bitmap);
?? ??? ??? ?
?? ??? ?}
?? ??? ?request.setAttribute("articles", articles);
?? ??? ?request.getRequestDispatcher("/jsp/many_vote.jsp").forward(request, response);
?? ?}
最后是驗證的servlet
public void doPost(HttpServletRequest request, HttpServletResponse response)
?? ??? ??? ?throws ServletException, IOException {
?? ??? ?response.setCharacterEncoding("UTF-8");
?? ??? ?PrintWriter out = response.getWriter();
?? ??? ?ArticleDao articleDao = new ArticleDao();
?? ??? ?// 多個投票的id
?? ??? ?String[] many_vote = request.getParameterValues("article_vote");
?? ??? ?String scaptcha=request.getParameter("scaptcha").toUpperCase();
?? ??? ?String scaptchaC="";
?? ??? ?String code=(String) request.getSession().getAttribute("scaptcha");
?? ??? ?if(code==null){
?? ??? ??? ?scaptchaC="";
?? ??? ?}else{
?? ??? ??? ?scaptchaC=code;
?? ??? ?}
?? ??? ?// 獲取ip
?? ??? ?// String ip = request.getRemoteAddr();
?? ??? ?// String ip = InetAddress.getLocalHost().getHostAddress();
?? ??? ?String ip = request.getHeader("x-forwarded-for");
?? ??? ?if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
?? ??? ??? ?ip = request.getHeader("Proxy-Client-IP");
?? ??? ?}
?? ??? ?if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
?? ??? ??? ?ip = request.getHeader("WL-Proxy-Client-IP");
?? ??? ?}
?? ??? ?if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
?? ??? ??? ?ip = request.getRemoteAddr();
?? ??? ?}
?? ??? ?if(scaptcha.equals("")||scaptcha==null){
?? ??? ??? ?System.out.println("scaptcha是空的");
?? ??? ??? ?
?? ??? ??? ?out.print("<script type='text/javascript'>alert('請輸入驗證碼...!');location.href='"
?? ??? ??? ??? ??? ?+ request.getContextPath() + "/index.jsp';</script>");
?? ??? ?}else{
?? ??? ??? ?if(!scaptcha.equals(scaptchaC)){
?? ??? ??? ??? ?out.print("<script type='text/javascript'>alert('該驗證碼不匹配...!');location.href='"
?? ??? ??? ??? ??? ??? ?+ request.getContextPath() + "/index.jsp';</script>");
?? ??? ??? ?}
?? ??? ??? ?if (many_vote != null && many_vote.length == 20) {
?? ??? ??? ??? ?
?? ??? ??? ??? ?//判斷ip是否為空
?? ??? ??? ??? ?if(ip!=null && !ip.equals("") && !ip.contains(",") && interapt(ip)){
?? ??? ??? ??? ??? ?// 判斷ip是否重復
?? ??? ??? ??? ??? ?if (articleDao.isIpRepetition(ip)) {
?? ??? ??? ??? ??? ??? ?out.print("<script type='text/javascript'>alert('此ip已經參加投票...!');location.href='"
?? ??? ??? ??? ??? ??? ??? ??? ?+ request.getContextPath() + "/index.jsp';</script>");
?? ??? ??? ??? ??? ?} else {
?? ??? ??? ??? ??? ??? ?// 循環(huán)插入
?? ??? ??? ??? ??? ??? ?for (int i = 0; i < many_vote.length; i++) {
?? ??? ??? ??? ??? ??? ??? ?articleDao.voteAdd(ip, many_vote[i]);
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ?out.print("<script type='text/javascript'>alert('投票成功...!');location.href='"
?? ??? ??? ??? ??? ??? ??? ??? ?+ request.getContextPath() + "/index.jsp';</script>");
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}else{
?? ??? ??? ??? ??? ?out.print("<script type='text/javascript'>alert('系統(tǒng)繁忙,請稍后投票...!');location.href='"
?? ??? ??? ??? ??? ??? ??? ?+ request.getContextPath() + "/index.jsp';</script>");
?? ??? ??? ??? ?}
?? ??? ??? ??? ?
?? ??? ??? ??? ?
?? ??? ??? ?} else {
?? ??? ??? ??? ?// out.print("<script type='text/javascript'>alert('請檢查投票數(shù)是否達到20人...!');location.href='"
?? ??? ??? ??? ?// + request.getContextPath() + "/index.jsp';</script>");
?? ??? ??? ??? ?out.print("<script type='text/javascript'>alert('請檢查投票數(shù)是否達到20人...!');window.history.back(-1);</script>");
?? ??? ??? ?}
?? ??? ?}
?? ??? ?System.out.println(scaptchaC+"####"+scaptcha);
?? ?}
總結
以上是生活随笔為你收集整理的实现图片验证码,其实就是简单的验证码实现,记录一下的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mappingResources、map
- 下一篇: myeclipse优化