前台慢加密实现

流程:

  1. 用户注册:

    输入用户名,密码,确认密码后,点击提交时

    首先生成一份随机盐salt


  2. function encrypt(source, salt) {
    	for (i = 0; i < 100000; i++) {
    		source = $.md5(source + salt);
    	}
    	return source;
    }

    将密码和盐传入,因为要慢加密,所以使密码加密了10W次,大约是0.6秒左右,将加密后的字符串作为密码与用户名和盐一起传到后台

  3. 后台再将密码和盐做一次md5加密,方法可以和前台不同作为密文保存在数据库中

  4. 用户登录时,输入用户名,密码

    在输入完用户名时,ajax请求后台,判断用户名是否存在的同时,将存在的用户名所对应的盐返回给前台

  5. 同步骤2,慢加密密码,

  6. 这时,会重新生成一次盐,同步骤2,再慢加密一次密码,得到第二份慢加密密码,然后将用户名、第一次慢加密密码、第二份盐、第二份慢加密密码传到后台

  7. 后台再将密码和数据库中的盐做一次md5加密,和数据库中的密码比对,一样表示密码正确,同时存入6中的第二份盐和第二份密码,将数据库中的密码和盐更新了。

可以看出再次过程中相当于自动为用户更新了密码。这种方法可以有效的对抗彩虹表这种暴力破解的方式,有效的提高了密码破解难度。

下面是一个实现的demo。

因为最近在学习jfinal,所以这个demo是使用的Jfianl

从底层起,数据库用的mysql,建立一个数据库demo,建立一张表user

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) NOT NULL,
  `password` varchar(32) NOT NULL,
  `tryCount` int(4) NOT NULL,
  `salt` int(4) NOT NULL,
  `regTime` datetime NOT NULL,
  `updateTime` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
)

建立一个Controller

package com.chmin.demo.controller;

import com.chmin.demo.model.User;
import com.chmin.demo.service.UserService;
import com.jfinal.core.Controller;

/**
 * @author chmin
 * @time 2016年2月14日 下午2:21:26
 */
public class UserController extends Controller {

	private UserService userService = new UserService();

	public void index() {
		toLogin();
	}

	/**
	 * 跳转到注册页面
	 */
	public void toReg() {
		renderJsp("reg.jsp");
	}

	/**
	 * 跳转到登陆页面
	 */
	public void toLogin() {
		renderJsp("login.jsp");
	}
	
	/**
	 * 获取用户盐,并验证用户名是否存在
	 */
	public void getSalt(){
		User user = getModel(User.class);
		renderJson(userService.getSalt(user));
	}

	/**
	 * 用户注册
	 */
	public void reg() {
		User user = getModel(User.class);
		renderText(userService.save(user));
	}
	
	/**
	 * 用户登陆
	 */
	public void login() {
		User user = getModel(User.class);
		String newPassword = getPara("newPassword");
		renderText(userService.login(user, newPassword));
	}
}

和一个service

package com.chmin.demo.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.chmin.demo.model.User;
import com.chmin.demo.util.Md5Util;
import com.chmin.demo.util.StringUtil;

/**
 * @author chmin
 * @time 2016年2月14日 下午4:24:08
 */
public class UserService {

	/**
	 * 保存用户
	 * 
	 * @param user
	 * @return
	 */
	public String save(User user) {
		if (user == null) {
			return "系统繁忙,请稍后重试!";
		} else if (StringUtil.isEmpty(user.getUsername())) {
			return "请输入用户名!";
		} else if (StringUtil.isEmpty(user.getPassword())) {
			return "请输入密码!";
		} else if (StringUtil.isEmpty(user.getSalt()+"")) {
			return "系统繁忙,请稍后重试!";
		} else if (User.dao.nameUsed(user.getUsername())) {
			return "用户名已被使用!";
		} else {
			user.setPassword(Md5Util.encrypt(user.getPassword() + user.getSalt()));
			user.setRegTime(new Date());
			user.setTryCount(0);
			return user.save() ? "用户注册成功!" : "系统繁忙,请稍后重试!";
		}
	}
	
	/**
	 * 登陆操作
	 * @param user
	 * @param newPassword
	 * @return
	 */
	public String login(User user, String newPassword){
		User user2 = null;
		if (user == null || StringUtil.isEmpty(user.getUsername())) {
			return "系统繁忙,请稍后重试!";
		} else if ((user2 = User.dao.findFirst("select * from user where username = ?", user.getUsername())) == null){
			return "用户不存在!";
		} else if (user2.getTryCount() >= 5){
			return "用户已被冻结!";
		} else {
			user.setPassword(Md5Util.encrypt(user.getPassword() + user2.getSalt()));
			if(user.getPassword().equals(user2.getPassword())){
				user2.setSalt(user.getSalt());
				user2.setPassword(Md5Util.encrypt(newPassword + user.getSalt()));
				user2.setTryCount(0);
				user2.update();
				return "true";
			} else {
				user2.setTryCount(user2.getTryCount() + 1);
				user2.update();
				return "密码错误!还有" + (5 - user2.getTryCount()) + "次尝试机会!";
			}
		}
	}
	
	/**
	 * 获取用户盐操作
	 * @param user
	 * @return
	 */
	public List<Object> getSalt(User user){
		List<Object> result = new ArrayList<>();
		boolean flag = false;
		String msg = null;
		if (user == null || StringUtil.isEmpty(user.getUsername())) {
			msg = "系统繁忙,请稍后重试!";
		} else if ((user = User.dao.findFirst("select * from user where username = ?", user.getUsername())) == null){
			msg = "用户不存在!";
		} else {
			msg = user.getSalt() + "";
			flag = true;
		}
		System.out.println(msg);
		result.add(flag);
		result.add(msg);
		return result;
	}
}

前台的注册页面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://"
			+ request.getServerName() + ":" + request.getServerPort()
			+ path + "/";
%>

<!DOCTYPE>
<html>
<head>
<base href="<%=basePath%>">
<title>登陆页面</title>
<meta name="pragma" content="no-cache">
<meta name="cache-control" content="no-cache">
<meta name="expires" content="0">
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="RegPage">
<script src="js/jquery-2.1.3.min.js"></script>
<script src="js/jquery.md5.js"></script>
</head>
<body>
	<div style="margin: 300px auto; width: 360px;">
		<form id="reg">
			<div style="width: 360px;">
				<span style="text-align: right; width: 120px; display: inline-block; margin-bottom: 10px;">用户名:</span>
				<input type="text" id="username" name="user.username">
			</div>
			<div style="width: 360px;">
				<span style="text-align: right; width: 120px; display: inline-block; margin-bottom: 10px;">密码:</span>
				<input type="password" id="password" name="user.password">
			</div>
			<div style="width: 360px;">
				<span style="text-align: right; width: 120px; display: inline-block; margin-bottom: 10px;">验证密码:</span>
				<input type="password" id="password2">
			</div>
			<div style="width: 360px;">
				<span style="text-align: right; width: 140px; display: inline-block;"></span>
				<a href="user/toLogin"><input type="button" value="Login"></a>
				<a href="javascript:reg()"><input type="button" value="Register"></a>
			</div>
			<input type="hidden" id="salt" name="user.salt">
		</form>
	</div>
</body>
<script type="text/javascript">
	function reg() {
		var username = $("#username").val().trim();

		if (username.length == 0) {
			alert("用户名不能为空!");
			return;
		}

		var password = $("#password").val().trim();

		if (password.length == 0) {
			alert("密码不能为空!");
			return;
		}

		var password2 = $("#password2").val().trim();

		if (password2.length == 0) {
			alert("密码不能为空!");
			return;
		}

		if (password != password2) {
			alert("两次密码不一致!");
			return;
		}

		var salt = getSalt();

		$("#salt").val(salt);

		$("#password").val(encrypt(password, salt));
		
		$.ajax({
			type: "post",
			data : $("#reg").serialize(),
			url : "user/reg",
			success : function(msg) {
				alert(msg);
				if(msg == "用户注册成功!"){
					window.location.href = "user/toLogin";
				}
			}
		})
	}

	function getSalt() {
		return ~~(Math.random() * 9000 + 1000);
	}

	function encrypt(source, salt) {
		for (i = 0; i < 100000; i++) {
			source = $.md5(source + salt);
		}
		return source;
	}
</script>
</html>

登陆页面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://"
			+ request.getServerName() + ":" + request.getServerPort()
			+ path + "/";
%>

<!DOCTYPE>
<html>
<head>
<base href="<%=basePath%>">
<title>登陆页面</title>
<meta name="pragma" content="no-cache">
<meta name="cache-control" content="no-cache">
<meta name="expires" content="0">
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="RegPage">
<script src="js/jquery-2.1.3.min.js"></script>
<script src="js/jquery.md5.js"></script>
</head>
<body>
	<div style="margin: 300px auto; width: 450px;">
		<form id="login">
			<div style="width: 450px;">
				<span style="text-align: right; width: 120px; display: inline-block; margin-bottom: 10px;">用户名:</span>
				<input type="text" id="username" name="user.username" onblur="javascript:getSalt()"><span style="color: red;" id="usernameError"></span>
			</div>
			<div style="width: 450px;">
				<span style="text-align: right; width: 120px; display: inline-block; margin-bottom: 10px;">密码:</span>
				<input type="password" id="password" name="user.password">
			</div>
			<div style="width: 450px;">
				<span style="text-align: right; width: 140px; display: inline-block;"></span>
				<a href="javascript:login()"><input type="button" value="Login"></a>
				<a href="user/toReg"><input type="button" value="Register"></a>
			</div>
			<input type="hidden" id="salt" name="user.salt">
			<input type="hidden" id="newPassword" name="newPassword">
		</form>
	</div>
</body>
<script type="text/javascript">
	function login(){
		var username = $("#username").val().trim();
		
		if(username.length == 0){
			alert("用户名不能为空!");
			return;
		}
		
		var password = $("#password").val().trim();
		
		if(password.length == 0){
			alert("密码不能为空!");
			return;
		}
		var salt = $("#salt").val();

		$("#password").val(encrypt(password, salt));
		
		salt = ~~(Math.random() * 9000 + 1000);
		
		$("#salt").val(salt);
		
		$("#newPassword").val(encrypt(password, salt));
		
		$.ajax({
			type: "post",
			data : $("#login").serialize(),
			url : "user/login",
			success : function(msg) {
				if(msg){
					window.location.href = "user/toReg";
				} else {
					alert(msg);
				}
			}
		})
	}
	
	function getSalt() {
		$.ajax({
			type: "post",
			data : $("#login").serialize(),
			url : "user/getSalt",
			success : function(msg) {
				if (msg[0]) {
					$("#salt").val(msg[1]);
					$("#usernameError").html("");
				} else {
					$("#salt").val("");
					$("#usernameError").html(msg[1]);
				}
			}
		})
	}
	
	function encrypt(source, salt) {
		for (i = 0; i < 100000; i++) {
			source = $.md5(source + salt);
		}
		return source;
	}
</script>
</html>


转载于:https://my.oschina.net/u/2518412/blog/615211

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值