開發者工具 · JSON 格式化程式和驗證程序
JSON 中的重複鍵:RFC 8259 允許什麼以及解析器做什麼
· 背景
json 標準 驗證
JSON 的語法允許相同的鍵兩次,規範只說名稱「應該」是唯一的,且解析器對於哪個值獲勝有分歧。這篇文章解釋了為什麼這對正確性和安全性很重要。
伺服器讀取了哪個「角色」?
考慮 `{"role":"viewer","role":"editor"}`。兩個成員在語法上都是完整的,因此 ToolAcre 報告有效的 JSON。當文字到達 `JSON.parse` 時,產生的物件具有 `role` 屬性,其值為 `"editor"`。較早的成員不會保留為隱藏歷史記錄。因此,成功的語法檢查不會回答物件名稱是否出現多次的問題。
格式化使遺失僅在發生後才可見:輸出在所選佈局中包含 `{"role":"editor"}`。它無法重現丟棄的 `viewer` 成員,因為序列化接收的是解析後的對象,而不是原始成員序列。如果重複的名稱對審閱很重要,請在按「格式」之前保留並檢查來源文字,而不是依賴標準化結果。
語法允許,規範不鼓勵
RFC 8259 表示物件內的名稱應該是唯一的。這個「應該」促進了可互通的輸出,而不使唯一性成為基本物件語法的一部分。重複的名稱仍然由有效的字串、冒號和正確的逗號分隔位置的值組成。因此,語法驗證器可以接受該文件,而應用程式策略則拒絕該文件。
這種區別很容易被忽視,因為許多錯誤都是強制性的語法錯誤:缺少冒號或尾隨逗號根本無法形成 JSON 物件。重複的內容不同。在解析器識別出每個標記後,它們會建立一個互通性問題。 ToolAcre 有意停止在語法上,並不添加重名規則,因此其 Valid 結果不得被視為唯一性保證。
JSON.parse 和 ToolAcre 做什麼
`JSON.parse` 使用稍後出現的位置。 ToolAcre 繼承了該行為,因為它在格式化之前進行解析。對於 `{"limit":10,"limit":25,"unit":"items"}`,驗證成功,解析的限制為 25,格式化輸出包含一個 `limit`。可選的鍵排序可以重新定位倖存的屬性,但不能暴露被覆蓋的事件。
不要將該結果推廣到每個解析器或配置。某些系統可以拒絕重複項,而其他處理堆疊可能會套用不同的策略或在建構物件之前檢查令牌。安全的跨系統宣告是狹窄的:重複的名稱不能可靠地互通。當區別很重要時,檢查每個邊界使用的實際解析器模式,而不是依賴語言範圍的宣告。
當解析器分歧成為風險時
只有在元件以不同方式解釋相同文字的特定多階段路徑中,重複才會成為安全問題。例如,請求過濾器可能會檢查一次事件,而應用程式則使用另一次事件。這是否會發生取決於確切的解析器、選項、轉發行為和欄位使用。僅重複語法並不能證明是可利用的繞過方法。
可防禦控制是在信任邊界建立一項策略並測試真實堆疊。當歧義不可接受時,在有損物件建構之前拒絕重複名稱,或確保每個元件接收相同的已解析表示。 ToolAcre 可以示範自己的最後勝利格式化行為,但它無法審核不屬於瀏覽器工具的閘道、框架或服務。
工作範例:具有重複鍵的文件
貼上 `{"theme":"light","prefs":{"density":"roomy","density":"compact"},"theme":"dark"}`。 ToolAcre 接受文字,因為每個成員在語法上都是有效的。解析後,根主題為 `dark`,巢狀密度為 `compact`。格式化會發出每個名稱的一份副本,因此兩個較早的值都會從顯示的檔案中消失。
此範例也說明了為什麼搜尋格式化結果為時已晚。重複偵測必須在讀取每個物件深度的原始令牌流時觀察成員名稱。陣列不需要重複名稱規則,儘管單獨的應用程式規則可能關心重複的元素值。保持來源不變,對其執行重複感知解析器或 linter,並確定策略是警告還是拒絕。
故意偵測重複項
使用明確承諾對來源 JSON 進行重複名稱檢測的工具。適當的方法包括重複失敗的解析器模式、追蹤每個開啟物件名稱的串流令牌處理程序或具有記錄的重複鍵規則的 linter。驗證巢狀物件和轉義名稱: `"name"` 和 `"name"` 解碼為相同的成員名稱,即使它們的來源拼字不同。
JSON 一旦普通解析丟棄了早期出現的情況,模式就不能取代。模式驗證器通常接收建構的值並查看一個屬性,而不是重複的令牌歷史記錄。在解析之前或解析期間執行唯一性檢查,然後對明確的值套用架構檢查。 ToolAcre 既不執行重複偵測,也不執行架構驗證,因此兩者都需要單獨的、專門建置的步驟。
這不包括什麼
重複的物件名稱與記錄中的重複值不同。 `[ {"id":7}, {"id":7} ]` 包含兩個獨立的對象,每個對像都有一個 `id`;檢測重複標識符有一個資料集規則。同樣,具有相同字串的兩個陣列元素保留兩個有意位置,除非應用程式合約表明該陣列代表一個集合。
本文並非主張針對廣泛的語言生態系統採取普遍的先勝、後勝或拒絕政策。它記錄了 ToolAcre 可觀察到的 `JSON.parse` 行為,並解釋了為什麼必須直接檢查另一個元件。它也不能單獨確定副本的可利用性。安全影響需要證據證明不同的解釋跨越相關的授權、路由或驗證邊界。
重點:有效的 JSON 並不總是明確的 JSON
ToolAcre 有效結果意味著令牌序列是嚴格的 JSON;這並不表示每個物件名稱都是唯一的。 `JSON.parse` 保留重複名稱的最後一個值,並格式化僅序列化該倖存者。由於較早出現的內容已被刪除,因此格式化輸出不適合作為確定原始來源是否包含重複項的證據。
當唯一性很重要時,請在普通解析或格式化之前使用重複識別工具檢查原始文字。隨後對產生的明確值應用架構和域驗證。為了進行安全審查,請追蹤實際的請求路徑和解析器設置,而不是假設存在分歧。實際規則很簡單:語法接受、重名策略和下游含義是使用單獨證據的單獨檢查。