将 BinaryFormatter.Deserialize 更改为 DataContractSerializer for Concurrent Dictionary

问题描述

我正在开发一个使用 BinaryFormatter.Deserialize 的应用程序已经有一段时间了。我们最近运行了 CheckMarx 漏洞扫描,将其标记为问题。 Microsoft even calls it "dangerous"。序列化不是 CheckMarx 的标志,所以我打算保持原样,我需要保持与现有客户的兼容性,而不是彻底改变。

我在反序列化 ConcurrentDictionary 时遇到问题。 首先我尝试了 XmlSerializer,但发现它不支持 IDictionary。 然后我尝试了 DataContractSerializer,因为它确实支持字典,但也失败了。

CheckMarx 标记的漏洞方式

using (FileStream fs = new FileStream(_savePath,FileMode.Open,FileAccess.Read,FileShare.Read))
{
     BinaryFormatter formatter = new BinaryFormatter();
     fileCache = (ConcurrentDictionary<string,string>)formatter.Deserialize(fs);
}

我现在正在尝试什么

using (FileStream fs = new FileStream(_savePath,FileShare.Read))
{
     DataContractSerializer serializer = new DataContractSerializer(typeof(ConcurrentDictionary<string,string>));
     ConcurrentDictionary<string,string> conDict;
     
     //I tried this way,which Failed - "Unexpected end of file."
     conDict = (ConcurrentDictionary<string,string>)serializer.Readobject(fs);

     //I tried this way,which also Failed - "The data at the root level is invalid. Line 1,position 1."
     XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs,new XmlDictionaryReaderQuotas());
     conDict = (ConcurrentDictionary<string,string>)serializer.Readobject(reader,true);
}

感谢您的任何建议。

解决方法

如果您至少不能远离 BinaryFormatter(这不是保护它的最佳方法,尤其是在您的应用程序是高风险的情况下)是设置 Binder 属性带有 SerializationBinder 的 BinaryFormatter:

using (FileStream fs = new FileStream(_savePath,FileMode.Open,FileAccess.Read,FileShare.Read))
{
     BinaryFormatter formatter = new BinaryFormatter();
     formatter.Binder = new DictionaryDeserializationBinder();
     fileCache = (ConcurrentDictionary<string,string>)formatter.Deserialize(fs);
}

public class DictionaryDeserializationBinder : SerializationBinder
{
    public override Type BindToType(string assemblyName,string typeName)
    {
        if (typeName.Equals("XmlDictionaryReader")){
            return typeof(XmlDictionaryReader);
        }
        return null;
    }
}

上面的代码需要一些编辑,因为我不确定您想要反序列化并验证它是什么类型。还有一个假设是检查您传递到字典中的数据,而不仅仅是检查是否有危险的 .NET 类型产生