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 相关文章推荐
phpmyadmin的#1251问题
Nov 25 PHP
国外PHP程序员的13个好习惯小结
Feb 20 PHP
ThinkPHP模板判断输出Defined标签用法详解
Jun 30 PHP
Codeigniter检测表单post数据的方法
Mar 21 PHP
Symfony2框架学习笔记之表单用法详解
Mar 18 PHP
JS(jQuery)实现聊天接收到消息语言自动提醒功能详解【提示“您有新的消息请注意查收”】
Apr 16 PHP
PHP实现微信提现(企业付款到零钱)
Aug 01 PHP
php策略模式简单示例分析【区别于工厂模式】
Sep 25 PHP
解决laravel groupBy 对查询结果进行分组出现的问题
Oct 09 PHP
PHP实现限制域名访问的实现代码(本地验证)
Sep 13 PHP
Laravel统一错误处理为JSON的方法介绍
Oct 18 PHP
PHP 出现 http500 错误的解决方法
Mar 09 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判断变量的函数
2012/04/24 PHP
php常用图片处理类
2016/03/16 PHP
PHP实现随机生成水印图片功能
2017/03/22 PHP
PHP判断json格式是否正确的实现代码
2017/09/20 PHP
深入解析Laravel5.5中的包自动发现Package Auto Discovery
2017/09/13 PHP
对php 判断http还是https,以及获得当前url的方法详解
2019/01/15 PHP
jquery之empty()与remove()区别说明
2010/09/10 Javascript
基于jQuery的倒计时插件代码
2011/05/07 Javascript
jquery插件制作简单示例说明
2012/02/03 Javascript
javascript修改图片src的方法
2015/01/27 Javascript
jQuery选择器源码解读(二):select方法
2015/03/31 Javascript
js实现类似MSN提示的页面效果代码分享
2015/08/24 Javascript
JS实现给对象动态添加属性的方法
2017/01/05 Javascript
浅谈vuejs实现数据驱动视图原理
2018/02/23 Javascript
vue插件开发之使用pdf.js实现手机端在线预览pdf文档的方法
2018/07/12 Javascript
highCharts提示框中显示当前时间的方法
2019/01/18 Javascript
浅谈react-router@4.0 使用方法和源码分析
2019/06/04 Javascript
原生JS实现多条件筛选
2020/08/19 Javascript
[01:56]无止竞 再出发——中国军团出征2017年DOTA2国际邀请赛
2017/07/05 DOTA
Python中SOAP项目的介绍及其在web开发中的应用
2015/04/14 Python
详解Python中的变量及其命名和打印
2016/03/11 Python
python删除服务器文件代码示例
2018/02/09 Python
pandas 小数位数 精度的处理方法
2018/06/09 Python
一文详述 Python 中的 property 语法
2020/09/01 Python
Python的Tqdm模块实现进度条配置
2021/02/24 Python
Clarks其乐鞋荷兰官网:Clarks荷兰
2019/07/05 全球购物
linux面试题参考答案(5)
2016/11/05 面试题
竞聘上岗演讲稿范文
2014/01/10 职场文书
助残日活动总结
2014/08/27 职场文书
维稳工作承诺书
2015/01/20 职场文书
全国爱眼日活动总结
2015/02/27 职场文书
寻找最美乡村教师观后感
2015/06/18 职场文书
2019行政前台转正申请书范文3篇
2019/08/15 职场文书
MySQL 数据类型详情
2021/11/11 MySQL
Java字符缓冲流BufferedWriter
2022/04/09 Java/Android
Python基本的内置数据类型及使用方法
2022/04/13 Python