知识补充

因为yii2 csrf的验证的加解密 涉及到异或运算

所以需要先补充php里字符串异或运算的相关知识,不需要的可以跳过

^异或运算
不一样返回1 否者返回 0
在PHP语言中,经常用来做加密的运算,解密也直接用^就行
字符串运算时 利用字符的ascii码转换为2进制来运算
单个字符运算
举例的ascii见下表

字符

二进制

ASCII

a

1100001

97

b

1100010

98

c

1100011

99

d

1100100

100

计算结果

运算

二进制

ASCII

a^b

0000 0011

3

a^c

0000 0010

2

b^d

0000 0110

6

ab^cd

0000 0010

2

a^cd

0000 0010

2

ab^c

0000 0010

2

1.对于单个字符和单个字符的
直接计算其结果即可 比如表里的a^b

2.对于长度一样的多个字符串 如表里的ab^cd
计算a^c对应的结果和和b^d对应的结果 对应的字符连接起来

<?php
$str1='ab';
$str2="cd";
$r= $str1^$str2;
var_dump($r);
echo "<hr>";
for($i=0;$i<strlen($r) ;$i++){
echo ord($r[$i])."<br>";
}
?>

对于不等的
以短的字符串长度位进行计算

Yii2的csrf token验证
在yii2的接收post请求时
在如果开启
enableCsrfValidation为true
在/vendor/yiisoft/yii2/web/Controller.php

<?php
public function beforeAction($action)
{
if (parent::beforeAction($action)) {
if ($this->enableCsrfValidation && Yii::$app->getErrorHandler()->exception === null && !Yii::$app->getRequest()->validateCsrfToken()) {
throw new BadRequestHttpException(Yii::t('yii', 'Unable to verify your data submission.'));
}
return true;
} return false;
}
?>

会进行validateCsrfToken验证
在/vendor/yiisoft/yii2/web/Request.php

<?php
public function validateCsrfToken($token = null)
{ $method = $this->getMethod();
// only validate CSRF token on non-"safe" methods http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
if (!$this->enableCsrfValidation || in_array($method, ['GET', 'HEAD', 'OPTIONS'], true)) {
return true;
} $trueToken = $this->loadCsrfToken(); if ($token !== null) {
return $this->validateCsrfTokenInternal($token, $trueToken);
} else {
return $this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken)
|| $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken);
}
}
?>

说明在 GET, HEAD, OPTIONS 均不验证,除了这几种主要用的也就post了

说明在我们发送post请求时必须发送相关验证的字段和值
下面看CsrfToken产生过程
在/vendor/yiisoft/yii2/web/Request.php里

<?php
public function getCsrfToken($regenerate = false)
{ if ($this->_csrfToken === null || $regenerate) {
if ($regenerate || ($token = $this->loadCsrfToken()) === null) {
$token = $this->generateCsrfToken();
}
// the mask doesn't need to be very random
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.';
$mask = substr(str_shuffle(str_repeat($chars, 5)), 0, static::CSRF_MASK_LENGTH);
// The + sign may be decoded as blank space later, which will fail the validation
$this->_csrfToken = str_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask)));
}
return $this->_csrfToken;
}
?>

会发现
_csrfToken的产生大致如下
如果开启了enableCsrfCookie,
CsrfToken就从cookie里取,否者从session里取(更安全)
可在
/vendor/yiisoft/yii2/web/Request.php的下面部位看到

<?php
protected function loadCsrfToken()
{
if ($this->enableCsrfCookie) {
return $this->getCookies()->getValue($this->csrfParam);
} else {
return Yii::$app->getSession()->get($this->csrfParam);
}
}
?>

从loadCsrfToken()里取出的值这里称token

在post里发送的也就是Yii::$app->getRequest()->csrfParam 这里称csrfToken
现在根据代码大致说下生成和验证的主要思路,当然自己看代码更能细致的了解
1.从cookie或者session里取出token ,当然cookie或者session里如果没有就是初始化操作的过程了,这里初始化不是重点
2.随机产生CSRF_MASK_LENGTH(Yii2里默认是8位)长度的字符串 mask
3.对mask和token进行如下运算
str_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask))); $this->xorTokens($arg1,$arg2) 是一个先补位异或运算

传入$arg1,$arg2
长度短的要用自身补到长度长的字符串的位置
见代码部分
在 /vendor/yiisoft/yii2/web/Request.php 的如下部分

 <?php
private function xorTokens($token1, $token2)
{
$n1 = StringHelper::byteLength($token1);
$n2 = StringHelper::byteLength($token2);
if ($n1 > $n2) {
$token2 = str_pad($token2, $n1, $token2);
} elseif ($n1 < $n2) {
$token1 = str_pad($token1, $n2, $n1 === 0 ? ' ' : $token1);
} return $token1 ^ $token2;
}
?>

就是说如果 $arg1比$arg2短,$arg1要用自身补齐 补到和和$arg2一样的长度
这里为什么要这样做?
因为在php里
'a'^'bc' 会只算 a^b 而不考虑c了,这里采用了向长度更长的来补
如果用
xorTokens来处理 'a'和'bc'
会先把a用自己填充到和bc一样的长度后再进行异或运算
异或运算详见上文补充

str_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask)));

计算后即会得出在post请求时要发送的值 csrfToken

下面是验证过程
1.根据 表单字段名
Yii::$app->getRequest()->csrfParam;
从post里拿到
csrfToken的值
从方法 validateCsrfToken里可以看到
代码
在/vendor/yiisoft/yii2/web/Request.php 的如下部分

<?php
public function validateCsrfToken($token = null)
{ $method = $this->getMethod();
// only validate CSRF token on non-"safe" methods http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
if (!$this->enableCsrfValidation || in_array($method, ['GET', 'HEAD', 'OPTIONS'], true)) {
return true;
} $trueToken = $this->loadCsrfToken(); if ($token !== null) {
return $this->validateCsrfTokenInternal($token, $trueToken);
} else {
return $this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken)
|| $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken);
}
} ?>

$this->getBodyParam($this->csrfParam)
可以看出
解密的目的就是要从
csrfToken里取出token 然后和会话里的token比较
见/vendor/yiisoft/yii2/web/Request.php 的如下部分

<?php
private function validateCsrfTokenInternal($token, $trueToken)
{ $token = base64_decode(str_replace('.', '+', $token));
$n = StringHelper::byteLength($token);
if ($n <= static::CSRF_MASK_LENGTH) {
return false;
}
$mask = StringHelper::byteSubstr($token, 0, static::CSRF_MASK_LENGTH);
$token = StringHelper::byteSubstr($token, static::CSRF_MASK_LENGTH, $n - static::CSRF_MASK_LENGTH);
/*
注意此时的$token在加密过程中是xorTokens($trueToken,$mask)的结果
*/
$token = $this->xorTokens($mask, $token); return $token === $trueToken;
}
?>

加密时用的是
str_replace('+', '.', base64_encode($mask . $this->xorTokens($token, $mask)));
解密
1.首先要把.替换成+
2.然后base64_decode
再 根据长度分别取出$mask和$this->xorTokens($token, $mask) ;
为了说明方便 $this->xorTokens($token, $mask) 这里称作 token1
然后
进行mask和token1的异或运算,即得token
注意在加密时
token1=token^mask
所以
解密时
token=mask^token1=mask^(token^mask)

yii2
中的核心思路
token是从会话中取得的
用随机串和token进行运算处理 得到一个加密串
验证的时候通过这个加密串解密出来这个token和会话里的值进行比较

yii2 csrf验证原理分析的更多相关文章

  1. yii2的csrf验证原理分析及token缓存解决方案

    本文主要分三个部分,首先简单介绍csrf,接着对照源码重点分析一下yii框架的验证原理,最后针对页面缓存导致的token被缓存提出一种可行的方案.涉及的知识点会作为附录附于文末. 1.CSRF描述 C ...

  2. 148.CSRF攻击原理分析、防御、装饰器、中间件、IFrame以及js实现csrf攻击

    CSRF攻击概述: CSRF(Cross Site Request Forgery 跨站域请求伪造)是一种网站攻击的方式,它在2007年曾被列为互联网20大安全隐患之一.其他的安全隐患,比如SQL脚本 ...

  3. Yii2 Restful API 原理分析

    Yii2 有个很重要的特性是对 Restful API的默认支持, 通过短短的几个配置就可以实现简单的对现有Model的RESTful API 参考另一篇文章: http://www.cnblogs. ...

  4. Django CSRF 原理分析

    原文链接: https://blog.csdn.net/u011715678/article/details/48752873 参考链接:https://blog.csdn.net/clark_fit ...

  5. Yii2 关闭和打开csrf 验证 防止表单多次重复提交

    原文地址:http://blog.csdn.net/terry_water/article/details/52221007 1.在Yii2配置中配置所有:所有的controller都将关闭csrf验 ...

  6. Django中csrf token验证原理

    我多年没维护的博客园,有一篇初学Django时的笔记,记录了关于django-csrftoekn使用笔记,当时几乎是照抄官网的使用示例,后来工作全是用的flask.博客园也没有维护.直到我的博客收到了 ...

  7. yii2表单提交CSRF验证

    Yii2表单提交默认需要验证CSRF,如果CSRF验证不通过,则表单提交失败,解决方法如下: 第一种解决办法是关闭Csrf public $enableCsrfValidation = false; ...

  8. flask提交表单验证不通过,以及CSRF攻击原理

    学习表单的问题1. 提交表单时怎么都无法验证通过 记录一下,自己的学习bug,主要是因为在模板中书写渲染的语句时,把CSRF的字段名写错了. 因为在模板中书写一些语句是没有提示的,自己手动敲代码容易出 ...

  9. Yii2 CSRF

    一.CSRF 即Cross-site request forgery跨站请求伪造,是指有人冒充你的身份进行一些恶意操作. 比如你登录了网站A,网站A在你的电脑设置了cookie用以标识身份和状态,然后 ...

随机推荐

  1. POJ 3977 - subset - 折半枚举

    2017-08-01 21:45:19 writer:pprp 题目: • POJ 3977• 给定n个数,求一个子集(非空)• 使得子集内元素和的绝对值最小• n ≤ 35 AC代码如下:(难点:枚 ...

  2. 你知道uwsgi???

    第一步,打开https://www.google.com.hk 第二步,输入how to restart uwsgi

  3. Python基础笔记系列三:list列表

    本系列教程供个人学习笔记使用,如果您要浏览可能需要其它编程语言基础(如C语言),why?因为我写得烂啊,只有我自己看得懂!! python中的list列表是一种序列型数据类型,一有序数据集合用逗号间隔 ...

  4. log4j.appender.AFile.File日志的相对路径

    log4j.appender.AFile=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.AFile.DatePattern='.'yy ...

  5. redis的Python接口调用

    Redis安装及教程: redis教程 安装Python的redis接口模块 redis-py requires a running Redis server. See redis教程 for ins ...

  6. Webpack——解决疑惑,让你明白

    Webpack——解决疑惑,让你明白 极客教程 作者 关注 2016.09.29 17:46* 字数 2868 阅读 22204评论 22喜欢 80 Webpack是目前基于React和Redux开发 ...

  7. How to Have a Healthy Relationship --shanbei 为单身节写

    我在扇贝发现一片好文. Sometimes relationships can seem like a lot of work until you sit back and realize just ...

  8. php服务端setcookie()原理

    1.什么是 Cookie? cookie 常用于识别用户.cookie 是服务器留在用户计算机中的小文件.每当相同的计算机通过浏览器请求页面时,它同时会发送 cookie.通过 PHP,您能够创建并取 ...

  9. 在IIS站点中使用数字证书

    1. SSL解析(内容来自百度百科) SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安 ...

  10. [BZOJ5297][CQOI2018]社交网络

    bzoj luogu sol 就是求以\(1\)为根的生成树的数量. 直接矩阵树定理. code #include<cstdio> #include<algorithm> #i ...