yii2中关于加密解密的那些事儿


Posted in PHP onJune 12, 2018

前言

Yii提供了方便的帮助函数来让你用一个安全秘钥来加密解密数据。数据通过加密函数进行传输,这样只有拥有安全秘钥的人才能解密。比如,我们需要存储一些信息到我们的数据库中,但是,我们需要保证只有拥有安全秘钥的人才能看到它(即使应用的数据库泄露)。

大家也都知道,我们做程序的时候,加密解密是绕不开的话题,使用yii2开发应用的时候,都内置了哪些有关加密解密(安全)方便的支持那?本文将为你揭晓。

相关环境

  • 操作系统及IDE macOS 10.13.1 & PhpStorm2018.1.2
  • 软件版本 PHP7.1.8 Yii2.0.14

在yii2中,管理加密解密的库叫做Security,它以yii2组件的形式存在,因此你可以通过Yii::$app->security来获取并使用它。

Security组件源代码位置如下

vendor/yiisoft/yii2/base/Security.php

Security组件一共有15个与加密解密(&编码)相关的公共方法,我们先来列一个清单。

  • encryptByPassword
  • encryptByKey
  • decryptByPassword
  • decryptByKey
  • hkdf
  • pbkdf2
  • hashData
  • validateData
  • generateRandomKey
  • generateRandomString
  • generatePasswordHash
  • validatePassword
  • compareString
  • maskToken
  • unmaskToken

我想有一些你一定没见过,没关系,我们一一去了解。

generateRandomString

之所以先说generateRandomString是因为它最常用,起码我是这样。

public function generateRandomString($length = 32){...}

生成一个随机的字符串,参数$length代表这个字符串的长度,默认32位。值得说明的是这个字符串的取值为范围是[A-Za-z0-9_-]。

generatePasswordHash & validatePassword

generatePasswordHash & validatePassword经常被用来加密用户密码以及对密码是否正确的验证,自从MD5可能被碰撞后,我们用yii2开发应用的时候,generatePasswordHash函数对密码进行加密就成为首选了,它调用了crypt函数。

一般用法如下

// 使用generatePasswordHash为用户的密码加密,$hash存储到库中
$hash = Yii::$app->getSecurity()->generatePasswordHash($password);

// 使用validatePassword对密码进行验证
if(Yii::$app->getSecurity()->validatePassword($password, $hash)){
 // 密码正确
}else{
 // 密码错误
}

generateRandomKey

和generateRandomString类似,生成一个随机的串,参数为长度,默认为32位,区别在于generateRandomKey生成的不是ASCII。

简单的说 generateRandomString 约等于 base64_encode(generateRandomKey)。

encryptByPassword & decryptByPassword

编码和解码函数,使用一个秘钥对数据进行编码,然后通过此秘钥在对编码后的数据进行解码。

例子

$dat = Yii::$app->security->encryptByPassword("hello","3166886");
echo Yii::$app->security->encryptByPassword($dat,"3166886");// hello

要注意,通过上面得到的编码后的数据不是ASCII,可以通过base64_encode和base64_decode在外层包装下。

encryptByKey & decryptByKey

同样是一组编码和解码函数,比通过密码的方式要快。函数声明为

public function encryptByKey($data, $inputKey, $info = null){}

public function decryptByKey($data, $inputKey, $info = null){}

encryptByKey & decryptByKey 存在着第三个参数,比如我们可以传递会员的ID等,这样此信息将和$inputKey一起作为加密解密的钥匙。

hkdf

使用标准的 HKDF 算法从给定的输入键中导出一个键。在PHP7+使用的是hash_hkdf方法,小于PHP7使用hash_hmac方法。

pbkdf2

使用标准的 PBKDF2 算法从给定的密码导出一个密钥。该方法可以用来进行密码加密,不过yii2有更好的密码加密方案 generatePasswordHash。

hashData和validateData

有的时候为了防止内容被篡改,我们需要对数据进行一些标记,hashData和validateData就是完成这个任务的组合。

hashData 用来对原始数据进行加数据前缀,比如如下代码

$result = Yii::$app->security->hashData("hello",'123456',false);
// ac28d602c767424d0c809edebf73828bed5ce99ce1556f4df8e223faeec60eddhello

你看到了在hello的前面多了一组字符,这组字符会随着原始数据的不同而变化。这样我们就对数据进行了特殊的防止篡改标记,接下来是validateData上场了。

注意:hashData的第三个参数代表生成的哈希值是否为原始二进制格式. 如果为false, 则会生成小写十六进制数字.

validateData 对已经加了数据前缀的数据进行检测,如下代码

$result = Yii::$app->security->validateData("ac28d602c767424d0c809edebf73828bed5ce99ce1556f4df8e223faeec60eddhello",'123456',false);
// hello

如果返回了原始的字符串则表示验证通过,否则会返回假。

validateData 函数的第三个参数应该与使用  hashData() 生成数据时的值相同. 它指示数据中的散列值是否是二进制格式. 如果为false, 则表示散列值仅由小写十六进制数字组成. 将生成十六进制数字.

compareString

可防止时序攻击的字符串比较,用法非常简单。

Yii::$app->security->compareString("abc",'abc');

结果为真则相等,否则不相等。

那么什么是时序攻击那?我来举一个简单的例子。

if($code == Yii::$app->request->get('code')){
 
}

上面的比较逻辑,两个字符串是从第一位开始逐一进行比较的,发现不同就立即返回 false,那么通过计算返回的速度就知道了大概是哪一位开始不同的,这样就实现了电影中经常出现的按位破解密码的场景。

而使用 compareString 比较两个字符串,无论字符串是否相等,函数的时间消耗是恒定的,这样可以有效的防止时序攻击。

maskToken && unmaskToken

maskToken用于掩盖真实token且不可以压缩,同一个token最后生成了不同的随机令牌,在yii2的csrf功能上就使用了maskToken,原理并不复杂,我们看下源码。

public function maskToken($token){
 $mask = $this->generateRandomKey(StringHelper::byteLength($token));
 return StringHelper::base64UrlEncode($mask . ($mask ^ $token));
}

而unmaskToken目的也很明确,用于得到被maskToken掩盖的token。

接下来我们看一个例子代码

$token = Yii::$app->security->maskToken("123456");
echo Yii::$app->security->unmaskToken($token);// 结果为 123456

最后我们总结下

  • 加密/解密: encryptByKey()、decryptByKey()、 encryptByPassword() 和 decryptByPassword();
  • 使用标准算法的密钥推导: pbkdf2() 和 hkdf();
  • 防止数据篡改: hashData() 和 validateData();
  • 密码验证: generatePasswordHash() 和 validatePassword()

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
php中理解print EOT分界符和echo EOT的用法区别小结
Feb 21 PHP
PHP中Date()时间日期函数的使用方法小结
Apr 20 PHP
实用PHP会员权限控制实现原理分析
May 29 PHP
PHP二维数组的去重问题解析
Jul 17 PHP
php中is_null,empty,isset,unset 的区别详细介绍
Apr 28 PHP
php实现redis数据库指定库号迁移的方法
Jan 14 PHP
php判断当前操作系统类型
Oct 28 PHP
PHP如何通过AJAX方式实现登录功能
Nov 23 PHP
mysql查找删除重复数据并只保留一条实例详解
Sep 24 PHP
PHP钩子实现方法解析
May 21 PHP
laravel unique验证、确认密码confirmed验证以及密码修改验证的方法
Oct 16 PHP
laravel入门知识点整理
Sep 15 PHP
php中curl和soap方式请求服务超时问题的解决
Jun 11 #PHP
Laravel框架模板继承操作示例
Jun 11 #PHP
Laravel框架模板加载,分配变量及简单路由功能示例
Jun 11 #PHP
Laravel框架在本地虚拟机快速安装的方法详解
Jun 11 #PHP
thinkPHP5框架中widget的功能与用法详解
Jun 11 #PHP
thinkPHP5框架自定义验证器实现方法分析
Jun 11 #PHP
PHP绕过open_basedir限制操作文件的方法
Jun 10 #PHP
You might like
使PHP自定义函数返回多个值
2006/11/26 PHP
自己前几天写的无限分类类
2007/02/14 PHP
PHP中文汉字验证码
2007/04/08 PHP
PHP实现的简单三角形、矩形周长面积计算器分享
2014/11/18 PHP
PHP也能干大事 随机函数
2015/04/14 PHP
Netbeans 8.2与PHP相关的新特性介绍
2016/10/08 PHP
Nigma vs Alliance BO5 第五场2.14
2021/03/10 DOTA
js 居中漂浮广告
2010/03/21 Javascript
js获取网页高度(详细整理)
2012/12/28 Javascript
js replace正则表达式应用案例讲解
2013/01/17 Javascript
基于Jquery实现万圣节快乐特效
2015/11/01 Javascript
javascript每日必学之运算符
2016/02/16 Javascript
JavaScript实现图片滑动切换的代码示例分享
2016/03/06 Javascript
canvas绘制表盘时钟
2017/01/23 Javascript
jQuery实现腾讯信用界面(自制刻度尺)样式
2017/08/15 jQuery
详解JS判断页面是在手机端还是在PC端打开的方法
2019/04/26 Javascript
浅析Angular 实现一个repeat指令的方法
2019/07/21 Javascript
原生js添加一个或多个类名的方法分析
2019/07/30 Javascript
Vue触发隐藏input file的方法实例详解
2019/08/14 Javascript
Python实现处理管道的方法
2015/06/04 Python
Python抓取框架Scrapy爬虫入门:页面提取
2017/12/01 Python
python pandas库中DataFrame对行和列的操作实例讲解
2018/06/09 Python
Python通过TensorFlow卷积神经网络实现猫狗识别
2019/03/14 Python
Pytorch evaluation每次运行结果不同的解决
2020/01/02 Python
使用tensorboard可视化loss和acc的实例
2020/01/21 Python
如何快速理解python的垃圾回收机制
2020/09/01 Python
爱尔兰橄榄球店:Irish Rugby Store
2019/12/05 全球购物
说出ArrayList,Vector, LinkedList的存储性能和特性
2015/01/04 面试题
个人实用简单的自我评价
2013/10/19 职场文书
班组长的岗位职责
2013/12/09 职场文书
美食节策划方案
2014/05/26 职场文书
离职保密承诺书
2014/05/28 职场文书
新法人代表任命书
2014/06/06 职场文书
职业生涯规划书之大学四年
2019/08/07 职场文书
详解PHP服务器如何在有限的资源里最大提升并发能力
2021/05/25 PHP
MySQL中order by的执行过程
2022/06/05 MySQL