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 相关文章推荐
global.php
Dec 09 PHP
将博客园(cnblogs.com)数据导入到wordpress的代码
Jan 06 PHP
php简单判断文本编码的方法
Jul 30 PHP
php实现的微信红包算法分析(非官方)
Sep 25 PHP
PHP中ID设置自增后不连续的原因分析及解决办法
Aug 21 PHP
php实现微信支付之现金红包
May 30 PHP
PHP抽象类与接口的区别详解
Mar 21 PHP
Laravel框架实现多个视图共享相同数据的方法详解
Jul 09 PHP
PHP 模拟登陆功能实例详解
Sep 10 PHP
php创建多级目录与级联删除文件的方法示例
Sep 12 PHP
php+js实现点赞功能的示例详解
Aug 07 PHP
解决Laravel使用验证时跳转到首页的问题
Nov 17 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读取文件内容的几种方法详解
2013/06/26 PHP
php一次性删除前台checkbox多选内容的方法
2013/09/22 PHP
UTF-8正则表达式如何匹配汉字
2015/08/03 PHP
CodeIgniter生成静态页的方法
2016/05/17 PHP
用PHP写的一个冒泡排序法的函数简单实例
2016/05/26 PHP
js玩一玩WSH吧
2007/02/23 Javascript
JavaScript初学者需要了解10个小技巧
2010/08/25 Javascript
JavaScript 处理Iframe自适应高度(同或不同域名下)
2013/03/29 Javascript
jQuery去掉字符串起始和结尾的空格(多种方法实现)
2013/04/01 Javascript
js 绑定键盘鼠标事件示例代码
2014/02/12 Javascript
js加入收藏夹代码(兼容ie/ff/op)
2014/05/16 Javascript
JavaScript子窗口调用父窗口变量和函数的方法
2015/10/09 Javascript
Vue 仿百度搜索功能实现代码
2017/02/16 Javascript
js中开关变量使用实例
2017/02/24 Javascript
jQuery自定义图片上传插件实例代码
2017/04/04 jQuery
JS实现前端缓存的方法
2017/09/21 Javascript
vue.js简单配置axios的方法详解
2017/12/13 Javascript
详解koa2学习中使用 async 、await、promise解决异步的问题
2018/11/13 Javascript
实例讲解v-if和v-show的区别
2019/01/31 Javascript
js this 绑定机制深入详解
2020/04/30 Javascript
Javascript实现贪吃蛇小游戏(含详细注释)
2020/10/23 Javascript
JS常用跨域方法实现原理解析
2020/12/09 Javascript
python绘制多个曲线的折线图
2020/03/23 Python
PyQt5图形界面播放音乐的实例
2019/06/17 Python
python实现控制台输出彩色字体
2020/04/05 Python
详解python使用金山词霸的翻译功能(调试工具断点的使用)
2021/01/07 Python
Html5新标签datalist实现输入框与后台数据库数据的动态匹配
2017/05/18 HTML / CSS
可打印的优惠券、杂货和优惠券代码:Coupons.com
2018/06/12 全球购物
介绍一下Prototype的$()函数,$F()函数,$A()函数都是什么作用?
2014/03/05 面试题
社区党总支书记先进事迹材料
2014/01/24 职场文书
校运会广播稿100字
2014/01/27 职场文书
小区停车场管理制度
2014/01/27 职场文书
面试自我介绍演讲稿
2014/04/29 职场文书
公司总经理岗位职责范本
2014/08/15 职场文书
建筑工程挂靠协议书
2016/03/23 职场文书
解决golang结构体tag编译错误的问题
2021/05/02 Golang