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 相关文章推荐
利用Memcached在php下实现session机制 替换PHP的原生session支持
Aug 21 PHP
php header示例代码(推荐)
Sep 08 PHP
PHP采集利器 Snoopy 试用心得
Jul 03 PHP
浅谈PHP正则表达式中修饰符/i, /is, /s, /isU
Oct 21 PHP
php控制文件下载速度的方法
Mar 24 PHP
php结合md5实现的加密解密方法
Jan 25 PHP
PHP接收App端发送文件流的方法
Sep 23 PHP
php判断是否为ajax请求的方法
Nov 29 PHP
[企业公众号]升级到[企业微信]之后发送消息失败的解决方法
Jun 30 PHP
Yii2框架数据验证操作实例详解
May 02 PHP
PHP 二维array转换json的实例讲解
Aug 21 PHP
PHP7.0连接DB操作实例分析【基于mysqli】
Sep 26 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 在线打包_支持子目录
2008/06/28 PHP
解决PHP超大文件下载,断点续传下载的方法详解
2013/06/06 PHP
PHP判断是否有Get参数的方法
2014/05/05 PHP
PHP实现搜索地理位置及计算两点地理位置间距离的实例
2016/01/08 PHP
/etc/php-fpm.d/www.conf 配置注意事项
2017/02/04 PHP
php smtp实现发送邮件功能
2017/06/22 PHP
Laravel框架中缓存的使用方法分析
2019/09/06 PHP
用JavaScript调用WebService的示例
2008/04/07 Javascript
js 解决“options为空或不是对象”
2008/12/22 Javascript
高性能web开发 如何加载JS,JS应该放在什么位置?
2010/05/14 Javascript
JS Pro-深入面向对象的程序设计之继承的详解
2013/05/07 Javascript
javascript中的document.open()方法使用介绍
2013/10/09 Javascript
浅析JavaScript基本类型与引用类型
2014/05/28 Javascript
教你在heroku云平台上部署Node.js应用
2014/07/30 Javascript
ajaxFileUpload.js插件支持多文件上传的方法
2014/09/02 Javascript
禁止iframe脚本弹出的窗口覆盖了父窗口的方法
2014/09/06 Javascript
angularJS中router的使用指南
2015/02/09 Javascript
jquery实现点击展开列表同时隐藏其他列表
2015/08/10 Javascript
js实现不提交表单获取单选按钮值的方法
2015/08/21 Javascript
AngularJS表单和输入验证实例
2016/11/02 Javascript
AngularJs实现聊天列表实时刷新功能
2017/06/15 Javascript
原生js封装运动框架的示例讲解
2017/10/01 Javascript
JS实现去除数组中重复json的方法示例
2017/12/21 Javascript
JavaScript实现的贝塞尔曲线算法简单示例
2018/01/30 Javascript
[01:00:04]DOTA2上海特级锦标赛B组小组赛#1 Alliance VS Spirit第二局
2016/02/26 DOTA
[28:05]完美世界DOTA2联赛循环赛Inki vs DeMonsTer 第一场 10月30日
2020/10/31 DOTA
pandas 选择某几列的方法
2018/07/03 Python
opencv python 图像轮廓/检测轮廓/绘制轮廓的方法
2019/07/03 Python
python实现查找所有程序的安装信息
2020/02/18 Python
jupyter notebook参数化运行python方式
2020/04/10 Python
python 读取串口数据的示例
2020/11/09 Python
详解Django自定义图片和文件上传路径(upload_to)的2种方式
2020/12/01 Python
英国Lookfantastic中文网站:护肤品美妆美发购物(英国直邮)
2020/04/27 全球购物
互联网创业商业模式以及赚钱法则有哪些?
2019/10/12 职场文书
用CSS3画一个爱心
2021/04/27 HTML / CSS
一文了解Java动态代理的原理及实现
2022/07/07 Java/Android