Blogger Information
Blog 1
fans 0
comment 1
visits 1844
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
如何正确对用户密码进行加密(原创)
猿站的博客
Original
1847 people have browsed it

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

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

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

Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
1 comments
phpcn_u133978 2018-03-12 11:52:56
太棒了
1 floor
Author's latest blog post