XDomainRequest——限制、局限性和變通方案
本文翻譯自微軟官網的一篇文章,名稱是 XDomainRequest – Restrictions, Limitations and Workarounds
本文原作者是EricLaw,前微軟正式員工。2004到2012年在微軟擔任IE程序經理(Program Manager)。
譯文如下:
更新:IE10 以上的瀏覽器支持使用 XMLHTTPRequest 對象,進行跨域資源共享(CORS)訪問。IE11 廢棄了 XDomainRequest 對象,并且此對象在IE11的Edge模式下不可用。
IE8 引入了 XDomainRequest 對象。XDomainRequest 對象允許 AJAX 應用程序在滿足一定條件的時候,直接發(fā)起安全的跨域請求。這個條件是:當數(shù)據(jù)源指明 HTTP 響應是公共的,并且AJAX應用程序可以確保 HTTP 響應只被當前頁面讀取。在那種方式下,同源策略安全保證是受到保護的。為此,HTTP 響應需要指明自身是允許跨域訪問的。實現(xiàn)方式很簡單,只需給 HTTP 響應加上Access-Control-Allow-Origin響應頭,并把這個響應頭的值設置成 * 或者是發(fā)起這個請求的頁面的域名。
當設計XDomainRequest這個新對象的時候,我們工作的最高優(yōu)先級是確保不讓現(xiàn)存的網站和服務置于險地。為了這個目標,我們把許多限制強加到使用XDomainRequest對象發(fā)送的各種各樣的請求上。絕大多數(shù)限制被設計用來阻止針對遺留服務的跨站點請求偽造攻擊(Cross-Site Request Forgery 即CSRF)。
這篇文章剩下的部分描述了這些限制和這些限制背后的原因。
1.必須使用 HTTP 或 HTTPS 協(xié)議訪問目標 URL
這一條很簡單——因為 XDomainRequest 對象依賴于一個HTTP響應頭來實現(xiàn)訪問控制,XDomainRequest 對象要求目標 URL 符合 HTTP 或 HTTPS 協(xié)議,以便于 XDomainRequest 對象檢驗響應頭。檢驗響應頭的目的是為了得到一個允許調用者訪問 HTTP 響應的許可。
2.只能使用 HTTP 的 GET 方法和 POST 方法訪問目標 URL
為了確保新加的XDomainRequest對象不會增加現(xiàn)有的服務器和服務的受到攻擊的可能性,我們選擇把這個對象可以調用的HTTP方法限制在只有GET方法和POST方法兩種。符合HTML 4.01 標準的表單被限制只能使用這兩個同名的方法。這意味著任何冒險使用 XDomainRequest 對象的服務,也容易受到來自于跨源 HTML 表單的攻擊。既然 HTML 表單已經好好地存在了超過十年,大家都假設應用程序可以抵御使用 GET和POST方法的攻擊行為。
我們假設使用其他方法發(fā)布的請求不會在服務器上做出和GET/POST一樣的處理。除此之外,大多數(shù)開發(fā)者想要使用的其他方法 (比如 WebDAV / REST methods) 也要求發(fā)送自定義 HTTP 報頭信息,請接著往下看:
3.請求中不能加入自定義的報頭
這條限制類似于第二條。我們想要確保XDomainRequest對象不會允許攻擊者發(fā)送一個HTML表單不會發(fā)送的請求。這一點非常重要。因為直到HTTP響應從服務器返回的時候, 瀏覽器才能使用Access-Control-Allow-Origin響應頭,所以瀏覽器在請求發(fā)送之前沒法分辨服務器是否愿意接受跨域的請求。沒有了這些限制,即使服務器沒有返回Access-Control-Allow-Origin響應頭,也有可能發(fā)生針對遺留服務器的“即發(fā)即棄”跨站點請求偽造攻擊(CSRF)。
所有XDomainRequest對象發(fā)送的請求帶有一個 Origin 請求頭,顯示調用頁面的源(域名)。
4.只支持 text/plain 作為請求報頭Content-Type的取值
在 XDomainRequest 對象最開始的版本中,我們允許這個對象按照Content-Type規(guī)范發(fā)送 POST 請求。因為HTML表單僅限于用三種不同的內容類型(即Content-Type取值)發(fā)送數(shù)據(jù):text/plain, application/x-www-urlencoded 和 multipart/form-data,所以讓 XDomainRequest 遵循Content-Type規(guī)范的做法被認為違反了我們只讓XDomainRequest發(fā)送HTML表單請求的目標。特別地,有人指出一些 AJAX服務器編程庫會盲目地做出如下假設:如果編程庫接收到 Content-Type 報頭取值是SOAP或者JSON的請求,那么客戶端要么是可信的,要么是同源的(因為以前HTML自身沒法發(fā)送Content-Type為SOAP或JSON的請求)。
很不幸,當我們在一個較晚的IE8 beta版本修復了這個問題的時候,我們走得太遠了;我們把 Content-Type 限制成 text/plain,但是不允許調用者指定數(shù)據(jù)是 application/x-www-urlencoded 形式的。上面的做法會人為制造困難,這是因為服務器端框架(比如ASP,ASP.NET等)只有在 Content-Type 請求頭被設置成 x-www-urlencoded 的情況下,才能自動地把請求域解析成名-值對。
注意:截至2014年,XDomainRequest 看起來好像再也不會發(fā)送任何Content-Type請求頭了,我不清楚什么時候變的。
為了應對這個問題,當服務器接收到來自XDomainRequest對象的請求的時候,當前處理HTML表單的服務器代碼必須重寫,來手動地把請求體解析成名-值對。這使得添加XDomainRequest對象的支持功能變得比原先困難得多。
5.身份驗證和cookie不能和請求一起發(fā)送
為了阻止對用戶的環(huán)境驗證(比如cookies、HTTP身份驗證、客戶端證書等等)的誤用,請求將會失去cookies和身份驗證,并且將會忽略任何身份驗證請求或HTTP響應中設置 cookies 的指令。因為一些 Windows 驗證協(xié)議(比如NTLM/Kerberos)是基于每個連接的,而不是基于每個請求的;所以 XDomainRequests 不會在以前驗證過的連接上發(fā)送請求。
那些希望發(fā)送跨域用戶身份驗證請求的網站,可以使用清楚明白的方法(比如把令牌放在POST請求體中或者是URL里)來傳送驗證信息,而不要冒險使用用戶的環(huán)境驗證。
6.只能在企業(yè)網域內發(fā)起指向企業(yè)內網URL的請求
正如文檔表格所顯示的那樣,XDomainRequest 限制企業(yè)網域內的頁面向本地基于企業(yè)內網的資源發(fā)起請求。這種安全預防措施不是被HTML表單直接強制加上去的,而是IE瀏覽器的區(qū)域提升安全特性提供了一種相似的網頁導航保護,恰好表單提交只是一種特殊的網頁導航。
7.請求URL必須和主頁URL采用相同的協(xié)議
這條限制意味著如果你的發(fā)起AJAX請求的頁面URL是 http://example.com ,那么你發(fā)起AJAX請求的URL必須是HTTP開頭。相似地,如果你的發(fā)起AJAX請求的頁面URL是 https://example.com ,那么你發(fā)起AJAX請求的URL必須是HTTPS開頭。
我們的意圖就是阻止HTTPS頁面使用XDomainRequest向HTTP資源發(fā)起請求,這是由于此方案防止了許多開發(fā)者和絕大多數(shù)用戶都不明白的混合內容安全威脅。
然而,這種限制過于寬泛,因為此限制阻止了HTTP頁面向HTTPS頁面發(fā)起XDomainRequest請求。當HTTP頁面自身采用了妥協(xié)HTTPS方案的時候,就沒有理由禁止HTTP頁面接收公有的安全內容。
最蹩腳的是,相同URL協(xié)議的限制意味著,web開發(fā)者在本地使用本地文件傳輸協(xié)議file:// 做測試的時候,將會發(fā)現(xiàn)全部的XDomainRequests被阻塞了。原因是本地文件傳輸協(xié)議file:// 既不匹配HTTP協(xié)議,也不匹配HTTPS協(xié)議,同時只有HTTP協(xié)議和HTTPS協(xié)議是有效的請求URL協(xié)議(參考第1條限制)。為了解決這個議題,web開發(fā)者必須把他們的頁面放在本地web服務器(比如IIS,Visual Studio的服務器)上運行。
為了跨越這條限制,你可以建立 postMessage-Proxy-for-XDR 。
盡管存在這些限制和沒有預料到的局限性,XDomainRequest對象還是提供了強大的功能。隨著支持跨域資源共享(CORS)規(guī)范的服務器越來越普遍,XDomainRequest對象只會變得越來越有用。
更新:IE10現(xiàn)在支持使用XMLHTTPRequest對象來進行跨域資源共享(CORS)訪問。應該使用XMLHTTPRequest對象而不是現(xiàn)在已經廢棄的XDomainRequest對象。
注意:我們打算用XDomainRequest對象支持COMET流技術,但AJAX開發(fā)者可能需要處理一個對象支持響應流的BUG。
注意:IE8,在用戶使用InPrivate瀏覽模式瀏覽網站的時候,所有的XDomainRequest 將會失敗并報錯。IE9修復了這個BUG。
原文鏈接:XDomainRequest——限制、局限性和變通方案


浙公網安備 33010602011771號