XSS攻击原理、示例和防范措施 --
XSS攻擊
XSS(Cross-Site Scripting,跨站腳本)攻擊歷史悠久,是危害范圍非常廣的攻擊方式。
Cross-Site Stripting的縮寫本應(yīng)該是CSS,但是為了避免和Cascading style sheets(層疊樣式表)的縮寫混淆,所以將Cross(即交叉)使用交叉形狀的X表示。
攻擊原理
XSS是注入攻擊的一種,攻擊者通過將代碼注入被攻擊者的網(wǎng)站中,用戶一旦訪問訪問網(wǎng)頁便會執(zhí)行被注入的惡意腳本。XSS攻擊主要分為反射性XSS攻擊(Reflected XSS attack)和存儲型XSS攻擊(Stored XSS Attack)兩類。
攻擊示例
反射型XSS(非持久型)
反射性XSS有稱為非持久型XSS(Non-Persistent XSS)。當(dāng)某個站點存在XSS漏洞時,這種攻擊會通過URL注入攻擊腳本,只有當(dāng)用戶訪問這個URL是才會執(zhí)行攻擊腳本。
例如:
@app.route('/hello1')
def hello1():
name = request.args.get('name')
response = '<h1>Hello, %s!</h1>' %name
這個視圖函數(shù)接收用戶通過查詢字符串(URL后邊的參數(shù))傳入的數(shù)據(jù),未做任何處理就把它直接插入到返回的響應(yīng)主題中,返回給客戶端。如果某個用戶輸入了一段JavaScript代碼作為查詢參數(shù)name的值:
http://127.0.0.1:5000/hello4?name=<script>alert('Bingo!')</script>
那么客戶端收到的響應(yīng)將變成下面的代碼:
<h1>Hello,<script>alert(‘Gingo!’)</script>!</h1>
當(dāng)客戶端收到響應(yīng)后,瀏覽器解析這行代碼就會打開一個彈窗,下圖是firefox瀏覽器(55.0版本)上的響應(yīng)。
在chrome 72.0版本上的響應(yīng):
下面在IE11上的響應(yīng)。
可見針對跨站攻擊,某些瀏覽器已經(jīng)做了安全防范。
不要覺得一個小彈窗不會造成什么危害,能夠執(zhí)行alert()函數(shù)就意味著通過這種方式可以執(zhí)行任務(wù)JS代碼。即攻擊者通過javaScript幾乎可以做任何事情:竊取用戶的cookie和其他敏感數(shù)據(jù),重定向到釣魚網(wǎng)站,發(fā)送其他請求,執(zhí)行注入轉(zhuǎn)賬、發(fā)布廣告信息、在社交網(wǎng)站關(guān)注某個用戶等。
即使不插入js代碼,通過HTML和XSS注入也可以影響頁面正常的輸出,篡改頁面樣式,插入圖片等。
如果網(wǎng)站A存在XSS漏洞,攻擊者將包含攻擊代碼的鏈接發(fā)送給網(wǎng)站A的用戶Foo,當(dāng)Foo訪問這個鏈接時就會執(zhí)行攻擊代碼,從而受到攻擊。
存儲型XSS(持久型)
存儲型XSS也被稱為持久型XSS(persistent XSS),這種類型的XSS攻擊更常見,危害也更大。它和反射型XSS類似,不過會把攻擊代碼存儲到數(shù)據(jù)庫中,任何用戶訪問包含攻擊代碼的頁面都會被殃及。
比如,某個網(wǎng)站通過表單接收用戶的留言,如果服務(wù)器接收數(shù)據(jù)后未經(jīng)處理就存儲到數(shù)據(jù)庫中,那么用戶可以在留言中出入任意javaScript代碼。比如攻擊者在留言中加入一行重定向代碼:
<script>window.location.href=”http://attacker.com”;<script>
其他任意用戶一旦訪問關(guān)于這條留言的頁面,包含這條留言的數(shù)據(jù)就會被瀏覽器解析,就會執(zhí)行其中的javaScript腳本。那么這個用戶所在頁面就會被重定向到攻擊者寫入的站點。
防范措施
HTML轉(zhuǎn)義
防范XSS攻擊最主要的方法是對用戶輸入的內(nèi)容進(jìn)行HTML轉(zhuǎn)義,轉(zhuǎn)義后可以確保用戶輸入的內(nèi)容在瀏覽器中作為文本顯示,而不是作為代碼解析。
這里的轉(zhuǎn)義和python的概念相同,即消除代碼執(zhí)行時的歧義,也就是把變量標(biāo)記的內(nèi)容標(biāo)記文本,而不是HTML代碼。具體來說,這會把變量中與HTML相關(guān)的符號轉(zhuǎn)換為安全字符,以避免變量中包含影響頁面輸出的HTML標(biāo)簽或惡意的javaScript代碼。
比如,在flask中我們可以使用JinJa2提供的escape()函數(shù)對用戶傳入的數(shù)據(jù)進(jìn)行轉(zhuǎn)義:
from jinja2 import escape
@app.route('/hello')
def hello():
name = request.args.get('name')
response = '<h1>Hello, %s!</h1>' %escape(name)
return response
在Jinja2中,HTML轉(zhuǎn)義相關(guān)的功能通過flask的依賴包MarkupSafe實現(xiàn)。
調(diào)用escape()并傳入用戶輸入的數(shù)據(jù),可以獲得轉(zhuǎn)義后的內(nèi)容,前面的示例中,用戶輸入的javaScript代碼將被轉(zhuǎn)義為:
<script>alert('Bingo!')</script>
轉(zhuǎn)義后,文本中的特殊字符(比如“>”和“<”)都將被轉(zhuǎn)義為HTML實體(character entity),這行文本最終在瀏覽器中會被顯示文文本形式的Hello, <script>alert('Bingo!')</script>!
如圖:
在python中,如果你想在單引號標(biāo)記的字符串中顯示一個單引號,那么你需要在單引號前添加一個反斜線來轉(zhuǎn)義它,也就是把它標(biāo)記為普通文本,而不是作為特殊字符解釋。在HTML中,也存在許多保留的特殊字符,比如大于小于號。如果你想以文本顯示這些字符,也需要對其進(jìn)行轉(zhuǎn)義,即使用HTML字符實體表示這些字符。HTML實體就是一些用來表示保留符號的特殊文本,比如<表示小于號,"表示雙引號。
一般我們不會再視圖函數(shù)中直接構(gòu)造返回的HTML響應(yīng),而是會使用Jinja2來渲染包含變量的模板,
驗證用戶輸入
XSS攻擊可以在任何用戶可定制內(nèi)容的地方進(jìn)行,例如圖片引用、自定義鏈接。僅僅轉(zhuǎn)義HTML中的特殊字符并不能完全規(guī)避XSS攻擊,因為在某些HTML屬性中,使用普通的字符也可以插入javaScript代碼。除了轉(zhuǎn)義用戶輸入外,我們還需要對用戶的輸入數(shù)據(jù)進(jìn)行類型驗證。在所有接收到用戶輸入的地方做好驗證工作。
以某個程序的用戶資料頁面為例,我們來演示一下轉(zhuǎn)義無法完全避免的 XSS攻擊。程序允許用戶輸入個人資料中的個人網(wǎng)站地址,通過下面的方式顯示在資料頁面中:
<a href=”{{url}}”>Website</a>
其中{{url}}部分表示會被替換為用戶輸入的url變量值。如果不對URL進(jìn)行驗證,那么用戶就可以寫入javaScript代碼,比如”javascript:alert(‘Bingo!’);”。因為這個值并不包含會被轉(zhuǎn)義的<和>。最終頁面上的連接代碼會變?yōu)椋?/p>
<a href=”javascript:alert(‘Bingo!’);”>Website</a>
當(dāng)用戶單擊這個鏈接時,瀏覽器就會執(zhí)行被href屬性中設(shè)置的攻擊代碼。
另外,程序還允許用戶設(shè)置頭像圖片的URL。這個圖片通過下面的方式顯示:
<img src=”{{url}}”>
類似的,{{url}}部分表示會被替換為用戶輸入的url變量值。如果不對輸入的URL進(jìn)行驗證,那么用戶可以將url設(shè)為”xxx”onerror=”alert(‘Bingo!’)”,最終的<img>標(biāo)簽就會變?yōu)椋?/p>
<img src=”xxx”onerror=”alert(‘Bingo!’)”>
在這里因為src中傳入了一個錯誤的URL,瀏覽器變回執(zhí)行onerror屬性中設(shè)置的javaScript代碼。
如果你想允許部分HTML標(biāo)簽,比如<b>和<i>,可以使用HTML過濾工具對用戶輸入的數(shù)據(jù)進(jìn)行過濾,僅保留少量允許使用的HTML標(biāo)簽,同時還要注意過濾HTML標(biāo)簽的屬性。
總結(jié)
以上是生活随笔為你收集整理的XSS攻击原理、示例和防范措施 --的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基础10 多进程、协程(multipr
- 下一篇: 黑客扫描特征及十种最易受攻击端口 (转自