PHP開發(fā)中csrf攻擊的簡單演示和防范
csrf攻擊,即cross site request forgery跨站(域名)請求偽造,這里的forgery就是偽造的意思。網(wǎng)上有很多關(guān)于csrf的介紹,比如一位前輩的文章CSRF的攻擊方式詳解,參考這篇文章簡單解釋下:csrf 攻擊能夠?qū)崿F(xiàn)依賴于這樣一個簡單的事實(shí):我們在用瀏覽器瀏覽網(wǎng)頁時通常會打開好幾個瀏覽器標(biāo)簽(或窗口),假如我們登錄了一個站點(diǎn)A,站點(diǎn)A如果是通過cookie來跟蹤用戶的會話,那么在用戶登錄了站點(diǎn)A之后,站點(diǎn)A就會在用戶的客戶端設(shè)置cookie,假如站點(diǎn)A有一個頁面siteA-page.php(url資源)被站點(diǎn)B知道了url地址,而這個頁面的地址以某種方式被嵌入到了B站點(diǎn)的一個頁面siteB-page.php中,如果這時用戶在保持A站點(diǎn)會話的同時打開了B站點(diǎn)的siteB-page.php,那么只要siteB-page.php頁面可以觸發(fā)這個url地址(請求A站點(diǎn)的url資源)就實(shí)現(xiàn)了csrf攻擊。
上面的解釋很拗口,下面舉個簡單的例子來演示下。
1,背景和正常的請求流程
A站點(diǎn)域名為html5.yang.com,它有一個/get-update.php?uid=uid&username=username地址,可以看到這個地址可以通過get方法來傳遞一些參數(shù),假如這個頁面的邏輯是:它通過判斷uid是否合法來更新username,這個頁面腳本如下:
<?php // 這里簡便起見, 從data.json中取出數(shù)據(jù)代替請求數(shù)據(jù)庫 $str = file_get_contents('data.json'); $data = json_decode($str, true); // 檢查cookie和請求更改的uid, 實(shí)際應(yīng)檢查數(shù)據(jù)庫中的用戶是否存在 empty($_COOKIE['uid']) ||empty($_GET['uid']) || $_GET['uid'] != $data['id'] ? die('非法用戶') : ''; // 檢查username參數(shù) $data['username'] = empty($_GET['username']) ? die('用戶名不能為空') : $_GET['username']; // 更新數(shù)據(jù) $data['username'] = $_GET['username']; if(file_put_contents('data.json', json_encode($data))) { echo "用戶名已更改為{$data['username']}<br>"; } else { die('更新失敗'); }
正常情況下這個頁面的鏈接是放在站點(diǎn)A下面的,比如A站點(diǎn)的csrfdemo.php頁面,用戶登錄站點(diǎn)A以后可以通過點(diǎn)擊這個鏈接來發(fā)送請求,比如站點(diǎn)A有一個頁面腳本,包含了這個鏈接:
<?php // 這里用一個data.json文件保存用戶數(shù)據(jù),模擬數(shù)據(jù)庫中的數(shù)據(jù) // 先初始化data.json中的數(shù)據(jù)為{"id":101,"username":"jack"}, 注意這句只讓它執(zhí)行一次, 然后把它注釋掉 // file_put_contents('data.json','{"id":101,"username":"jack"}'); $data = json_decode(file_get_contents('data.json'), true); // 這里為了簡便, 省略了用戶身份驗(yàn)證的過程 if ($data['username']) { // 設(shè)置cookie setcookie('uid', $data['id'], 0); echo "登錄成功, {$data['username']}<br>"; } ?> <a rel="external nofollow" > 更新用戶名為json </a>
加載這個頁面如下:
用點(diǎn)擊頁面中的鏈接來到get-update.php頁面:
上面是正常的請求流程,下面來看B站點(diǎn)是如何實(shí)現(xiàn)csrf攻擊的。
2,csrf攻擊的最簡單實(shí)現(xiàn)
B站點(diǎn)域名為test.yang.com,它有一個頁面csrf.php,只要用戶在維持A站點(diǎn)會話的同時打開了這個頁面,那么B站點(diǎn)就可以實(shí)現(xiàn)csrf攻擊。至于為什么會打開......,其實(shí)這種情景在我們?yōu)g覽網(wǎng)頁時是很常見的,比如我在寫這篇博客時,寫著寫著感覺對csrf某個地方不懂,然后就百度了,結(jié)果百度出來好多結(jié)果,假如說有個網(wǎng)站叫csrf百科知識,這個網(wǎng)站對csrf介紹的非常詳細(xì)、非常權(quán)威,那么我很可能會點(diǎn)進(jìn)去看,但是這個網(wǎng)站其實(shí)是個釣魚網(wǎng)站,它在某個訪問頻率很高的頁面中嵌入了我博客編輯頁面的url地址,那么它就可以實(shí)現(xiàn)對我博客的csrf攻擊。好了,言歸正傳,下面來看下csrf.php腳本代碼:
<?php ?> <img src="http://html5.yang.com/csrfdemo/get-update.php?uid=101&username=jsonp">
下面再來訪問下A站點(diǎn)的csrfdemo.php頁面:
可以看到用戶名被修改為了jsonp。
簡單分析下:B站點(diǎn)的這個csrf.php利用了html中的img標(biāo)簽,我們都知道img標(biāo)簽有個src屬性,屬性值指向需要加載的圖片地址,當(dāng)頁面載入時,加載圖片就相當(dāng)于向src指向的地址發(fā)起http請求,只要把圖片的地址修改為某個腳本地址,這樣自然就實(shí)現(xiàn)了最簡單的csrf攻擊。如此說來,其實(shí)csrf很容易實(shí)現(xiàn),只不過大家都是“正人君子”,誰沒事會閑著去做這種“下三濫”的事情。但是害人之心不可有,防人之心不可無。下面看下如何簡單防范這種最簡單的csrf攻擊。
3,簡單防范措施
其實(shí)防范措施也比較簡單,A站點(diǎn)可以在get-update.php腳本中判斷請求頭的來源,如果來源不是A站點(diǎn)就可以截?cái)嗾埱?,下面在get-update.php增加些代碼:
<?php // 檢查上一頁面是否為當(dāng)前站點(diǎn)下的頁面 if (!empty($_SERVER['HTTP_REFERER'])) { if (parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST) != 'html5.yang.com') { // 可以設(shè)置http錯誤碼或者指向一個無害的url地址 //header('HTTP/1.1 404 not found'); //header('HTTP/1.1 403 forbiden'); header('Location: http://html5.yang.com/favicon.ico'); // 這里需要注意一定要exit(), 否則腳本會接著執(zhí)行 exit(); } } $str = file_get_contents('data.json'); // 代碼省略
但是,這樣就萬事大吉了嗎,如果http請求頭被偽造了呢?A站點(diǎn)升級了防御,B站點(diǎn)同時也可以升級攻擊,通過curl請求來實(shí)現(xiàn)csrf,修改B站點(diǎn)的csrf.php代碼如下:
<?php $url = 'http://html5.yang.com/csrfdemo/get-update.php?uid=101&username=jsonp'; $refer = 'http://html5.yang.com/'; // curl方法發(fā)起csrf攻擊 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); // 設(shè)置Referer curl_setopt($ch, CURLOPT_REFERER, $refer); // 這里需要攜帶上cookie, 因?yàn)锳站點(diǎn)get-update.php對cooke進(jìn)行了判斷 curl_setopt($ch, CURLOPT_COOKIE, 'uid=101'); curl_exec($ch); curl_close($ch); ?> <img src="http://html5.yang.com/csrfdemo/get-update.php?uid=101&username=jsonp">
4,小結(jié)
下面我們回到問題的開始,站點(diǎn)A通過cookie來跟蹤用戶會話,在cookie中存放了重要的用戶信息uid,get-update.php腳本通過判斷用戶的cookie正確與否來決定是否更改用戶信息,看來靠cookie來跟蹤會話并控制業(yè)務(wù)邏輯是不太安全的,還有最嚴(yán)重的一點(diǎn):get-update.php通過get請求來修改用戶信息,這個是大忌。所以站點(diǎn)A可以接著升級防御:用session來代替cookie來跟蹤用戶會話信息,將修改用戶信息的邏輯重寫,只允許用post方法來請求用戶信息。站點(diǎn)B同樣可以升級攻擊:curl可以構(gòu)造post請求,劫持session等等,不過這些我還沒研究過,后續(xù)再說吧。
相關(guān)文章
CI框架驗(yàn)證碼CAPTCHA輔助函數(shù)用法實(shí)例
這篇文章主要介紹了CI框架驗(yàn)證碼CAPTCHA輔助函數(shù)用法,以實(shí)例形式詳細(xì)講述了基于CAPTCHA輔助函數(shù)實(shí)現(xiàn)驗(yàn)證碼的方法,需要的朋友可以參考下2014-11-11Laravel5.1 框架數(shù)據(jù)庫操作DB運(yùn)行原生SQL的方法分析
這篇文章主要介紹了Laravel5.1 框架數(shù)據(jù)庫操作DB運(yùn)行原生SQL的方法,結(jié)合實(shí)例形式分析了laravel5.1使用DB運(yùn)行原生SQL的相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2020-01-01Laravel如何創(chuàng)建服務(wù)器提供者實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于Laravel如何創(chuàng)建服務(wù)器提供者的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Laravel具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04PHP+FFMPEG實(shí)現(xiàn)將視頻自動轉(zhuǎn)碼成H264標(biāo)準(zhǔn)Mp4文件
最近做一個在線教學(xué)網(wǎng)的項(xiàng)目,需要實(shí)現(xiàn)上傳任意格式視頻自動為h264標(biāo)準(zhǔn)視頻,使用html5播放。最終使用PHP+FFMPEG實(shí)現(xiàn),在此將詳細(xì)解決方案分享給大家!2014-09-09