带有 XMLSerialization 的明文密码

Cleartext Password with XMLSerialization

我正在使用 XML 与第三方 Web 服务通信。一切正常,除了我们的安全扫描器报告了一些 CWE-216 缺陷。

密码确实存储在内存中 LoginDetails class 类似于下面(为了示例而简化)

[Serializable()]
public class LoginDetails
{
    public string Login { get; set; }
    public string Password { get; set; }
}

第三方要求以明文形式发送密码。所以不幸的是,我在这里的问题上别无选择。我想做的是确保该字段安全存储and/or 在使用后尽快从内存中删除。

在补救方面,我尝试同时使用 SecureString - 出于显而易见的原因 - 并使用 StringBuilder 因为这否定了不变性。我还尝试在 LoginDetails class 上实现 IDisposable。这包括将两个属性设置为空。然后我引发了各种讨论 (particularly this one),指出它并没有真正带来多大好处。

问题是,当将 Password 字段类型更改为 SecureStringStringBuilder 时 - 它们未正确序列化 - 因此第三方请求失败。有什么办法可以覆盖 XMLSerializer 以不同方式处理这些类型 - 因此它们在我们这边的内存中存储得更安全,但以明文形式传输给第三方 - 或者整个尝试毫无意义是因为双方都不会实施这些安全尝试?

或者有什么我完全忽略的吗?

非常感谢

为了解决这个问题,我创建了一个名为 SerializableSecureString 的自定义类型,实现了 IXmlSerializableIDisposable

希望以下内容对以后的人有所帮助!

实施

类型包含一个私有的SecureString成员变量,以及一个用于序列化的私有string属性。

private readonly SecureString Content = new SecureString();
private string Value { }

私有字符串属性的get解包私有成员变量如下...

get
{
    IntPtr bstr = Marshal.SecureStringToBSTR(Content);
    string copiedText = Marshal.PtrToStringAuto(bstr);
    Marshal.ZeroFreeBSTR(bstr);

    return copiedText;
}

有两个构造函数。 .Net 专门用于序列化的空构造函数...

public SerializableSecureString()
{
}

...还有一个用于类型的实际构造。它采用明文字符串并将其打包到 SecureString 变量中,如下所示...

public SerializableSecureString(string clearText)
{
    if (clearText != null)
    {
        foreach (char t in clearText)
            Content.AppendChar(t);
    }
}

序列化发生在 WriteXml 函数中 IXmlSerializable 的实现中。它使用WriteString写出私有字符串的值属性(Value)...

public void WriteXml(XmlWriter writer)
{
    writer.WriteString(Value);
}

为了处理 SecureString 值,我在 IDisposable 模式中实现了 Dispose 方法并调用了 Content.Dispose()

用法

我可以创建一个 LoginDetails class 的实例(如问题中引用的那样)...

LoginDetails loginDetails = new LoginDetails
{
    Login = "MyUsername",
    Password = new SerializableSecureString(WebConfigurationManager.AppSettings["MyPassword"])
};

密码存储在 web.config 文件的加密部分 - 因此使用 WebConfigurationManager.

使用后,可以像下面这样在finally块中处理数据

finally
{
    LoginDetails.Password.Dispose();
}