同事報案,安裝SPA專案在localhost,跨網域發出AJAX請求到ServerA時出現存取被拒訊息,而該情況獨獨出現於IE11,Chrome與Firefox並無問題。
排除Web API端的CORS配套機制的問題(由Chrome及Firefox具名擔保,延伸閱讀:CORS OPTIONS Preflight Request與IIS設定),且更玄的是問題只發生在同事的IE11,在我的IE11測試本機localhost SPA專案發送同樣的AJAX需求到ServerA,一切正常。
經過一番診察,濃縮出檢測問題的極簡步驟-在F12開發工具主控台下指令$.post(httq://172.28.1.1/cors/chart/getdata, {}),正常狀況應出現CORS請求訊息如下:
失敗案例則被IE11直接拒絕,連嘗試送出Request的動作都沒有。
爬文在Stackoverflow找到一則相關討論,我注意到裡面有一段描述:
Internet Explorer has two major exceptions when it comes to same origin policy:
- Trust Zones: if both domains are in highly trusted zone e.g, corporate domains, then the same origin limitations are not applied
- Port: IE doesn't include port into Same Origin components, thereforehttp://company.com:81/index.html and http://company.com/index.html are considered from same origin and no restrictions are applied.
發現關鍵字「信任的網站區域」。檢查同事的IE11,果然找出差異:同事的IE11將ServerA設為信任的網站,我的IE無此設定,故ServerA被歸於網際網路。區域設定為IE的專利,這解釋了為何問題只發生在同事的IE,我的IE及Chrome與Firefox都正常。
但仍然有疑點,前述Stackoverflow討論只提到同屬信任網站不算Cross Site,未能解釋為何近端內部網路存取信任網站會直接被拒絕?
再用關鍵字查到一篇文章,提到IE10+有項特性:當Origin(執行發出AJAX呼叫的一方)與Host(提供資源的一方)二者只有一個在信任的網站區域,另一個不是時(例如:Origin為受信任網站,Host為近端或網際網路;或Origin為近端或網際網路,Host為受信任網站),會產生我所觀察到的存取被拒。而經實驗證實:將localhost加入信任的網站或將ServerA移出信任的網站,CORS運作便會正常。
由前述文章再找到MSDN文件,才算真相大白:
- Cross-domain requests are allowed within the same zone if the Internet Explorer security manager has allowed "Access data sources across domains" (URLACTION_CROSS_DOMAIN_DATA) either implicitly or by prompting the user.
當跨網域請求發生在同一區域,由IE安全管理員決定是否允許。(包使用CORS OPTIONS詢問) - If the request is from a more trusted security zone to a less trusted one, the security settings of the originating zone apply. (The security zones, in order of trust, are as follows: Local Machine, Trusted Sites, Local Intranet, Internet.)
當一個較安全區域向較不安全區域發出請求時,安全原則依較安全的一方決定。
各區域的安全強度依序為本機(Local Machine,注意,本機並不是指localhost,而是以file: /// URL開啟本機資料夾的網頁,參考)、信任的網站、近端內部網路。 - All cross-domain requests to or within the Restricted Sites zone are disallowed, regardless of selected security zone policy.
與限制的網站相關的跨網域請求將完全被禁止。
文章附了一張表,其中有一項重要原則-所有由較不安全區域跨網域存取較安全區域資源的行為都是被禁止的,例如:由近端內部網路存取信任網站、由網際網路存取近端內部網路…都將被拒絕。
回到我們的案例,SPA網頁在localhost執行被歸為近端內部網路,當ServerA被設為信任的網站,localhost向ServerA發出跨網域請求,就觸犯了「由較不安全區域(近端內部網路)向較安全區域(信任的網站)發出請求」的禁令,這就是IE直接拒絕該請求的依據!同時我也補做實驗,反過來將localhost設為信任的網站,將ServerA設為近端內部網路,測試CORS存取可成功,理由是情況已被逆轉為由較安全的區域向較不安全區域發出請求。因此,先前提到Origin與Host必須同屬一個區域的假設不完全正確,正確的說法應是「Origin與Host必須同區域,或者Origin所處區域的安全強度較Host來得高」。
又解開了一個謎團,感覺真好!