浅谈csrf攻击以及yii2对其的防范措施

凡是我yii2学习社群的成员都知道,我不止一次给大家说构造表单100%使用yii2的ActiveForm来实现,这除了能和AR更好结合外就是自动生成csrf隐藏域,一个非常安全的举措。

今天北哥就给大家普及下csrf是啥?如果你已经知道了可以直接拉文章到底部点个赞。:smile:

CSRF(Cross-site request forgery跨站请求伪造)是一种对网站的恶意利用,在 2007 年曾被列为互联网 20 大安全隐患之一。

关于CSRF,要从一个故事开始~

老王丢钱事件

这个故事要从程序员老王丢了1万块钱说起,总之是进了小偷,找回无果。丢钱后的老王一直在思考,钱是怎么丢的、为何丢钱、为何是我丢钱~~

后来老王出现了严重的心理问题,他决定报复社会。

老王首先研究了网银系统,他发现转账是通过GET形式

https://bank.abc.com/withdraw?account=liuxiaoer&amount=1000&to=abei

这意思就是说将 liuxiaoer 的1000元钱转给abei,当然当请求到达银行服务器后,程序会验证该请求是否来自合法的session并且该session的用户就是 liuxiaoer 并且已经登录。

老王自己也有一个银行账号 wang2,他尝试登录并且通过浏览器发送请求给银行,代码如下

https://bank.abc.com/withdraw?account=liuxiaoer&amount=1000&to=wang2

失败了~因为当前登录账号是老王自己,发送请求后服务器发现session所属用户wang2和account=liuxiaoer并不是一个人,因此被拒绝。

也就是说这个操作必须是 liuxiaoer 自己才可以,复仇的力量是可怕的,老王通过facebook层层找到了 liuxiaoer 就是快递员老刘的银行账号。

于是一个伟大的计划诞生了,老王的计划是这样的。

1、首先做一个网页,在网页中加入如下代码

src="https://bank.abc.com/withdraw?account=liuxiaoer&amount=1000&to=wang2"

然后通过各种情景让老刘(liuxiaoer)访问了此网页。

2、当老刘(liuxiaoer)访问此网页后,上面的请求会被发送到银行,此刻还会带着老刘(liuxiaoer)自己的浏览器cookie信息,当然这样一般也不会成功,因为银行服务器发现老刘(liuxiaoer)并不在登录状态。

3、老王想了一个招,他在淘宝找了一个灰色商人老李,让他通过种种方法,总之让老刘(liuxiaoer)通过浏览器给老李转了一次款。

4、就在第三步操作的2分钟内,老王成功让老刘(liuxiaoer)再一次访问了自己做的网页,你知道的,此刻老刘(liuxiaoer)在银行的session还没有过期,老王网页给银行服务器发送请求后,验证通过,打款成功。

5、老王收到了款,老刘(liuxiaoer)并不知道这一切,对于银行来说这是一笔在正常不过的转账。

这就是CSRF攻击,浏览器无法拦截。

CSRF攻击特点

基于上面血淋淋的故事,我们总结下CSRF攻击的几个特点。

  • 黑客借助于受害者的cookie等浏览器信息骗取服务器新人,黑客并拿不到cookie等。
  • 由于浏览器同源策略,黑客无法拿到攻击的响应结果,能做的只是发起请求,你是否还记得很多钓鱼网站都模拟了登录框么?
  • CSRF攻击主要是发送修改数据请求。

CSRF防御对象

因此我们要保护的是所有能引起数据变化的客户端请求,比如新建、更新和删除。

CSRF防御方案

基于CSRF攻击特点,在业界目前防御 CSRF 攻击主要有三种策略:

  • 验证 HTTP Referer 字段;
  • 在请求地址中添加 token 并验证;
  • 在 HTTP 头中自定义属性并验证。

HEEP Referer

在http请求的时候,头部有一个叫做Referer的字段,该字段记录本次请求的来源地址。因此服务器端可以通过此字段是否为同一个域名来判断请求是否合法,因为客户自己做的网页发起的请求,其Referer为黑客网站。

这种方法最简单,并且不需要修改业务代码,我们只需要对到达服务器的每个请求做一次拦截分析即可。

但是此方法的缺点也是明显的,因为Referer的值是浏览器的,虽然HTTP协议不允许去修改,但是如果浏览器自身存在漏洞,那么就有可能导致Referer被人工设置,不安全。

比如IE6,就可以通过方法篡改Referer值。

就算是最新的浏览器此方法也不是绝对可用的,这涉及了用户的隐私,很多用户会设置浏览器不提供Referer,因此服务器在得不到Referer的情况下不能贸然的决绝服务,有可能这是一个合法请求。

添加Token

CSRF攻击之所以能成功,是因为黑客完全伪造了一次用户的正常请求(这也是浏览器无法拦截的原因),并且cookie信息就是用户自己的,那么我们如果在请求中放入一些黑客无法去伪造的信息(不存在与cookie中),不就可以抵御了么!

比如在请求前生成一个token放到session中,当请求发生时,将token从session拿出来和请求提交过来的token进行对比,如果相等则认证通过,否则拒绝。token时刻在变化,黑客无法去伪造。

针对于不同类型的请求一般方案是

  • GET 放到url中,比如http://url?csrftoken=xxxx
  • POST 放到表单的隐藏域 <input type=”hidden” name=”csrftoken” value=”xxxx”/>

对于GET请求,这里有一点要说明,在一个网站中请求的url很多,一般情况我们是通过js对dom的所有节点进行遍历,发现a链接就在其href中增加token。

这里存在一个问题,比如黑客将自己网站的链接发到了要攻击页面,则黑客网站链接后面会有一个token,此刻客户可以通过编写自己网站代码得到这个token,然后用这个token立刻构造表单,发起CSRF攻击,因此在js遍历的时候,如果发现不是本站的链接,可以不加token。

在HTTP头部增加属性

这个方法在思路上和上面的token方式一样,只不过将token放到了HTTP头部中,不再参数传递,通过XMLHttpRequest类可以一次性的给所有请求加上csrftoken这个HTTP头属性并设置值。

这种方法适合上面批量添加token不方便的情况,一次性操作,不过局限性也比较大,XMLHttpRequest请求通常用在ajax方法中,并非所有请求都适合。

Yii2

首先要说的是每种CSRF防范措施都有其弊端,无论你的防范多么严密,黑客拥有更多的攻击手段,因此在重要逻辑上(必须写入和删除)必须非常小心,接下来我们把yii2框架在csrf上的部署说一下。

我们以yii2.0.14为解说版本。

在CSRF这块,yii2框架采取了HTTP头部和参数token并行的方式,针对于每个请求,在beforeAction都会做一次判断,如下

// vendor/yiisoft/yii2/web/Controller.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;
}

如果我们没有设置 enableCsrfValidation 为false,并且没有报错,则会进行csrf验证,核心方法就是

Yii::$app->getRequest()->validateCsrfToken()

该方法存在于 vendor/yiisoft/yii2/web/Request.php 中,我们看一看它。

public function validateCsrfToken($clientSuppliedToken = null) {
    // 省略上面代码
    return $this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken)
        || $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken);
}

validateCsrfToken函数代码我们只需要看最后的返回,getBodyParam或getCsrfTokenFromHeader方法得到的token,只要有一种验证通过,就认为合法。

以上是整体的思路,为了让你看的更清晰,我画一个图并增加一些名词解释。

 

以上是yii2的csrf策略部署,当然我还是推荐你使用 xdebug等调试工具 一步一步看看这个过程。

最后我在把上图的关键函数进行说明

  • generateCsrfToken() 该函数生成token并存到cookie或session中,该值不会随页面刷新而变化,它更多充当钥匙的作用,根绝它生成具体的csrfToken。
  • getCsrfToken() 生成具体的csrfToken,就是你在表单隐藏域中看到的那个值,这个值将来会传到服务器和真实的csrfToken进行对比,验证是否合法。
  • validateCsrfToken() 进行合法性验证,该函数得到一个真实的csrfToken然后和客户端上传来的csrfToken进行对比。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了防范CSRF(Cross-Site Request Forgery)攻击,可以采取以下几个防范措施: 1. 验证来源:在服务器端验证请求的来源是否合法。可以使用一些方法,如检查Referer头部、检查请求的Origin头部、使用自定义的Token等来确保请求来自于合法的源。 2. 使用CSRF令牌:为每个用户生成一个唯一的CSRF令牌,并将该令牌嵌入到表单或请求中。当提交表单或发起请求时,服务器端会验证该令牌的有效性。攻击者无法获取到合法用户的CSRF令牌,从而无法成功伪造请求。 3. 同源策略:浏览器的同源策略可以帮助防止跨站点攻击。通过限制页面中脚本的访问权限,确保只有相同源的页面才能相互通信,从而减少CSRF攻击的可能性。 4. 设置安全的Cookie:使用HttpOnly标志和Secure标志对Cookie进行设置。HttpOnly标志可以防止通过客户端脚本访问Cookie,减少被盗取的风险。Secure标志则要求Cookie只能在通过HTTPS协议进行传输,增加了传输过程中的安全性。 5. 强化身份验证:使用强密码策略、多因素身份验证等方式来加强对用户身份的验证,以减少被攻击者冒充的可能性。 6. 及时更新和修补漏洞:及时更新和修补应用程序和框架中的漏洞,以防止攻击者利用已知的漏洞进行CSRF攻击。 7. 安全编码实践:在开发过程中采用安全编码实践,遵循最佳实践和安全标准,避免在应用程序中引入安全漏洞。 综合采取上述防范措施可以有效减少CSRF攻击的风险,并提高应用程序的安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值