关于PHP>=5.5时密码哈希校验的使用案例

关于密码安全,一直都是各位开发者所关心的事,对于密码我们都是采用加密处理,PHP也提供了很多加密函数,如md5()、sha1()等等,但是我们一般不会单纯地对原密码直接进行加密,因为这样虽然加密了,但是强度过低,很容易遭遇不法分子破解。我们比较常用的是使用md5加salt来增强加密后的密码安全性,salt及盐值,这个值要随机生成,可在用户注册的时候和密码一起生成并保存到数据库中,用户登录验证的时候再把密码和盐值一起组合验证。如:md5(md5('php123456').'dsrfere34332'),类似于这样的加密方式,然后存进数据库,需要校验的时候取出来,再把原密码取出来加密与之比较即可,相对复杂的密码加盐处理后破解难度还是很大的。

PHP版本大于等于5.5,系统提供了4个密码哈希处理的函数,内核自带无需安装扩展。分别是password_hash、password_verify、password_get_info、password_needs_rehash。

我们接下来通过面向对象的方式进行使用案例说明:

index.php

<?php    
    require_once "Db.class.php";//引入数据库操作类
    require_once "User.class.php";//用户类
    require_once "db.config.php";//数据库配置文件

    $ac = trim($_GET['ac']);
    if(in_array($ac, get_class_methods('User'))){//判断方法名称是否正确
        $user = new User($host,$user,$pass,$dbname);
        extract($_POST);
        $hash = password_hash($password,PASSWORD_DEFAULT);//创建hash密码,60位长度,默认加密层级为10,根据自己需要可设置,硬件支持,最多为20。
        switch ($ac) {
            case 'login':
                $data = $user->login($hash,$username);
                if(password_verify($password,$data['pass_hash'])){//校验hash密码
                    $info = $user->update_logintime($data['id']);
                    unset($data['pass_hash']);
                    $user->output('200','Login successfully.',$data);
                }else{
                    $user->output('400','Login unsuccessfully.',$data);
                }
                break;
            
            case 'register':
                $id = $user->register($hash,$username);
                $data = ['id' => $id];
                $id ? $user->output('200','Register successfully.',$data) : $user->output('400','Register unsuccessfully.',$data);
                break;
        }
    }else{
        exit('Method invalid.');
    }


Db.class.php文件

<?php
    class Db{
        private $_host;
        private $_user;
        private $_pass;
        private $_data_name;
        private $_conn;
        const CHARSET = 'set names utf8';

        public function __construct($host,$user,$pass,$dbname){
            $this->_host = $host;
            $this->_user = $user;
            $this->_pass = $pass;
            $this->_data_name = $dbname;
            $this->_conn = mysqli_connect($this->_host,$this->_user,$this->_pass,$this->_data_name);
            if(mysqli_connect_errno($this->_conn)){
                exit("connect error:".mysqli_connect_error());
            }
            mysqli_query($this->_conn,self::CHARSET);
        }

        public function insert($sql){//插入语句
            $id = $this->query($sql);
            if($id){
                return mysqli_insert_id($this->_conn);
            }else{
                return false;
            }
        }

        public function select($sql){//查询语句查询多条
            $resource = $this->query($sql);
            if($resource){
                while ($row =  mysqli_fetch_assoc($resource)) {
                    $result[] = $row;
                }
                return $result;
            }else{
                return mysqli_error($this->_conn);
            }
        }

        public function update($sql){//修改语句
            $resource = $this->query($sql);
            if($resource){
                return mysqli_affected_rows($this->_conn);
            }else{
                return false;
            }
        }

        public function find($sql){//查询一条
            $result = $this->select($sql);
            return $result ? $result[0] : [];
        }

        public function query($sql){//执行语句
            $resource = mysqli_query($this->_conn,$sql);
            if($resource){
                return $resource;
            }else{
                return mysqli_error($this->_conn);
            }
        }
    }


User.class.php

<?php
    class User{

        private $_db;

        public function __construct($host,$user,$pass,$dbname){
            $this->_db = new Db($host,$user,$pass,$dbname);
        }

        public function register($pass_hash,$username){//注册
            $sql = "insert into hash_test(pass_hash,username,registertime) value('$pass_hash','$username',NOW())";
            return $this->_db->insert($sql);
        }

        public function login($pass_hash,$username){//登录
            $sql = "select id,pass_hash from hash_test where username = '$username'";
            return $this->_db->find($sql);
        }

        public function update_logintime($id){//修改登录时间
            $sql = "update hash_test set logintime = NOW() where id = $id";
            return $this->_db->update($sql);
        }

        public function output($code,$msg,$datas = []){//自定义接口返回格式
            $outputData = [
                'code' => $code,
                'msg' => $msg, 
                'datas' => $datas 
            ];
            exit(json_encode($outputData));
        }
    }

db.config.php

<?php
    $host = '127.0.0.1';
    $user = 'root';
    $pass = '';
    $dbname = 'password_test';

数据库sql语句

/*
Navicat MySQL Data Transfer

Source Server         : localhost_3306
Source Server Version : 50714
Source Host           : localhost:3306
Source Database       : password_test

Target Server Type    : MYSQL
Target Server Version : 50714
File Encoding         : 65001

Date: 2017-12-28 15:22:05
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for hash_test
-- ----------------------------
DROP TABLE IF EXISTS `hash_test`;
CREATE TABLE `hash_test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `pass_hash` varchar(60) NOT NULL COMMENT '密码哈希值',
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `registertime` datetime NOT NULL COMMENT '注册时间',
  `logintime` datetime DEFAULT NULL COMMENT '登录时间',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=46 DEFAULT CHARSET=utf8;

前台页面展示:

注册界面


登录界面


数据库截图



注册返回:



登录返回:



上述代码首先通过注册填写用户名和密码,对原密码进行哈希处理后存到数据库,登录时再通过用户名获取用户id和哈希密码,如果存在则将注册时加密的密码hash取出来,然后根据原密码的加密处理和数据库里面的哈希密码进行比对;然后使用password_verify()函数验证密码,password_verify()函数有两个参数,第一个参数是纯文本密码,第二个参数是用户数据表中读取出来的密码hash值。如果该函数返回true,说明密码正确,否则,密码错误,终止登录。

通过以上的案例,发现验证密码如此简单,通过password_hash加密后的密码,使用字典方式很难破解,因为每次生成的密码都是不一样的,破解这种加密只能采用暴力破解。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值