一、CSRF

即Cross-site request forgery跨站请求伪造,是指有人冒充你的身份进行一些恶意操作。

比如你登录了网站A,网站A在你的电脑设置了cookie用以标识身份和状态,然后你又访问了网站B,这时候网站B就可以冒充你的身份在A网站进行操作,因为网站B在请求网站A时,浏览器会自动发送之前设置的cookie信息,让网站A误认为仍然是你在进行操作。

对于csrf的防范,一般都会放在服务器端进行,那么我们来看下Yii2中是如何进行防范的。

二、Yii2 CSRF

首先说明一下,我安装的是Yii2高级模版。

csrf token生成

vendor\yiisoft\yii2\web\Request.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;

}

getCsrfToken方法首先会用loadCsrfToken方法尝试加载已存在的token,如果没有则用generateCsrfToken方法再生成一个,并经过后续处理,得到最终的前台请求时携带的csrf

token。

protected function loadCsrfToken()

{

if ($this->enableCsrfCookie) {

return $this->getCookies()->getValue($this->csrfParam);

} else {

return Yii::$app->getSession()->get($this->csrfParam);

}

}

loadCsrfToken方法会尝试从cookie或session中加载已经存在的token,enableCsrfCookie默认为true,所以一般会从cookie中获取

public function getCookies()

{

if ($this->_cookies === null) {

$this->_cookies = new CookieCollection($this->loadCookies(), [

'readOnly' => true,

]);

}

return $this->_cookies;

}

这里又调用了loadCookies方法

protected function loadCookies()

{

$cookies = [];

if ($this->enableCookieValidation) {

if ($this->cookieValidationKey == '') {

throw new InvalidConfigException(get_class($this) . '::cookieValidationKey

must be configured with a secret key.');

}

foreach ($_COOKIE as $name => $value) {

if (!is_string($value)) {

continue;

}

$data = Yii::$app->getSecurity()->validateData($value,

$this->cookieValidationKey);

if ($data === false) {

continue;

}

$data = @unserialize($data);

if (is_array($data) && isset($data[0], $data[1]) &&

$data[0] === $name) {

$cookies[$name] = new Cookie([

'name' => $name,

'value' => $data[1],

'expire' => null,

]);

}

}

} else {

foreach ($_COOKIE as $name => $value) {

$cookies[$name] = new Cookie([

'name' => $name,

'value' => $value,

'expire' => null,

]);

}

}

return $cookies;

}

这里就是解析验证$_COOKIE中的数据。

cookies设置

vendor\yiisoft\yii2\web\Response.php

protected function sendCookies()

{

if ($this->_cookies === null) {

return;

}

$request = Yii::$app->getRequest();

if ($request->enableCookieValidation) {

if ($request->cookieValidationKey == '') {

throw new InvalidConfigException(get_class($request) .

'::cookieValidationKey must be configured with a secret key.');

}

$validationKey = $request->cookieValidationKey;

}

foreach ($this->getCookies() as $cookie) {

$value = $cookie->value;

if ($cookie->expire != 1 && isset($validationKey)) {

$value =

Yii::$app->getSecurity()->hashData(serialize([$cookie->name, $value]),

$validationKey);

}

setcookie($cookie->name, $value, $cookie->expire, $cookie->path,

$cookie->domain, $cookie->secure, $cookie->httpOnly);

}

}

sendCookies方法利用cookieValidationKey对cookie进行一系列处理,主要是为了获取的时候进行验证,防止cookie被篡改。

public function getCookies()

{

if ($this->_cookies === null) {

$this->_cookies = new CookieCollection;

}

return $this->_cookies;

}

这里的getCookies方法跟request中的不同,并不会从$_COOKIE中获取,_cookies属性在request中的generateCsrfToken方法中有进行设置

protected function generateCsrfToken()

{

$token = Yii::$app->getSecurity()->generateRandomString();

if ($this->enableCsrfCookie) {

$cookie = $this->createCsrfCookie($token);

Yii::$app->getResponse()->getCookies()->add($cookie);

} else {

Yii::$app->getSession()->set($this->csrfParam, $token);

}

return $token;

}

csrf验证

vendor\yiisoft\yii2\web\Request.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);

}

}

这里先验证一下请求方式,接着获取cookie中的token,然后用validateCsrfTokenInternal方法进行对比

private function validateCsrfTokenInternal($token, $trueToken)

{

if (!is_string($token)) {

return false;

}

$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 = $this->xorTokens($mask, $token);

return $token === $trueToken;

}

解析请求携带的csrf token 进行对比并返回结果。

三、总结

Yii2的做法就是先生成一个随机token,存入cookie中,同时在请求中携带随机生成的csrf

token,也是基于之前的随机token而生成的,验证的时候对cookie和csrf

token进行解析,得到随机token进行对比,从而判断请求是否合法。

最后,本文只是对大概的流程进行了分析,具体的细节还请查看源码。

php 提取二维数组的key,PHP 获取二维数组中某个key的集合相关推荐

  1. vue取通过key取value_如何通过获取map中的key来获得与key对应的value值,进行运算...

    展开全部 获取map的key和value的方法分为以下62616964757a686964616fe4b893e5b19e31333366306439两种形式: 1.map.keySet():先获取m ...

  2. mysql primary key 多个_关于mysql中primary key重复的解决方法

    我们都知道MySQL数据库中是讲究primarykey的唯一性的,如果primarykey出现了重复,则会影响其他的表制定的规则. 今天我们要和大家一起分享的是Mysql数据库中primarykey重 ...

  3. (三)Java的基本程序结构(二)---数据输入、控制流、大数、数组

    Java的基本程序结构(二)-数据输入.控制流.大数.数组 文章目录 Java的基本程序结构(二)---数据输入.控制流.大数.数组 前言 一.数据输入 二.控制流 1.块作用域 2.流程控制语句分类 ...

  4. java 数组下标 变量_Java基础语法:数组

    一.简介 描述: 数组是相同类型数据的有序集合. 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们. 基本特点: 数组的长度是确定的.数组一旦被创建,它的大小就是不可以改变的. ...

  5. python 结构体数组 定义_一篇文章弄懂Python中所有数组数据类型

    前言 数组类型是各种编程语言中基本的数组结构了,本文来盘点下Python中各种"数组"类型的实现. list tuple array.array str bytes bytearr ...

  6. 杰理的蓝牙芯片的key是什么?以及该如何添加key?杰理key文件原理

    目录 一.简介 关于杰理芯片的key文件,实际上 杰理芯片特有的一种机制,而这种机制就是存在于杰理芯片特有的架构,也是杰理公司延续将近10年的特点,估计以后也会是这种机制.具体为什么,请听我娓娓道来, ...

  7. php json数组的长度,js 获取json数组里面数组的长度实例

    作为一个前端页面开发者第一次处理json数据,遇到了'js 获取json数组里面数组的长度'?竟然不知道 json没有.length属性(真是要嘲讽下自己),少壮不努力老大徒伤悲啊!以前都是去寻求男朋 ...

  8. php 二维数组去除一项,PHP二维数组提取函数----把不需要的数据剔除

    首先说明一些这个函数的应用场景,比如说你得到的数据是个二维数组,里面的很多成员其实是不必要的,比如说api调用后不必要给别人返回一些用不到的垃圾数据吧,如下是代码. /* * delMemberGet ...

  9. PHP 如何获取二维数组中某个key的集合(高性能查找)

    分享下PHP 获取二维数组中某个key的集合的方法. 具体是这样的,如下一个二维数组,是从库中读取出来的. 代码: $user = array( 0 => array( 'id' => 1 ...

最新文章

  1. [Head First设计模式]餐馆中的设计模式——命令模式
  2. 4怎么修边_亦木良品阻燃板怎么样
  3. BugkuCTF-MISC题多方法解决
  4. python及pycharm
  5. 71.Ext.form.ComboBox 完整属性
  6. 调试 Dockerfile - 每天5分钟玩转 Docker 容器技术(15)
  7. Windows编程中引入winsock2.h后导致的错误解决
  8. 神经网络中的Softmax激活函数
  9. 预训练语言模型论文分类整理
  10. JS----正则表达式
  11. ui自动化分享ppt_全面迎接自动化!微软公布RPA价格,将于4月2日正式上市
  12. MySQL是怎样运行的(实体书扫描+掘金小册)免费下载
  13. 配置案例| Modbus转Profinet网关与ARX-MA100微型空气质量监测系统连接
  14. Spring Boot工程结构推荐
  15. 【冷门快捷键】设置VSCode终端大小最小化快捷键Alt+PageUp/PageDown、编辑代码窗口切换大小快捷键Alt+数字键盘“+”、Alt+数字键盘“-”、Alt+数字键盘“0”
  16. 安卓电子书格式_全网免费电子书资源,都在这个神器里了
  17. FOC控制原理学习(一)
  18. [下载]免费网页密码破解软件─WebCracker 4.0 汉化注册版下载
  19. matlab hold on 置顶,matlab中 hold on 与hold off的用法
  20. 问题 C: Be Unique (20)--《算法笔记》

热门文章

  1. Java 序列化和反序列化
  2. JAVA调用NuSoap服务
  3. 关于sources.list和apt-get [转载]
  4. 法拉利等12家车厂 将与苹果手机联网(图)
  5. WCF分布式开发常见错误(3):客户端调用服务出错
  6. mysql 写不进数据库_求助,为何我的数据不能写入数据库
  7. 写给测试小白:怎么快速找到bug?怎么写测试用例?
  8. 什么是 Service Mesh?
  9. java n%9==0_用C++实现求N!中末尾0的个数的方法详解
  10. 新闻页面_页面加载功能设计总结