在反序列化之前清除 XSS JSON

cleaning JSON for XSS before deserializing

我正在使用 Newtonsoft JSON 解串器。如何清除 XSS(跨站点脚本)的 JSON?是在反序列化之前清理 JSON 字符串还是编写某种自定义 converter/sanitizer?如果是这样 - 我不是 100% 确定解决这个问题的最佳方法。

下面是一个 JSON 的例子,它注入了一个危险的脚本并且需要 "cleaning." 我想要在反序列化之前管理它。但是我们需要假设各种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 是从第 3 方 UI 界面发布的,因此它相当公开,因此需要服务器端验证。从那里,它被序列化为各种对象,通常存储在数据库中,稍后在基于 HTML 的 UI 中直接检索和输出,因此必须减轻脚本注入。

有趣!!谢谢你的提问。我们通常在 Web 表单方面使用 html.urlencode。我有一个企业网站 api 运行 有这样的验证。我们创建了一个自定义正则表达式来验证。请看看这个 MSDN link

这是为解析名为 KeyValue 的请求而创建的示例模型(比方说)

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

第 1 步:尝试使用自定义正则表达式

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 步: 使用 HttpUtility.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();

好的,我打算 尝试 使这篇文章简短一些,因为要写出完整的内容需要大量工作。但是,从本质上讲,您需要关注需要清理的数据的上下文。从对原始 post 的评论来看,听起来 JSON 中的某些值将用作将要呈现的 HTML,而这个 HTML 来自不受信任的来源。

第一步是提取需要作为 HTML 清理的任何 JSON 值,对于这些对象中的每一个,您需要通过 HTML 运行 它们] 解析器并删除不在白名单中的所有内容。不要忘记您还需要一个属性白名单。

HTML Agility Pack 是在 C# 中解析 HTML 的良好起点。如何做这部分在我看来是一个单独的问题 - 并且可能是链接问题的副本。

在我看来,您对 base64 字符串的担忧似乎有点过分了。这不像您可以简单地将 aW5zZXJ0IGg0eCBoZXJl 放入 HTML 文档中,浏览器将呈现它。它可以通过 javascript(您的白名单将阻止)滥用,并且在某种程度上,通过 data: url(但这并不是那么糟糕,因为 javascript 将 运行 在数据页面的上下文中。不好,但你不会自动吞噬 cookie)。如果您必须允许 a 标签,则部分过程需要验证 URL 是 http(s)(或您想要允许的任何方案)。

理想情况下,你会避免这种不舒服的情况,而是使用类似 markdown 的东西 - 然后你可以简单地转义 HTML 字符串,但这并不总是我们可以控制的。不过,您仍然需要进行一些 URL 验证。