首頁 >後端開發 >php教程 >yii2對csrf攻擊的防範措施

yii2對csrf攻擊的防範措施

不言
不言原創
2018-07-10 15:06:361984瀏覽

這篇文章主要介紹了關於yii2對csrf攻擊的防範措施,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

今天北哥就給大家普及下csrf是啥?如果你已經知道可以直接拉文章到底部按個讚了。

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 放到表单的隐藏域

对于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攻擊的防範措施

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

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

  • generateCsrfToken() 该函数生成token并存到cookie或session中,该值不会随页面刷新而变化,它更多充当钥匙的作用,根绝它生成具体的csrfToken。

  • getCsrfToken() 生成具体的csrfToken,就是你在表单隐藏域中看到的那个值,这个值将来会传到服务器和真实的csrfToken进行对比,验证是否合法。

  • validateCsrfToken()  进行合法性验证,该函数得到一个真实的csrfToken然后和客户端上传来的csrfToken进行对比。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

如何在yii2-wx中使用try_catch

关于Yii2中GridView的用法总结

以上是yii2對csrf攻擊的防範措施的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn