使用 XML 序列化时保护敏感值(密码)

本文关键字:密码 XML 序列化 保护 使用 | 更新日期: 2023-09-27 18:31:23

我们有一个保存用户登录配置文件的类,这是一个简单的类,我们只是序列化到磁盘。 我们当然可以加密、压缩等序列化过程,但是,出于其他原因,我想保持简单。

序列化的一项是密码 (字符串) 属性。 我不介意它被序列化,但我希望序列化的值是 3DES 加密的,这样如果有人在某个阅读器中打开文件,它不会损害密码。 我知道我可以简单地将密码值设置为加密值并获取加密值,但我想稍微自动化一下,以便在调用 GET'er 时处理解密,SET'er 处理加密,因此它是无缝的。

你建议最好的方法是什么? 我在想的是我需要将"密码"属性标记为序列化程序忽略,它只是指向另一个属性的路径,该属性保存加密值并因此返回解密。 这是处理此问题的最佳/唯一方法吗? 只是想看看是否有更简单的方法,然后再通过我可以看到的唯一方法对其进行编码,以将加密/解密保持在序列化类逻辑中。

谢谢。

使用 XML 序列化时保护敏感值(密码)

您可以将密码属性标记为序列化忽略,并使用要序列化的包装器属性:

public class LogonInfo
{
    [XmlIgnore]
    public string Password { get; set; }
    public string EncPassword {
    {
        get
        {
            return Encrypt(Password);
        }
        set
        {
            Password = Decrypt(value);
        }
    }
    // TODO: add Encrypt and Decrypt methods
}

您可以使用 ExtendedXmlSerializer。如果某个类具有需要加密的属性:

public class Person
{
    public string Name { get; set; }
    public string Password { get; set; }
}

您必须实现接口 IPropertyEncryption。例如,它将显示 Base64 编码,但在现实世界中最好使用更安全的东西,例如。RSA.:

public class Base64PropertyEncryption : IPropertyEncryption
{
    public string Encrypt(string value)
    {
        return Convert.ToBase64String(Encoding.UTF8.GetBytes(value));
    }
    public string Decrypt(string value)
    {
        return Encoding.UTF8.GetString(Convert.FromBase64String(value));
    }
}

在 Person 类配置中,您需要指定要加密的属性:

public class PersonConfig : ExtendedXmlSerializerConfig<Person>
{
    public PersonConfig()
    {
        Encrypt(p => p.Password);
    }
}

然后,您必须注册 PersonConfig 类和 IPropertyEncryption 的实现。在文档中描述了使用 Autofac 的配置。有简单的配置:

var toolsFactory = new SimpleSerializationToolsFactory();
// Register your config class
toolsFactory.Configurations.Add(new PersonConfig());
// If you want to use property encryption you must register your implementation of IPropertyEncryption, e.g.:
toolsFactory.EncryptionAlgorithm = new Base64PropertyEncryption(); 
ExtendedXmlSerializer serializer = new ExtendedXmlSerializer(toolsFactory);

然后你可以序列化对象:

var obj = new Person {Name = "John", Password = "Ab238ds2"};
var xml = serializer.Serialize(obj);

您的 xml 将如下所示:

<?xml version="1.0" encoding="utf-8"?>
<Person type="ExtendedXmlSerialization.Samples.Encrypt.Person">
    <Name>John</Name>
    <Password>QWIyMzhkczI=</Password>
</Person>

ExtendedXmlSerializer 还有许多其他有用的功能:

  • 从标准 XMLSerializer 反序列化 xml
  • 具有属性接口的序列化类
  • 序列化循环引用和引用 ID
  • 旧版本的 xml 的反序列化
  • 属性加密
  • 自定义序列化程序

ExtendedXmlSerializer 支持 .net 4.5 和 .net Core。您可以将其与WebApi和AspCore集成。

我会使用您喜欢的任何方法存储密码的哈希值,例如 MD5。在内存或磁盘上,实际密码都不会存储。然后,要进行身份验证,请获取输入的明文密码,再次对其进行哈希处理,并根据存储的哈希进行检查。这样,身份验证仍然有效,但除了初始输入之外,密码明文不可用。在初始输入期间,密码很容易受到攻击,因为它必须在接收数据和散列数据之间位于内存中以进行比较。由于这个时间很短,攻击不太可能,但有可能。

在程序的这个阶段,SecureString将是散列之前存储密码的不错选择。这在哈希之前提供密码的自动加密,并允许您指定何时从内存中删除对象。

如果第三方获得哈希,这对他们来说是无用的,因为它是不可逆的。此外,如果他们尝试使用哈希登录,您的程序将再次对其进行哈希处理,但检查失败。为了更加偏执,您也可以始终加密整个文件!

我假设这是在本地发生的,或者网络连接是加密的(例如,https)。根据上面的评论,切勿通过网络发送明文密码。