关于密码安全,一直都是各位开发者所关心的事,对于密码我们都是采用加密处理,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.');
}
<?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);
}
}
}
<?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加密后的密码,使用字典方式很难破解,因为每次生成的密码都是不一样的,破解这种加密只能采用暴力破解。