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

时间:2012-04-17 20:56:53

标签: c# .net security xml-serialization

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

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

您认为最好的方法是什么?我在想的是我需要将序列化程序忽略的“密码”属性标记为它,它只是另一个保存加密值的属性的路径,因此将其解密。这是处理此问题的最佳/唯一方法吗?只是想看看是否有一种更简单的方法在我编写之前通过唯一的方式我可以看到这样做以保持加密/解密在序列化类逻辑中。

感谢。

3 个答案:

答案 0 :(得分:11)

您可以将serial属性标记为序列化,并使用要序列化的包装属性:

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
}

答案 1 :(得分:2)

您可以使用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
  • 带有属性接口的序列化类
  • 序列化循环引用和参考标识
  • 旧版xml的反序列化
  • 属性加密
  • 自定义序列化程序

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

答案 2 :(得分:1)

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

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

如果第三方获得哈希值,则对它们没用,因为它与正确的算法不可逆。如果他们尝试使用哈希登录,你的程序会再次哈希它,检查失败。为了更加偏执,你也可以随时加密整个文件!

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