11

網頁內嵌 JSON 注意事項

 3 years ago
source link: https://blog.darkthread.net/blog/escape-script-in-json/
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.

網頁內嵌 JSON 注意事項

2021-01-07 08:29 PM 0 2,468

在輸出網頁時內嵌 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),應不致遇到問題。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK