咱媽說別亂點連接之淺談CSRF攻擊

平時常常聽到人們說別亂點連接,當心有病毒。還有長輩們轉發的「天吶~XXX的陰謀,全是病毒」、「XXX驚天大病毒,點了蘋果手機就要爆炸!」、「如今轉發熱門鏈接會亂扣費!千萬別點!」。php

到底長輩們說的這些是對的仍是錯的,是真的仍是假的?下面我用通俗易懂的語言爲你們剖析。html

CSRF攻擊就是僞裝你去行騙

首先咱們說說CSRF(Cross-site request forgery),它的中文名稱是跨站請求僞造,也被稱爲:one click attack/session riding,縮寫爲:CSRF/XSRF。程序員

簡單地說,CSRF就是利用了咱們的登陸狀態或者受權狀態(請注意「利用」,並無竊取到),而後作一些損害咱們自身利益的事情。ajax

舉個例子,CSRF使用咱們微信頭像和暱稱,而後去跟咱爸媽要錢。「爸,生活費不夠了。你打到XXX帳戶上」,咱爸看見頭像和暱稱覺得是親生的,他就轉帳。如此,行騙成功。瀏覽器

GET方式形成的CSRF攻擊

長輩們說得對,連接確實不能隨便點。我用簡單的代碼舉個例子。安全

信任的網站test.com

假設咱們有一個銀行帳戶,其中有一個登陸頁面login.php和付款頁面paybill.php,這些頁面都屬於咱們信任的網站test.com(test.com網站是虛擬的)。服務器

login.php中設置cookie進行登陸:微信

<?php
    setcookie('uid', 1, time()+86400); echo "your uid is {$_COOKIE['uid']}"; 

paybill.php經過身份驗證後進行扣款,可是必須輸入收款人和扣款金額:cookie

<?php //身份驗證 if (!isset($_COOKIE['uid']) || $_COOKIE['uid']< 0) { die('login error!'); } //金額獲取 if (!isset($_GET['money'])) { die('no money'); } //收款人獲取 if (!isset($_GET['to_who'])) { die('nobody'); } $uid = $_COOKIE['uid']; $money = $_GET['money']; $to_who = $_GET['to_who']; //此處應該還有相關DB操做,省去一萬字 echo "transfer {$money} yuan to {$to_who}!"; 

刷新一下login.php,進行登陸(實際的用戶登陸更爲複雜,這裏進行簡單模擬了)session

在瀏覽器訪問paybill.php頁面,轉錢1000元給媽媽。

http://test.com/csrf/paybill.php?money=1000&to_who=mama

黑客網站

這時候黑客發現test.com網站沒有作任何防護措施,他馬上在本身的網站B上僞造了一個頁面,頁面上有這麼一個連接,他的收款人to_who變成了hacker。

<html> <head> <meta charset="utf-8"> </head> <body> <a href="http://test.com/csrf/paybill.php?money=1000&to_who=hacker" taget="_blank">震驚!!史上尺度最大的照片!!<a/> </body> </html> 

假設由於好奇心點擊了該鏈接:

這樣就轉了1000元給了hacker

爲何會出現這種狀況,咱們在別的網站點擊連接竟然能扣本身帳戶的錢?點擊連接前,咱們已經登陸了信任網站test.com,而這個test.com/csrf/paybill.php?money=1000&to_who=hacker這個鏈接是咱們本身發送的,test.com會識別當前已經登陸,而後轉帳,test.com網站沒法判斷究竟是誰讓咱們點擊的。

從上面這個實例可知,完成CSRF攻擊流程:

一、用戶登陸了信任的網站A,而且保存登陸狀態

二、黑客找出網站A沒有防護的連接,經過社會工程學假裝,誘導點擊。

三、只要登陸狀態保持,用戶主動訪問目標連接,則攻擊成功。

有人說那每次訪問其餘網站,把以前的網站都註銷。是的,這個辦法能夠,但這麼作這現實嗎?咱們須要註銷許多經常使用的網站,下次登陸又要輸入用戶名和密碼,極其反人類。這確定不是最佳辦法,防護措施應該讓程序員考慮,用戶別亂點連接是最重要的。

CSRF的攻擊渠道不必定來自其餘網站,也能夠是廣告郵件、QQ空間、微信、facebook等社交媒體或軟件。試想一下,若是你的女友知道這個連接,她在QQ上發給你:

http://test.com/csrf/paybill.php?money=1000&to_who=girlfriend你點擊後,那就轉了1000元給女友,假設她將money改爲10w,後果然的不敢想象,你竟然存了這麼私房錢,跪搓衣板吧,錢也都到了你女友帳戶上。

好了,小白用戶看見這裏能夠關閉,別亂點連接就對,該給女友的錢的仍是一分不能少。

POST也能形成CSRF攻擊

上面的CSRF能夠說至關危險,更新資源的操做不該該使用GET方式,GET方式只應該用於讀操做。更新操做必定要使用POST方式,特別涉及到錢的問題。

然而POST方式能夠解決大部分的CSRF問題,還有剩下少部分的聰明的黑客,同樣可以模擬POST請求,僞造身份進行攻擊。

假設paybill.php 咱們修改成POST取:

<?php if (!isset($_COOKIE['uid'])) { die('login error!'); } if (!isset($_POST['money'])) { die('no money'); } if (!isset($_POST['to_who'])) { die('nobody'); } $uid = $_COOKIE['uid']; $money = $_POST['money']; $to_who = $_POST['to_who']; if ($uid > 0) { echo "transfer {$money} yuan to {$to_who}!"; } 

訪問http://test.com/csrf/paybill.php?money=1000&to_who=girlfriend,提示沒有money

可是道高一尺魔高一丈,聰明的黑客也改進了代碼,使用POST提交,而且money改成2000:

<html> <head> <meta charset="utf-8"> </head> <body> <form action="http://test.com/csrf/paybill.php" method="post"> <input type="hidden" name="money" value="2000"> <input type="hidden" name="to_who" value="girlfriend"> <input type="submit" value="點擊中大獎"> </form> </body> </html> 

點擊中大獎,以下(又轉了2000元給女友):

抓包結果以下,能夠看到Cookie: uid=1money=2000&to_who=girlfriend都已發送過去。

POST http://test.com/csrf/paybill.php HTTP/1.1 Host: test.com Referer: http://hack.com/hack/welcome.php Cookie: uid=1 money=2000&to_who=girlfriend 

如此一來,無論哪一種訪問方式均可能受到攻擊。因此,這並非GET和POST誰更安全的問題,POST只是提升了攻擊門檻和成本(其實也就多幾行html和js)。

劃重點,那麼CSRF可以攻擊的根本緣由是:服務器沒法識別你的來源是否可靠。

防護CSRF的思想

那麼防護的方法有不少:

一、好比加上驗證碼。但這麼作很繁瑣,而且影響用戶體驗。

二、好比轉帳須要二次密碼驗證,如今不少銀行就這麼搞的。

三、確認來源是否可靠(推薦)

無論防護方法1仍是2,都是讓用戶自身再次確認受權。

這種安全防範的事兒,更應該由程序驗證。

根據驗證是否可靠性思路,能夠有如下幾種方法:

驗證HTTP Referer 字段

HTTP協議裏面定義了一個訪問來源的字段,這個字段叫Referer。黑客僞造的連接或表單是在其餘網站上,因此咱們能夠判斷Referer是否爲自身網站,若是是,則容許訪問,若是不是,則拒絕訪問。

從咱們的網站訪問paybill.php,抓包發現Referer是不存在的

"HTTP_REFERER"=>"" 

從黑客的網站訪問paybill.php,抓包發現Referer來自黑客網站

["HTTP_REFERER"]=> string(35) "http://hack.com/welcome.php" 而後代碼裏判斷: if (HTTP_REFERER!="") { die('多是CSRF攻擊,拒絕訪問'); } else { die('容許訪問'); } 

因此咱們只須要攔截Referer就能夠判斷是否爲攻擊。

可是這種方法是有缺陷的,上面實驗嘗試過,若是對方在QQ上發送給你一個連接呢?點擊的時候屬於主動點擊,此時同樣沒有Referer。程序會把它歸屬爲安全請求,那麼就被繞過了。而且若是某些低版本的瀏覽器存在漏洞(好比IE6),Referer頗有可能被篡改,因此這個方法並不是十全十美。

服務端驗證請求的token一致性

csrf攻擊的核心原理就是利用用戶驗證信息儲存cookie中,發送請求,使得服務器沒法判斷真僞,而token之因此可以攔截,就是由於它是csrf攻擊過程當中幾乎不可能僞造的東西。

實現原理:在服務端生成一個隨機的token,加入到HTTP請求參數中,服務器攔截請求,查看發送的token和服務端的是否一致,若一致,則容許請求;若不一致,則拒絕請求。

新增form.php表單頁面,將token存入session(不要存在cookie中,你懂的):

<?php session_start(); $csrf_token = md5(openssl_random_pseudo_bytes(32));//生成隨機token $_SESSION['token']= $csrf_token; ?> <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>csrf</title> </head> <body> <h1>轉帳</h1> <form action="paybill.php" method="POST"> money:<input type="text" name="money"> to_who:<input type="text" name="to_who"> <input type="hidden" name="token" value="<?php echo $csrf_token ?>"> <input type="submit" value="ok"> </form> </body> </html> 

paybill.php獲取token,與session中存儲的token判斷是否一致:

<?php session_start(); if (! isset($_COOKIE['uid'])) { die('login error!'); } if (! isset($_POST['money'])) { die('no money'); } if (! isset($_POST['to_who'])) { die('nobody'); } if (! isset($_POST['token']) || $_POST['token'] != $_SESSION['token']) { die('forbidden'); } $uid = $_COOKIE['uid']; $money = $_POST['money']; $to_who = $_POST['to_who']; if ($uid > 0) { echo "transfer {$money} yuan to {$to_who}!"; } 

查看頁面form.php

請求成功:

每次訪問表單頁面,都應該生成一個token:

<input type="hidden" name="token" value="a88f67a7effa917450cff12e179df35d"> 

咱們再嘗試從黑客網站進行訪問,顯示」forbidden」,證實在token驗證時被攔截:

這樣子就已經有效防護csrf攻擊。該方法能夠用於a連接和表單等請求,屬於同一個原理。

注意:網上不少文章並無生成惟一的或者隨機性較大的token,都是同一個token,這是有問題的,若是黑客看到該token,同樣能夠僞造請求,進行攻擊。

Ajax防護CSRF

實際上A jax防護的思想也能夠利用上面的token驗證方式。

在IBM上看過一篇文章說Ajax防護時,在 HTTP 頭中自定義屬性並驗證token。

它是這麼說的:

把 token 以參數的形式置於 HTTP 請求之中,而是把它放到 HTTP 頭中自定義的屬性裏。經過 XMLHttpRequest 這個類,能夠一次性給全部該類請求加上 csrftoken 這個 HTTP 頭屬性,並把 token 值放入其中。這樣解決了上種方法在請求中加入 token 的不便,同時,經過 XMLHttpRequest 請求的地址不會被記錄到瀏覽器的地址欄,也不用擔憂 token 會透過 Referer 泄露到其餘網站中去。

我的以爲不須要如此麻煩,易用性也不太好,直接對Aajx進行一次封裝,加入一個open_token的選項,true就把token也發送過去,不然不進行驗證,原理和上面是同樣的。

最好將token賦值給js的一個全局變量,整個網站均可以使用。

總結

CSRF防護原則:

  • GET方式不能用於更新資源的操做

  • POST方式請求加上隨機token驗證

OWASP 2017年的十大安全威脅已經公佈了,咱們能夠看看2013年和2017年CSRF穩穩排在第八位。

總之,CSRF是一種常見的Web安全威脅,它攻擊特色是利用用戶身份信息假裝,發送請求,形成危害。這種攻擊成本極低,但網站和用戶不注意,很容易受到傷害。固然,更使人欣賞的是黑客利用社會工程學欺騙大衆,這纔是最重要的。

若是你們對社會工程學感興趣,推薦一部電影——《我是誰:沒有絕對安全的系統》,很是精彩。

互聯網安全你攻我防,你槍我盾,沒有永遠靈驗的方法,只有學會攻擊,才能抵禦攻擊。

此文已由做者受權騰訊雲技術社區發佈,轉載請註明文章出處

相關文章
相關標籤/搜索