【古蹟維修日記】JSONP 呼叫無聲卡與 MIME Sniffing 資安漏洞
0 |
記錄最近維護古蹟遇到的問題一枚。
接到通報,老系統某個使用 JSONP 呼叫第三方網頁執行指定作業並接收回覆,不知何時開始失效了。
客戶端程式類似這樣:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSONP Test</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<div>
<button id="btnTest">JSONP Test</button>
<textarea id="txtResult" rows="4" cols="50" style="display:block; margin-top:6px;">
</textarea>
</div>
<script>
function handleResponse(data) {
console.log(data);
}
$('#btnTest').click(function() {
$.ajax({
url: 'http://172.23.160.1/aspnet/jsonp/api.aspx',
data: { userId: 'Jeffrey' },
dataType: 'jsonp',
success: function(data) {
$('#txtResult').val(JSON.stringify(data));
}
});
});
</script>
</body>
</html>
奇妙的是,使用 F12 監看 JSONP 呼叫,HTTP 狀態 200,但沒有回應內容:
意思是 api.aspx程式有成功執行 (HTTP 200)也回傳了,但資料長度是 0 Byte?收到一張無聲卡?
困惑了一陣子,同事改用 Chrome 測試才出現轉機。Chrome 執行相同網頁也是無回應,但有提供一則錯誤代碼 ERR_BLOCKED_BY_ORB
。
ORB 是 Opaque Response Blocking 的縮寫,指瀏覽器可依要求,拒絕處理「不透明的回應」(Opaque Responses),意指沒有明確標示的 MIME 類型,或者 MIME 類型與實際內容不匹配。而有個 Header X-Content-Type-Options: nosniff 可要求瀏覽器嚴格遵守資源的 MIME 類型,禁止進行「MIME 類型嗅探」(MIME Type Sniffing) 自動偵測並設定 MIME Type 以免形成資安漏洞。(延伸閱讀:資安議題 — Http Security Header by LSZ)
舉個例子,若網站允許使用者上傳 .jpg 檔。攻擊者寫了一段內含 JavaScript 的 HTML 假裝 .jpg 上傳,其他使用者瀏覽該圖片時若瀏覽器啟用 MIME Type Sniffing 自動識別校正成網頁呈現,攻擊者的惡意 JavaScript 便會被執行。
回頭看這個重現情境中的 api.aspx,內容像以下這樣。有兩大重點,1) 有回傳 Header X-Content-Type-Options: nosniff 2) 未指定 MIME Type。
<%@Page Language="C#"%>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
Response.Headers.Add("X-Content-Type-Options", "nosniff ");
var callback = Request.QueryString["callback"];
if (!string.IsNullOrEmpty(callback) &&
System.Text.RegularExpressions.Regex.IsMatch(callback, "^[a-zA-Z0-9_]+$"))
{
Response.Write(callback + "({name:'Jeffrey', score:32767})");
}
else
{
Response.Write("Invalid callback");
}
}
</script>
搞懂這些,要解決就簡單了,加上 Response.ContentType = "application/javascript" 就好了。
<%@Page Language="C#"%>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
Response.Headers.Add("X-Content-Type-Options", "nosniff ");
var callback = Request.QueryString["callback"];
if (!string.IsNullOrEmpty(callback) &&
System.Text.RegularExpressions.Regex.IsMatch(callback, "^[a-zA-Z0-9_]+$"))
{
Response.ContentType = "application/javascript";
Response.Write(callback + "({name:'Jeffrey', score:32767})");
}
else
{
Response.Write("Invalid callback");
}
}
</script>
搞定收工。
This post describes a JSONP callback issue in an old system. The problem, identified as ERR_BLOCKED_BY_ORB in Chrome, was due to missing MIME type specification. Solution: Adding Response.ContentType = "application/javascript" in the server-side code resolved the issue.
Comments
Be the first to post a comment