为了账号安全,请及时绑定邮箱和手机立即绑定

用户登录模块进行必要的安全处理(MD5加密、加盐和传输过程加密)

标签:
MySQL

1、首先简谈一下常规Web登录模块的开发(只为了实现简单的登录功能,未对数据库字段进行加密处理以及传输过程中进行加密处理)

   非安全性登录模块开发

   使用JSP+MYSQL

   数据库表如下所示:

      https://img1.sycdn.imooc.com//5b8b9c340001e7b703610178.jpg

  先用jsp页面创建login.jsp和index.jsp页面(为了方便讲解,直接使用jsp页面传值及校验)具体代码如下所示:

  

复制代码

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录界面</title>
</head>
<body>
<form action="index.jsp" method="post">
    账&nbsp;号:<input type="text" name="username"/><br/>
    密&nbsp;码:<input type="password" name="password"><br/><br/>
        <input type="submit" value="提交"><br/>
</form>
</body>
</html>

复制代码

复制代码

<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>首页</title>
</head>
<body>
<%    //获取mysql连接对象
    String driverClass="com.mysql.jdbc.Driver";
    String user="root";
    String psw="zwkkwz";
    String url="jdbc:mysql://localhost:3306/mytest";
    Class.forName(driverClass);
    Connection conn=DriverManager.getConnection(url,user,psw);    //获取login.jsp传过来的username和password
    String username=request.getParameter("username");
    String password=request.getParameter("password");
    String sql="select * from login where username=?";
    PreparedStatement stmt=conn.prepareStatement(sql);
    stmt.setString(1, username);
    ResultSet rs=stmt.executeQuery();%>
<%    if(rs.next()){
        String p=rs.getString("password");        if(password.equals(p)){
            out.println("用户"+username+"登录成功");
        }else{
            out.println("用户"+username+"登录失败");
        }
    }else{
        out.println("用户"+username+"不存在");
    }%>
</body>
</html>

复制代码

通过上面两个jsp页面进行实现登录页面的,可以实现校验功能。但存在的安全隐患问题太多

  • 数据库以明文的形式进行存储

  • 数据传输的过程中未对数据进行加密处理(可以使用WireShark等抓包工具获取post传递的明文信息

2、接下来针对以上两个问题进行分析和解决:

安全加固1:对数据库表的password字段进行摘要处理(在MYSQL中对数据摘要处理,sql语句如下)

//使用SHA进行摘要处理UPDATE loginset password = SHA(password)//使用MD5进行摘要处理UPDATE userinfo set password = MD5(password)

原来明文123456 经过是用MD5加密后是e10adc3949ba59abbe56e057f20f883e

https://img1.sycdn.imooc.com//5b8b9c3d0001bda005810055.jpg

但是这样子还是不安全,进入http://www.cmd5.com/ 输入加密后的密文进行解密后可以得到明文密码

  • 比如数据库有多个密码的明文是123456,通过MD5加密生成的密文是一模一样的,这样别人解密后就可以获取到其他一样的密码

  • 针对上述问题,我们会进行加盐处理。即在用户注册时随机生成一个规定长度的字段,然后和用户密码相结合,在进行MD5加密,等会再讨论这个问题。

https://img1.sycdn.imooc.com//5b8b9c44000139aa07620193.jpg

 

当对数据库的明文密码进行MD5加密后,我们再来改造一下jsp页面的处理逻辑,对用户输入的密码也进行MD5处理后再校验

  • 写一个工具类DigestUtil,由这个工具类来帮助我们生成用户输入的password对应的MD5

  • 写一个工具类BytesToString,将字节数组转化为字符串

  • 具体代码分别如下,具体过程请读者自己分析代码

复制代码

package util;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;public class DigestUtil {    
    public static String getMD5(byte[] data) throws NoSuchAlgorithmException{
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(data);        byte[] resultBytes = md.digest();
        String resultString = BytesToString.fromBytesToString(resultBytes);        return resultString;
    }    
    public static String getSHA1(byte[] data) throws NoSuchAlgorithmException{
        MessageDigest md = MessageDigest.getInstance("SHA1");
        md.update(data);        byte[] resultBytes = md.digest();
        String resultString = BytesToString.fromBytesToString(resultBytes);        return resultString;
    }

}

复制代码

复制代码

package util;public class BytesToString {    
    public static String fromBytesToString(byte[] resultBytes) {
        StringBuilder builder = new StringBuilder();        for (int i = 0; i < resultBytes.length; i++) {            if (Integer.toHexString(0xFF & resultBytes[i]).length() == 1) {
                builder.append("0").append(
                        Integer.toHexString(0xFF & resultBytes[i]));
            } else {
                builder.append(Integer.toHexString(0xFF & resultBytes[i]));
            }
        }        return builder.toString();
    }

}

复制代码

改造后的index.jsp代码,如下:

复制代码

<%@page import="util.DigestUtil"%>
<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>首页</title>
</head>
<body>
<%    //获取mysql连接对象
    String driverClass="com.mysql.jdbc.Driver";
    String user="root";
    String psw="zwkkwz";
    String url="jdbc:mysql://localhost:3306/mytest";
    Class.forName(driverClass);
    Connection conn=DriverManager.getConnection(url,user,psw);    //获取login.jsp传过来的username和password
    String username=request.getParameter("username");
    String password=request.getParameter("password");
    String sql="select * from login where username=?";
    PreparedStatement stmt=conn.prepareStatement(sql);
    stmt.setString(1, username);
    ResultSet rs=stmt.executeQuery();%>
<%    if(rs.next()){
        String p=rs.getString("password");        //简单的明文校验代码
        /* if(password.equals(p)){
            out.println("用户"+username+"登录成功");
        }else{
            out.println("用户"+username+"登录失败");
        }
    }else{
        out.println("用户"+username+"不存在");
    } */
        //sql使用MD5加密后的密文和用户输入的password校验代码
        if(p.equals(DigestUtil.getMD5(password.getBytes())))            //getMD5(byte[] data)方法是将原始的数据转换成加密后的密文        {
            out.println("数据库password字段"+p);
            out.println("用户输入的password"+password);
            out.println("经过处理后的password"+DigestUtil.getMD5(password.getBytes()));
            out.println("用户"+username+"登录成功");
            
        }else{
            out.println("用户"+username+"登录失败");
        }
        }else{
        out.println("用户"+username+"不存在");
        }%>
</body>
</html>

复制代码

通过以上步骤,我们只对数据库的password明文字段进行了简单的MD5加密,有以下缺点:

  • 容易根据密文位数推测算法,从而使用工具破解

  • 真实密码相同,加密过的密码也相同

接下来我们介绍一下对其进行加盐处理:

3、加盐处理,以此来增强系统的复杂度,再通过摘要处理,就能得到隐蔽性更强的摘要值

  • 将表中的salt字段随意输入abccba,然后和原来的明文密码123456结合,再进行SHA1加密

  • 多建一对数据,将表中的salt字段输入cbaabc,然后和原来的明文密码123456结合,再进行SHA1加密

https://img1.sycdn.imooc.com//5b8b9c4e0001d01306260109.jpg

 

  所谓的salt字段就是一个随机的字段,具体随机算法就不讨论了,每当用户注册账户时,后台就给它随机生成一个不同的字段

  然后根据password和salt字段结合进行摘要处理,存在数据库表中的password字段,这样一来,原来明文都是123456生成的密文就不一样了

 操作如下:

    https://img1.sycdn.imooc.com//5b8b9c540001a0ce05900400.jpg

  得到加密后密文是(原来密码都是123456):

      https://img1.sycdn.imooc.com//5b8b9c5b0001c73507480102.jpg

  接下来改造index.jsp的处理逻辑,对于用户输入的密码进行SHA1处理后的工具类在上面的DigestUtil方法中有列举出

  index.jsp代码如下:

  

复制代码

<%@page import="util.DigestUtil"%>
<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>首页</title>
</head>
<body>
<%    //获取mysql连接对象
    String driverClass="com.mysql.jdbc.Driver";
    String user="root";
    String psw="zwkkwz";
    String url="jdbc:mysql://localhost:3306/mytest";
    Class.forName(driverClass);
    Connection conn=DriverManager.getConnection(url,user,psw);    //获取login.jsp传过来的username和password
    String username=request.getParameter("username");
    String password=request.getParameter("password");
    String sql="select * from login where username=?";
    PreparedStatement stmt=conn.prepareStatement(sql);
    stmt.setString(1, username);
    ResultSet rs=stmt.executeQuery();%>
<%    if(rs.next()){
        String p=rs.getString("password");        //sql使用SHA1进行加盐加密后的密文和用户输入的password校验代码        //我们需要获取到用户输入的密码和对应的salt
        String salt=rs.getString("salt");        if(p.equals(DigestUtil.getSHA1((password+salt).getBytes()))){
                out.println("数据库password字段"+p);
                out.println("用户输入的password"+password);
                out.println("经过处理后的password"+DigestUtil.getSHA1((password+salt).getBytes()));
                out.println("用户"+username+"登录成功");
                
            }else{
                out.println("用户"+username+"登录失败");
            }
        }else{
            out.println("用户"+username+"不存在");
            }    %>
    <%
        rs.close();
        stmt.close();
        conn.close();    %>
</body>
</html>

复制代码

  以上的步骤我们只是对sql进行了加密操作。

     为了防止用户输入密码在传输的过程中被抓包工具获取,我们还要在密码传输的过程中进行加密,这样可以使得获取到的也是密文。

   使用MD5.js对表单加密(可以百度搜索MD5.js下载)

   传输加密:在浏览器端发送出数据之前就要对数据进行加密处理。

   在jsp引入MD5.js;给input标签指定一个id,然后在提交的时候给定一个方法,来对用户输入的密码进行加密,具体的login.jsp如下:

    

复制代码

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录界面</title>
<script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="md5.js"></script>
</head>
<body>
<form action="index.jsp" method="post">
    账&nbsp;号:<input type="text" name="username"/><br/>
    密&nbsp;码:<input type="password" name="password" id="password"><br/><br/>
    
    <input type="submit" value="提交" ="toMd5()"><br/>
</form>
</body>
<script type="text/javascript">
    function toMd5(){
        var passwordNode=document.getElementById("password");        //加密前        alert(passwordNode.value);
        var hash=hex_md5(passwordNode.value);
        passwordNode.value=hash;        //加密后        alert(passwordNode.value);
    }</script>
</html>

复制代码

 原文出处:https://www.cnblogs.com/zwk2018/p/9570408.html


点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消