今天来说一下如何对用户的密码进行正确的加密,如何才能够保证密码的安全性,提高网站数据的安全
一、首先建表的时候需要有 password 和 auth_key 这两个字段,
password 是存储密码加密后的字符串
auth_key 是用来对 password 进行二次加密的,具体做法下面会讲解
二、首先讲解添加用户时 对密码的处理方式
/**
* 添加用户操作
* @return mixed
*/
public function addPost() {
$param = input('post.');
$param["auth_key"] = createRandomKey();
$param["password"] = generatePassword(
$param["auth_key"], $param["password"]);
}
如上代码片段 接收到 post过来的数据 首先生成 auth_key 这个 auth_key 方法的具体内容如下
/**
* 生成n位随机数
* @param int $length
* @return string
*/
function createRandomKey($length=32) {
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str ="";
for ( $i = 0; $i < $length; $i++ ) {
$str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
就是生成32位的随机数,
接下来接到用户输入的密码,然后将 auth_key 和 用户输入的 密码 扔到一个叫 generatePassword 的方法里面,具体方法内容如下
/**
* 用户生成密码规则
* @param $authKey
* @param $password
* @return string
*/
function generatePassword($authKey, $password) {
return md5(md5($password).$authKey);
}
我们可以看到 这个方法里面将 传参进来的 password 进行了md5 加密 然后拼接上 auth_key 紧接着进行了二次 md5 加密,这样的做法可以保证网站所有的用户密码是完全唯一的,也就增加了破解难度
那么到这么我们可以看到 用户的密码的安全性已经有很大的提高了,但是验证用户密码的时候怎么办呢。因为密码是完全唯一的,这个时候就用到了 auth_key 在存储用户信息的时候 将 auth_key 和 password 分别存入到数据表的两个字段里,然后接下来讲解 在登录的时候 如何验证
三、登录时验证用户密码
首先登录页面的form 表单中 需要有一个 hidden 隐藏域 :loginKey
至于为什么要加,请往下看
登录按钮不要 将 type="submit" 该为 type="button"
登 录
当用户点击登录的时候出发 js
$(function(){
$("#checkCode").click(function() {
$(this).attr("src", "{:captcha_src()}?t={:time()}");
});
$('#formSubmit').click(function() {
if(common.isNullOrEmpty($('#loginKey').val())){
$.ajax({
url: "{:url('Login/oauthPassword',array('t'=>time()))}", // 加随机数防止缓存
type: "post",
data: {
username: $('#username').val()
},
dataType: "json",
success: function (data) {
if(data.code != 200) {
common.error(data.msg);
return false;
}
$('#loginKey').val(data.key);
$("form#doLogin").submit();
}
});
} else {
common.error("数据错误,请刷新页面重新登录");
}
});
});
js里面 判断 如何 loginKey 为空的话 则 发起 ajax 请求去获取 loginKey
如果不为空的话则表明数据错误,数据错误的发生场景为,点击登录然后 返回 密码错误等错误信息的时候 form表单中的 login_key 可能不会自动清空,但是不判断也可以,因为在重新点击登录的时候会重新赋值login_key
接下来请看 Login/oauthPassword 控制器代码如下
/**
* 获取密码验证码
*/
public function oauthPassword() {
$username = input("post.username");
$data["code"] = 200;
$hasUser = $this->sysAdminService->findAdminForLogin(
$username, $this->platformType);
$loginKey = createRandomKey();
Session::set("_login_key_".$hasUser["id"], $loginKey);
$data["key"] = $loginKey;
echo json_encode($data);
}
如上 createRandomKey 在本篇文章的上文有贴代码段 就是 生成随机的32位字符串
然后存 session 名字为 _login_key_ 连接上 用户的id,内容为 上面生成的 loginKey
然后以json形式返回给前端,前端将login_key 赋值给 hidden 隐藏域
接下来请看控制器对用户登录操作的处理逻辑
//登录操作
public function doLogin() {
$username = input("param.username");
$password = input("param.password");
$loginKey = input("param.loginKey");
if(isNullOrEmpty($loginKey)) {
$this->error("登录失败");
}
$hasUser = $this->sysAdminService->findAdminForLogin(
$username, $this->platformType);
if(empty($hasUser)){
$this->error("用户不存在");
}
$cacheLoginKey = Session::get("_login_key_".$hasUser["id"]);
$generatePassword = md5(generatePassword(
$hasUser["auth_key"], $password).$loginKey);
if($generatePassword != md5($hasUser['password'].$cacheLoginKey)){
$this->error("密码错误");
}
第一步 将关键的三个值获取到了
第二步 判断 loginKey 是否为空 如果为空 则返回错误信息
第三步 根据 用户名去查找用户信息
第四步 判断用户是否存在 如果不存在 则返回错误信息
第五步 读取 刚刚在 oauthPassword 方法中存入的session值
第六步 加密用户输入的密码,加密方法刚刚在文章上面已经讲过了,下面再说一遍吧
1、首先 generatePassword($hasUser['auth_key'], $password) 第一个参数是查出来用户存在数据库的 auth_key, 第二个参数是用户输入的 密码
generatePassword里面又将 用户输入的明文密码进行了md5加密 md5($password) 接下来又连接上了 第一个参数 auth_key : md5($password).$auth_key 最后 进行了二次加密:md5(md5($password).$auth_key)),
2、然后回来 md5(generatePassword($hasUser['auth_key'], $password).$loginKey); 可以看到 又连接上了 密码验证码:loginKey 然后再次进行了 md5加密
第七步 将用户数据库的 password连接上 刚才 session 读取出来的 cacheLoginKey 再次进行md5加密 (在这里说一下 ,其实 cacheLoginKey 和 loginKey 正常来讲是一样的值,但是为什么还要分两个呢。
因为 cacheLoginKey 大家可以仔细看 是用 session存的 并且携带了 每个用户的id 可以更加的确保每个用户的匹配度,其实 不存session 也是可以的。)
然后 判断 $generatePassword 如果不等于 md5($hasUser['password'], $cacheLoginKey) 则返回错误信息:密码错误
最后
为什么要加loginKey 目的就是更加安全,这样用户每次登录的密码都是完全唯一的,想破解的话则是难上加难了
好了,本篇文章到这里也就结束了,可能本篇文章 有讲的不对或者不到位的地方,还望谅解,本篇文章仅供参考