【问题标题】:JSON ToObject with SecureStringJSON ToObject 与 SecureString
【发布时间】:2017-05-31 14:28:51
【问题描述】:

我在将 JSON 文本序列化为包含 SecureString 变量的对象时遇到问题。如何在将公共“pwd”变量保持为 SecureString 的同时序列化以下内容?

假设有以下字符串:

string j_str = "{ 'uid':'JohnDoe', 'age':30, 'pwd':'MyPassword' }";

我想将此字符串序列化为我在 C# 中拥有的对象

public class User
{
   public string uid = { get; set; }
   public string age = { get; set; }
   public SecureString pwd = { get; set; }
}

所以我可以像这样使用 JSON ToObject) 调用 Newtonsoft 进行以下调用:

JObject j_obj = JObject.Parse(j_str);

User newUser = j_obj.ToObject<User>();

这会导致以下错误:

Newtonsoft.Json.JsonSerializationException: 'Error converting value "MyPassword" to type 'System.Security.SecureString'. Path 'pwd'

【问题讨论】:

  • pwd属性的类型改为string
  • “同时将公共 'pwd' 变量保留为 SecureString?” - 这看起来像 XY problem。你为什么要首先这样做?
  • 因为密码是要保存在 SecureString 中的机密,以避免被内存转储和类似攻击泄露。这表示 SecureString 没有默认的 json 序列化程序,它知道如何保密,因此还需要为 SecureString 实现一个自定义的 json 序列化程序,它会做一些类似加密的事情,这样生成的 json 就不会泄露秘密明文。

标签: c# .net json serialization json.net


【解决方案1】:

从字符串构造它似乎违背了使用 SecureString 背后的原则。见https://msdn.microsoft.com/en-us/library/system.security.securestring(v=vs.110).aspx

一个 SecureString 对象不应该从一个字符串构造, 因为敏感数据已经受制于内存 不可变 String 类的持久性后果。最好的办法 构造一个 SecureString 对象是从一个字符一次 非托管源,例如 Console.ReadKey 方法。

【讨论】:

  • 似乎,如果字符串是明文密码。但是,如果您对加密字符串进行序列化/反序列化,则不会将明文机密泄漏到内存中。此外,在许多情况下,您无法始终在 SecureString 中保密,因此您暂时将其提取到字符串或从字符串构造,之后您可以将字符串固定在不安全的代码块中以将其归零。很多示例和代码示例,包括 stackoverflow 上的许多示例。
【解决方案2】:

如前所述,这确实违反了 SecureString 的原则。但是这里有一个可以用于 SecureString 的 JSON 转换器。

using System.Runtime.InteropServices;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

public class SecureStringConverter : JsonConverter<SecureString>
{
    public override void WriteJson(JsonWriter writer, SecureString value, JsonSerializer serializer)
    {
        IntPtr ptr = Marshal.SecureStringToBSTR(value);
        writer.WriteValue(Marshal.PtrToStringBSTR(ptr));
        Marshal.ZeroFreeBSTR(ptr);
    }

    public override SecureString ReadJson(JsonReader reader, Type objectType, SecureString existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        string json_val = (string)reader.Value;
        SecureString s = new SecureString();

        if (json_val != null) 
        {
            foreach (char c in json_val) 
            {
                s.AppendChar(c);
            }
        }
        s.MakeReadOnly();
        return s;
    }
}

序列化用户:

string serialized_user = JsonConvert.SerializeObject(user, new SecureStringConverter());

反序列化serialized_user:

User deserialized_user = JsonConvert.DeserializeObject<User>(serialized_user, new SecureStringConverter());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-03
    • 1970-01-01
    • 2015-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-24
    相关资源
    最近更新 更多