面对网络世界,密码安全一直是企业和用户非常关心的内容。毕竟现在人们花钱都是通过网络账户,不管是娱乐、学习还是购物,所以我们通常都会对用户的密码进行加密。在加密的时候,经常会听到“盐”这个词。这是什么意思?我们通常对用户的密码进行哈希处理。如果不加盐,即使是两层的md5也有可能通过彩虹表破译。彩虹表是网上收集的各种字符组合的Hash加密结果。加盐是通过一组随机字符与用户原密码的组合,人为地组成一个新的字符,从而增加破译的难度。就像做菜一样,加少许盐更好吃。接下来,我们演示一种更安全的通过代码加盐的方式。首先,我们创建一个简单的用户表。这张表只有四个字段,这里只做测试用。CREATETABLE`zyblog_test_user`(`id`int(11)NOTNULLAUTO_INCREMENT,`username`varchar(255)COLLATEutf8mb4_binDEFAULTNULLCOMMENT'username',`password`varchar(255)COLLATEutf8mb4_binDEFAULTNULLCOMMENT'password',`salt`char(4)COLLATEutf8mb4_binDEFAULTNULLCOMMENT'salt',PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_bin;然后定义两种方法,一种用于生成salt,一种用于GenerateasaltedHashpassword。/***随机生成四位字符串的salt*也可以根据实际情况使用6位或更长的salt*/functiongenerateSalt(){//随机生成一个四位字符$chars=array_merge(范围('A','Z'),范围('a','z'),范围('0','9'));对于($i=0;$i<4;$i++){$str.=$chars[mt_rand(0,count($chars)-1)];}return$str;}/***密码生成*使用两层hash,第二层加salt*sha1加salt然后md5*/functiongenerateHashPassword($password,$salt){returnmd5(sha1($password).$salt);}generateSalt()方法很简单,就是生成一个随机的四字符字符串,我们用这个字符串以大小写数字的形式生成。这就是传说中的“盐”。接下来,我们可以使用generateHashPassword()方法对用户的原始密码加盐。这里我们先在第一层使用sha1()对原始密码进行一次hash,然后使用这个hash值拼接salt字符串再进行md5()加密。最终加密的Hash值很难在彩虹表中找到。即使找到了,也只是上层sha1()拼接的salt字符串的内容。毕竟用户的原始密码还是有一层加密的。剩下的就是我们进行入站和出站的注册登录测试了。$pdo=newPDO('mysql:host=localhost;dbname=blog_test;charset=utf8mb4','root','');$username='ZyBlog1';$password='123456';//注册函数register($用户名,$密码){全局$pdo;//首先判断用户是否已经注册$pre=$pdo->prepare("SELECTCOUNT(id)FROMzyblog_test_userWHEREusername=:username");$pre->bindParam(':username',$username);$pre->execute();$result=$pre->fetchColumn();//如果用户名存在则无法注册if($result>0){echo'用户名已注册!',PHP_EOL;返回0;}//生成盐$salt=generateSalt();//密码经过加盐和散列$password=generateHashPassword($password,$salt);//插入新用户$pre=$pdo->prepare("insertintozyblog_test_user(username,password,salt)values(?,?,?)");$pre->bindValue(1,$用户名);$pre->bindValue(2,$password);$pre->bindValue(3,$salt);$pre->execute();返回$pdo->lastInsertId();}$userId=register($username,$password);if($userId>0){echo'注册成功!用户ID是:'。$userId,PHP_EOL;}//注册成功!用户ID为:1//查询数据库中的数据$sth=$pdo->prepare("SELECT*FROMzyblog_test_user");$sth->execute();$result=$sth->fetchAll(PDO::FETCH_ASSOC);print_r($result);//数组//(//[0]=>数组//(//[id]=>1//[用户名]=>ZyBlog1//[password]=>bbff8283d0f90625015256b742b0e694//[salt]=>xOkb//)//)//验证函数login($username,$password){global$pdo;//先根据用户名查表$pre=$pdo->prepare("SELECT*FROMzyblog_test_userWHEREusername=:username");$pre->bindParam(':用户名',$用户名);$pre->execute();$result=$pre->fetch(PDO::FETCH_ASSOC);//用户名存在并获取到用户信息后if($result){//根据用户表中的salt字段生成hash密码$password=generateHashPassword($password,$result['salt']);//比较hash密码确认登录成功if($password==$result['password']){returntrue;}}returnfalse;}$isLogin=login($username,$password);if($isLogin){echo'登录成功!',PHP_EOL;}else{echo'登录失败,用户名或密码错误!',PHP_EOL;}//登录成功!代码比较简单。注册时,我们直接将用户密码加密后存入数据库。主要关心的是,在登录的时候,我们先根据用户名找出对应的用户信息。然后对用户提交的登录原始密码进行加密,并与数据库中的原始密码进行比对验证。如果密码验证成功,则可以判断用户登录成功。另外需要注意的是,我们的salt字符串也是保存在数据库中的。毕竟在登录的时候,我们还是需要将用户的原始密码和这个salt字符串结合加密后再进行密码匹配。其实通过彩虹表破解密文基本上是很难的。在几年前的CSDN账号泄露事件中,大家发现这个全球最大的华人程序员网站居然有明文存储的密码,这就为攻击者提供了很多用户常用的明文密码。因为大家都喜欢用相同的用户名和密码注册不同的网站,所以不管加什么其他的盐都没用。毕竟原来的密码是对的。在这样的网站的数据库中得到用户的明文密码后,就可以用这些密码来试试这些用户是否在其他网站上用相同的账号名和密码注册了账号。因此,在日常生活中,我们对于一些重要的网站账号和密码,尽量使用不同的内容。如果记不住,可以使用一些具有加密功能的记事本软件保存,这样会更安全。而我们程序员应该经常对用户密码和重要信息进行加密,这是一个基本的职业规范。测试代码:https://github.com/zhangyue0503/dev-blog/blob/master/php/202003/source/%E4%BB%80%E4%B9%88%E5%8F%AB%E7%BB%99%E5%AF%86%E7%A0%81%E2%80%9C%E5%8A%A0%E7%9B%90%E2%80%9D%EF%BC%9F%E5%A6%82%E4%BD%95%E5%AE%89%E5%85%A8%E7%9A%84%E4%B8%BA%E4%BD%A0%E7%9A%84%E7%94%A8%E6%88%B7%E5%AF%86%E7%A0%81%E2%80%9C%E5%8A%A0%E7%9B%90%E2%80%9D%EF%BC%9F.php各自媒体平台你可以搜索【硬核项目经理】
