網頁內嵌 JSON 注意事項
0 | 6,137 |
在輸出網頁時內嵌 JSON 轉成 JavaScript 物件是我愛用的手法,這點之前有介紹過,例如以下範例:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<script>
var DataItem = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.DataItem));
</script>
</head>
<body>
<div>
</div>
</body>
</html>
不需額外寫程式,C# 端 DataItem 物件直接就轉成 JavaScript,簡潔方便,看起來沒什麼問題。
但以上寫法不夠嚴謹,讓我們動點手腳搞壞它:
public class HomeController : Controller
{
public ActionResult Index()
{
var item = new
{
Index = 255,
Name = "BOOM!!! </script>",
};
ViewBag.DataItem = item;
return View();
}
}
轟! JSON 中出現 &lgt;/script> 與上方的 &lgt;script> 配對成功,提前結束 script 區塊,JavaScript 程式不完整噴出錯誤,後方的程式碼混進 HTML 造成網頁錯亂:(提醒:若 JSON 內容由使用者輸入且未過濾 HTML 標籤,將存在被 XSS 攻擊的風險,請務必修正。另外,使用 Html.Raw() 時千萬要謹慎。)
寫過 Inline ASPX 的老人們都知道要避開這個雷(像是這篇文章出現的Response.Write("<script>parent.showMsg('" + msg + "');<" + "/script>");
),在 <script> 內嵌內容時 JSON 卻容易疏忽。Json.NET 有個 Newtonsoft.Json.StringEscapeHandling.EscapeHtml 參數,在 SerializeObject() 時傳入 JsonSerializerSettings 指定 StringEscapeHandling = StringEscapeHandling.EscapeHtml 即可輕易解決。
<script>
var DataItem = @Html.Raw(
Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.DataItem,
new Newtonsoft.Json.JsonSerializerSettings
{
StringEscapeHandling = Newtonsoft.Json.StringEscapeHandling.EscapeHtml
}));
</script>
啟用 StringEscapeHandling.EscapeHtml 後,< > 將被轉碼為 \u003c、\u003e,可避免字串內含 HTML 標籤干擾網頁解析。
如果無特殊需求,建議直接修改 JsonConvert.DefaultSettings 讓 Json.NET 預設啟用 EscapeHtml,做法可在 Global.asax.cs 或 App_Start 類別方法修改預設值,如此可避免忘記調設定出錯:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
StringEscapeHandling = Newtonsoft.Json.StringEscapeHandling.EscapeHtml
};
最後,順便看一下 ASP.NET Core。ASP.NET Core 預設已改用 System.Text.Json,官方文件有提到 System.Text.Json 原本就會換掉特殊字 字(甚至包含中文),這點之前我已見識過 - ASP.NET Core JSON 中文編碼問題與序列化參數設定,只要不要亂設 JsonSerializerOptions.Encoder (例如:JavaScriptEncoder.UnsafeRelaxedJsonEscaping),應不致遇到問題。
This aritle introduce the script tag escaping issue while embedding JSON in HTML, and how to avoid it.
Comments
Be the first to post a comment