IE 都更筆記 - CORS 與 Windows 驗證不相容問題
1 | 4,021 |
雖然 Windows 11 Edge IE 模式無法用 AD 帳號登入網站的疑慮已消除,IE Only 古蹟不致立即崩塌,但現在已是時侯該安排都更計劃,將老舊危樓逐步改建翻新,別拖到重要的事變成重要又緊急,搞出一場盛大「肝臟爆破秀」... Orz
今天遇到的問題與跨網站 AJAX 呼叫有關。我們都知道 IE 將網站區分成謂網際網路、近端內部網路、信任的網站、限制的網站等區域,而在「信任的網站」保護傘下,程式享有許多特權,可以啟用 ActiveX、無視跨站台存取限制等 (延伸閱讀:IE CORS跨網域存取的特殊規則),當轉到 Chrome 或 Edge Chromium,一切回歸 HTML 標準,問題便如雨後春筍般冒出頭。
CORS 也不是什麼難解問題,透過加入 Access-Control-Allow-Origin 及相關 Header,並設好 IIS 接收 OPTIONS Preflight,理論上就 OK 了。
用以下網頁示範:
ℎttp://127.0.0.1/aspnet/cors/client.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CORS Test</title>
</head>
<body>
<button>Test</button>
<script src="jquery-1.12.4.min.js"></script>
<script>
$('button').click(function() {
$.post('http://192.168.50.7/aspnet/cors/cross-site.aspx').done(function(res) {
alert('OK-' + res);
});
});
</script>
</body>
</html>
ℎttp://192.168.50.7/aspnet/cors/cross-site.aspx
<%@Page Language="C#"%>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
//Response.AddHeader("Access-Control-Allow-Origin", "http://127.0.0.1");
//Response.AddHeader("Access-Control-Allow-Methods", "POST,GET");
Response.ContentType = "text/plain";
Response.Write(DateTime.Now.ToString("mmssfff"));
}
</script>
由於 client.html 與 cross-site.aspx 網站 IP 不同屬於不同來源,不意外地會收到錯誤:Access to XMLHttpRequest at 'http://192.168.50.7/aspnet/cors/cross-site.aspx' from origin 'http://127.0.0.1' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
。
在 cross-site.aspx 啟用 esponse.AddHeader("Access-Control-Allow-Origin", "http://127.0.0.1"); 及 Response.AddHeader("Access-Control-Allow-Methods", "POST,GET");,即可打通跨站台存取。
到這裡都算簡單,如果我停用 cross-site.aspx 的匿名存取,改為 Windows 整合驗證,麻煩就來了。
Access to XMLHttpRequest at 'http://192.168.50.7/aspnet/cors/cross-site.aspx' from origin 'http://127.0.0.1' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
再次出現,理由是 IIS 回傳 401 要求進行身分認證,而這個回應未包含 Access-Control-Allow-Origin,直接被瀏覽器封鎖。
傳回 401 這段仍在 IIS 處理階段,還沒輪到 cross-site.apsx 執行,所以我們在 web.config 加入 Access-Control-Allow-Origin 能解決問題嗎?
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://127.0.0.1" />
<add name="Access-Control-Allow-Methods" value="GET,POST" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
加入後,上述錯誤訊息消失,但瀏覽器接收 401 錯誤卻不會帶出帳號密碼輸入視窗,以存取被拒收場。
CORS 請求涉及第三方站台,基於安全及隱私考慮通常會以匿名方式發送,不夾帶 Cookie 等身分識別。研究許久,終於查到關鍵 - XHR 有個 withCredentials 屬性,設定後 XHR 會傳送 Cookie 也能完成 Windows 身分驗證。jQuery.ajax 有個 xhrFields 可指定 withCredentials,所以 client.html 要修改如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CORS Test</title>
</head>
<body>
<button>Test</button>
<script src="jquery-1.12.4.min.js"></script>
<script>
$('button').click(function() {
$.ajax({
url: 'http://192.168.50.7/aspnet/cors/cross-site.aspx',
method: 'POST',
xhrFields: {
withCredentials: true
}
}).done(function(res) {
alert('OK-' + res);
});
});
</script>
</body>
</html>
然後,IIS 端還要加上 Access-Control-Allow-Credentials: true Header。
終於,掛著第三站台 IP 的帳號密碼輸入視窗出現了,我感動到熱淚盈眶...
Tips of how to send CORS requests to Window authentication ASP.NET pages.
Comments
# by Huang
IE逝去的美好,只能留給回憶