2015-09-21 24 views
6

我正在使用Newtonsoft JSON解串器。如何爲XSS(跨站點腳本)清理JSON?在反序列化之前清潔JSON字符串或者寫一些自定義轉換器/消毒劑?如果是這樣 - 我不能100%確定解決這個問題的最佳方法。在反序列化之前清理JSON for XSS

下面是一個JSON的例子,它注入了一個危險的腳本並需要「清理」。我想要在我對它進行反序列化之前進行管理。但是我們需要假設各種XSS場景,包括BASE64編碼腳本等,所以問題更復雜,只需要一個簡單的REGEX字符串替換即可。

{ "MyVar" : "hello<script>bad script code</script>world" } 

這裏是我的解串器的快照(JSON - >對象):

public T Deserialize<T>(string json) 
{ 
    T obj; 

    var JSON = cleanJSON(json); //OPTION 1 sanitize here 

    var customConverter = new JSONSanitizer();// OPTION 2 create a custom converter 

    obj = JsonConvert.DeserializeObject<T>(json, customConverter); 

    return obj; 
} 

JSON是從第三方UI界面發佈,所以它的相當暴露,因此服務器端驗證。從那裏開始,它會被序列化到各種對象中,並且通常存儲在數據庫中,以後可以在基於HTML的UI中直接檢索和輸出,因此腳本注入必須得到緩解。

+1

我已經更新我的問題來解決我的意思是「清理」。 – MarzSocks

+0

這取決於上下文。你能提供一些數據如何顯示的細節嗎?它會包含URL數據嗎?它會直接放入HTML嗎?它只會從JavaScript訪問嗎?它是一個HTML屬性嗎? XSS預防實際上取決於上下文。 – Gray

+1

JSON從第三方UI界面發佈,因此其相當公開且因此服務器端驗證。從那裏它被序列化爲各種對象,並且通常存儲在數據庫中,之後可以在基於HTML的UI中直接檢索和輸出,因此必須控制腳本標記。理想情況下,要在進入應用程序邏輯層之前清理它,並且序列化程序是統一它們的地方。 :-) – MarzSocks

回答

3

好吧,我會盡量保持這個比較短,因爲這是一個大量的工作,寫了整個事情。但是,基本上,您需要關注需要清理的數據的上下文。從原始文章的評論中,聽起來像JSON中的一些值將被用作將被呈現的HTML,並且該HTML來自不可信來源。

第一步是提取哪些JSON值需要作爲HTML進行消毒處理,對於每個對象,您需要通過HTML解析器運行這些對象,並將不在白名單中的所有內容刪除。不要忘記,你還需要一個白名單來表示屬性。

HTML Agility Pack是在C#中解析HTML的好起點。在我看來,如何做這部分是一個單獨的問題 - 可能是相關問題的重複。

您擔心base64字符串在我看來有點過分強調。這不像你可以簡單地把aW5zZXJ0IGg0eCBoZXJl放入一個HTML文檔中,瀏覽器就會呈現它。它可以通過JavaScript(你的白名單將被阻止)濫用,並在某種程度上通過data:網址(但這並不是那麼糟糕,因爲JavaScript將在數據頁面的上下文中運行,不好,但你不是,用這個自動吞掉餅乾)。如果您必須允許a標籤,則該流程的一部分需要驗證URL是否爲http(或任何您希望允許的方案)。

理想情況下,你會避免這種不舒服的情況,而是使用類似markdown的東西 - 那麼你可以簡單地轉義HTML字符串,但這並不總是我們可以控制的東西。儘管如此,你仍然需要做一些URL驗證。

+1

我結束了這條路線。使用HTML Agility Pack,並在轉換爲JSON期間清理字符串值。 – MarzSocks

+1

不知道你是否說過在存儲它們之前先對它們進行清理,但如果是的話,至少要保存原始文件以防萬一出現錯誤並且損壞了一些數據。如果它是第三方,而你根本沒有存儲它,那麼無論哪種方式都沒問題。很高興看到它很有用。 – Gray

2

有趣!感謝您的詢問。我們通常在web表單中使用html.urlencode。我有一個企業網絡API正在運行,有這樣的驗證。我們創建了一個自定義正則表達式來驗證。請看看這個 MSDN link

這是創建解析

public class KeyValue 
{ 
    public string Key { get; set; } 
} 

步驟1命名KEYVALUE(比方說)該請求的示例模型:使用HttpUtility:與自定義的正則表達式

var json = @"[{ 'MyVar' : 'hello<script>bad script code</script>world' }]"; 

     JArray readArray = JArray.Parse(json); 
     IList<KeyValue> blogPost = readArray.Select(p => new KeyValue { Key = (string)p["MyVar"] }).ToList(); 

     if (!Regex.IsMatch(blogPost.ToString(), 
      @"^[\p{L}\p{Zs}\p{Lu}\p{Ll}\']{1,40}$")) 
      Console.WriteLine("InValid"); 
      //   ^means start looking at this position. 
      //   \p{ ..} matches any character in the named character class specified by {..}. 
      //   {L} performs a left-to-right match. 
      //   {Lu} performs a match of uppercase. 
      //   {Ll} performs a match of lowercase. 
      //   {Zs} matches separator and space. 
      //   'matches apostrophe. 
      //   {1,40} specifies the number of characters: no less than 1 and no more than 40. 
      //   $ means stop looking at this position. 

步驟2試圖.UrlEncode - this newtonsoft website link暗示了下面的實現。

string json = @"[{ 'MyVar' : 'hello<script>bad script code</script>world' }]"; 

     JArray readArray = JArray.Parse(json); 
     IList<KeyValue> blogPost = readArray.Select(p => new KeyValue {Key =HttpUtility.UrlEncode((string)p["MyVar"])}).ToList();