laravel的CSRF防護(hù)機(jī)制和延伸

在說(shuō)laravel框架里對(duì)CSRF的攻擊防護(hù)之前先對(duì)XSS和CSRF攻擊做一下簡(jiǎn)單的介紹灭红。

XSS和CSRF攻擊

XSS全稱(chēng)“跨站腳本”攻擊(Cross-site scripting)槽片。是通過(guò)利用網(wǎng)站的bug在頁(yè)面里注入惡意的js代碼挠轴,當(dāng)用戶打開(kāi)這些頁(yè)面的時(shí)候,這些惡意代碼就會(huì)在用戶毫無(wú)感知的情況下執(zhí)行嗽桩,從而實(shí)現(xiàn)一些用戶未經(jīng)授權(quán)的操作纫版,例如轉(zhuǎn)賬匯款胳挎,更改密碼等。

實(shí)施攻擊的比較常見(jiàn)的方式是通過(guò)發(fā)帖或評(píng)論等方式上傳數(shù)據(jù)到服務(wù)器迅细,比如發(fā)布一條包含這些數(shù)據(jù)的評(píng)論:<script type="text/javascript">alert('xss')</script> 巫橄,如果服務(wù)器沒(méi)有過(guò)濾或轉(zhuǎn)義上傳的這些評(píng)論數(shù)據(jù),直接就存入數(shù)據(jù)庫(kù)茵典。那么當(dāng)這個(gè)頁(yè)面再次被請(qǐng)求的時(shí)候湘换,這條評(píng)論會(huì)從數(shù)據(jù)庫(kù)取出,展示在前端頁(yè)面上,html會(huì)將<script>標(biāo)簽中的腳本解析執(zhí)行彩倚,完成xss攻擊筹我。

目前主流的瀏覽器都具有一定的xss防護(hù)機(jī)制澜建,這種類(lèi)型的xss可能在瀏覽器會(huì)直接過(guò)濾掉屈糊。這里主要說(shuō)明攻擊原理。

想象一下如果腳本的內(nèi)容不是alert('xss')奕枝,而是調(diào)用發(fā)起轉(zhuǎn)賬接口或是將用戶的cookies上傳到攻擊者的服務(wù)器上(前提是cookies沒(méi)有設(shè)置http-only)哥谷,那用戶將會(huì)在毫不知情的情況下造成損失岸夯。

CSRF叫做跨站請(qǐng)求偽造(Cross-site request forgery),本質(zhì)上來(lái)說(shuō)XSS是實(shí)現(xiàn)CSRF攻擊的一種手段呼巷,它們都屬于跨站攻擊囱修。

laravel中CSRF的防護(hù)

在laravel中,框架是通過(guò)發(fā)送令牌的方式來(lái)實(shí)現(xiàn)CSRF防護(hù)的王悍。具體的實(shí)現(xiàn)過(guò)程是破镰,當(dāng)瀏覽器發(fā)起頁(yè)面請(qǐng)求的時(shí)候,laravel會(huì)返回給瀏覽器一個(gè)額外的cookie压储,cookie名為XSRF-TOKEN鲜漩,值是一個(gè)隨機(jī)的字符串,且每一次請(qǐng)求都會(huì)變化集惋。

當(dāng)用戶在瀏覽器中通過(guò)點(diǎn)擊按鈕或其他方式發(fā)起POST請(qǐng)求時(shí)孕似,瀏覽器會(huì)自動(dòng)將cookies發(fā)送給后端,laravel通過(guò)反序列化session_id刮刑,拿到用戶session數(shù)據(jù)喉祭,然后對(duì)比用戶session中的_tokenXSRF-TOKENcookie的值是否匹配,如果不匹配雷绢,會(huì)返回419返回碼泛烙。

注意,laravel對(duì)于GET請(qǐng)求是不做CSRF驗(yàn)證的翘紊。

通過(guò)這種機(jī)制蔽氨,就能夠防止非瀏覽器環(huán)境對(duì)非GET接口的直接調(diào)用。

防護(hù)的局限性

想象一下XSS攻擊的實(shí)現(xiàn)場(chǎng)景帆疟。如果頁(yè)面已經(jīng)被注入了js鹉究,那么通過(guò)js獲取XSRF-TOKENcookie不就是輕而易舉的事情了嗎?這樣子不照樣可以發(fā)起惡意請(qǐng)求了踪宠?

確實(shí)會(huì)存在這種風(fēng)險(xiǎn)自赔,所以在github上就有人提議將XSRF-TOKEN這個(gè)cookie設(shè)置為http-only,以防止這種情況發(fā)生殴蓬。

cookie的http-only屬性設(shè)置為true后匿级,可以阻止JavaScript的訪問(wèn)

不過(guò)這個(gè)請(qǐng)求最終沒(méi)有被實(shí)施蟋滴。剛開(kāi)始我也不太理解,后來(lái)想想也確實(shí)沒(méi)有必要痘绎,而且也不應(yīng)該這樣做津函,因?yàn)檫@個(gè)令牌就是用于給js讀取的,然后js發(fā)送ajax請(qǐng)求之前讀取出此值孤页,然后添加上X-CSRF-TOKEN頭部尔苦。laravel的驗(yàn)證機(jī)制就是基于此頭部的,而不是從cookie中獲取的值行施。如下是源碼:

    /**
     * Get the CSRF token from the request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return string
     */
    protected function getTokenFromRequest($request)
    {
        $token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');

        if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
            $token = $this->encrypter->decrypt($header, static::serialized());
        }

        return $token;
    }

并且存放用戶session_id的這個(gè)cookie是http-only的允坚,雖然惡意的js腳本可以獲取到XSRF-TOKEN令牌,但是它獲取不到用戶的session_id蛾号,這樣子即使有令牌在手稠项,你也無(wú)法假扮用戶執(zhí)行非授權(quán)操作。

http-only是框架的默認(rèn)配置鲜结,你也可以更改session.php配置文件展运,將其改為false,不過(guò)為了網(wǎng)站的安全性精刷,強(qiáng)烈不建議更改它拗胜。

關(guān)于此點(diǎn)的更詳細(xì)解釋?zhuān)梢圆榭次业?a href="http://www.reibang.com/p/2cfb676c58b1" target="_blank">這篇博文

新的攻擊方式

現(xiàn)在看下來(lái)好像只需要保證session_id是http-only的,那么我們就可以高枕無(wú)憂怒允,無(wú)須擔(dān)心xss注入了埂软。既然惡意的js無(wú)法獲取到我的session_id,無(wú)法冒充我本人纫事,那我還有什么好擔(dān)心的呢勘畔?

其實(shí)不然,我認(rèn)為還有兩點(diǎn)需要擔(dān)心:

其一丽惶,通過(guò)http協(xié)議發(fā)送出去的數(shù)據(jù)包有可能被中間人攻擊咖杂,被截獲,然后攻擊者從截獲的數(shù)據(jù)包中解析出用戶的cookies蚊夫,接下來(lái)再冒充用戶偽造請(qǐng)求發(fā)起攻擊。
此時(shí)懦尝,可以將站點(diǎn)升級(jí)成https知纷,然后將存有session_id的這個(gè)cookie設(shè)置為secure,即session.php配置文件中的secure配置項(xiàng)陵霉。

cookie的secure屬性表示只有當(dāng)協(xié)議是https時(shí)琅轧,瀏覽器才會(huì)傳輸此cookie給后端,否則就不發(fā)送踊挠。

其二乍桂,這里假設(shè)攻擊者將受害站點(diǎn)B嵌入一個(gè)iframe中冲杀,然后你通過(guò)攻擊者的誘騙或其他不知情的方式訪問(wèn)到了攻擊者站點(diǎn)A,并發(fā)起了http請(qǐng)求(點(diǎn)擊了按鈕或其他什么形式觸發(fā)的)睹酌,表面上看此請(qǐng)求是在A站點(diǎn)發(fā)出的权谁,實(shí)際上可能你點(diǎn)擊的那個(gè)按鈕是B站點(diǎn)的一個(gè)轉(zhuǎn)賬按鈕,攻擊者通過(guò)iframe嵌入B站點(diǎn)的形式憋沿,把那個(gè)按鈕包裝成了A站點(diǎn)下看起來(lái)無(wú)害的一個(gè)按鈕旺芽,并誘使你點(diǎn)擊了它。如果你此時(shí)在站點(diǎn)B是屬于登陸狀態(tài)的話辐啄,那么這次請(qǐng)求瀏覽器或自動(dòng)將你的cookies發(fā)送給后端采章,達(dá)到了攻擊目的。

對(duì)此的防護(hù)手段壶辜,就是防止頁(yè)面被iframe悯舟。有如下幾種方式來(lái)防止頁(yè)面被未經(jīng)授權(quán)的iframe:

  1. 使用js代碼來(lái)判斷:
if(window != window.top){
    window.top.location.href = myOrigin;
}

注意:這個(gè)只判斷top是不太準(zhǔn)確的,可能循環(huán)嵌套砸民。比如:your-web -> attacker-web -> your-web抵怎。這種就判斷失敗了

  1. 后端返回一個(gè)X-Frame-Options: deny頭部,此方案可以在運(yùn)維端配置阱洪,通過(guò)配置nginx來(lái)實(shí)現(xiàn)便贵。X-Frame-Options頭部的值還可以設(shè)置為其他的,具體參考文末的參考資料冗荸。

  2. 通過(guò)CSP(Content Security Policy)機(jī)制來(lái)實(shí)現(xiàn)承璃。實(shí)現(xiàn)CSP機(jī)制也有兩種方案:a. 通過(guò)Content Security Policy頭部來(lái)控制。b. 通過(guò)在html代碼中加上meta標(biāo)簽的形式來(lái)控制蚌本,例如<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">盔粹。

總結(jié)

綜上所述,為了防范CSRF攻擊程癌,我們要做好如下三點(diǎn):

  1. 對(duì)于用戶提交的數(shù)據(jù)做過(guò)濾和轉(zhuǎn)義舷嗡,防止<script>標(biāo)簽被存入。
  2. 對(duì)于cookie設(shè)置http-only嵌莉,阻止js訪問(wèn)之进萄。
  3. 防止頁(yè)面未經(jīng)授權(quán)的iframe。

當(dāng)然锐峭,各種攻擊手段和漏洞層出不窮中鼠,也許還有其他的攻擊形式我沒(méi)有想到,或許這三種手段也無(wú)法做到盡善盡美的防護(hù)沿癞,歡迎大家一起來(lái)留言討論研究援雇。

我相信只有從原理上理解了這些攻擊手段,才能從源頭找到應(yīng)對(duì)的策略椎扬,對(duì)于本文有表述的不到位的惫搏,或理解有誤的地方也歡迎大家提出指正具温。

完!

參考資料
MDN - X-Frame-Options
MDN - Content Security Policy (CSP)
laravel - CSRF Protection
[Proposal] Allow setting XSRF-TOKEN cookie as httpOnly for XSS attacks
wikipedia - Cross-site request forgery
CSRF令牌為什么要通過(guò)HTTP頭部而不是cookie來(lái)驗(yàn)證

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末筐赔,一起剝皮案震驚了整個(gè)濱河市铣猩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌川陆,老刑警劉巖剂习,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異较沪,居然都是意外死亡鳞绕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)尸曼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)们何,“玉大人,你說(shuō)我怎么就攤上這事控轿≡┲瘢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵茬射,是天一觀的道長(zhǎng)鹦蠕。 經(jīng)常有香客問(wèn)我,道長(zhǎng)在抛,這世上最難降的妖魔是什么钟病? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮刚梭,結(jié)果婚禮上肠阱,老公的妹妹穿的比我還像新娘。我一直安慰自己朴读,他們只是感情好屹徘,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著衅金,像睡著了一般噪伊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上氮唯,一...
    開(kāi)封第一講書(shū)人閱讀 52,156評(píng)論 1 308
  • 那天酥宴,我揣著相機(jī)與錄音,去河邊找鬼您觉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛授滓,可吹牛的內(nèi)容都是我干的琳水。 我是一名探鬼主播肆糕,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼在孝!你這毒婦竟也來(lái)了诚啃?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤私沮,失蹤者是張志新(化名)和其女友劉穎始赎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體仔燕,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡造垛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晰搀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片五辽。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖外恕,靈堂內(nèi)的尸體忽然破棺而出杆逗,到底是詐尸還是另有隱情,我是刑警寧澤鳞疲,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布罪郊,位于F島的核電站,受9級(jí)特大地震影響尚洽,放射性物質(zhì)發(fā)生泄漏悔橄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一翎朱、第九天 我趴在偏房一處隱蔽的房頂上張望橄维。 院中可真熱鬧,春花似錦拴曲、人聲如沸争舞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)竞川。三九已至,卻和暖如春叁熔,著一層夾襖步出監(jiān)牢的瞬間委乌,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工荣回, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留遭贸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓心软,卻偏偏與公主長(zhǎng)得像壕吹,于是被迫代替她去往敵國(guó)和親著蛙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359