3

IE 都更筆記 - CORS 與 Windows 驗證不相容問題

 2 years ago
source link: https://blog.darkthread.net/blog/ie-cors-401/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
CORS 與 Windows 驗證不相容問題-黑暗執行緒

雖然 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 的帳號密碼輸入視窗出現了,我感動到熱淚盈眶...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK