如何正确对用户密码进行加密(原创)

后端 置顶 2 1883
猿站
猿站 一个月前     PHP

今天来说一下如何对用户的密码进行正确的加密,如何才能够保证密码的安全性,提高网站数据的安全

一、首先建表的时候需要有 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 目的就是更加安全,这样用户每次登录的密码都是完全唯一的,想破解的话则是难上加难了

    好了,本篇文章到这里也就结束了,可能本篇文章 有讲的不对或者不到位的地方,还望谅解,本篇文章仅供参考

转载请注明来源:

回帖