C# Json.NET和.NET核心WebApi-防止字符串值在进程内存中持久化

C# Json.NET和.NET核心WebApi-防止字符串值在进程内存中持久化,c#,asp.net-core,json.net,asp.net-core-webapi,C#,Asp.net Core,Json.net,Asp.net Core Webapi,我有一个用.NETCore2.0编写的API,用于分发JSONWeb令牌(JWT)。这是通过一个非常简单的模型通过POST请求完成的 public class TokenRequest { public string Username { get; set; } public string Password { get; set; } } API的细节并不重要——这里的目标是防止密码在请求完成后留在内存中。让我们假设一旦字符串进入,我就可以安全地处理它——我试图解决的问题是阻止

我有一个用.NETCore2.0编写的API,用于分发JSONWeb令牌(JWT)。这是通过一个非常简单的模型通过POST请求完成的

public class TokenRequest
{
    public string Username { get; set; }
    public string Password { get; set; }
}
API的细节并不重要——这里的目标是防止密码在请求完成后留在内存中。让我们假设一旦字符串进入,我就可以安全地处理它——我试图解决的问题是阻止Json.NET将值分配给字符串,从而导致它被扣押

编辑:正如回答中指出的,字符串没有在这里实习,这是我的错误。即便如此, 我担心的是,密码可能会以我无法控制的方式(字符串)在内存中停留很长时间,而不是以我可以控制的方式(字节数组,当我使用完它后可以将其归零)。为了清楚起见,我删除了更多关于实习的内容

为了测试,我一直在发出请求,并使用WinDbg来确定这些值是否作为字符串存在于内存中

我的原始模型不能按原样工作,因为它使用了
字符串
——即使我的代码中没有任何内容引用
密码
,但它被反序列化的事实最终会将字符串放入进程内存中,直到它被垃圾回收

知道这一点,我尝试了这种模式:

public class TokenRequest
{
    public string Username { get; set; }
    public byte[] Password { get; set; }
}
这实际上是可行的,但问题是
Password
现在必须是base64编码的字符串。我在内存中找不到原始的base64值或作为字符串的解码值,这很好,但将密码base64编码是不可取的

我已经看过了
JsonTextReader
的源代码,这很有道理--
ReadAsBytes
使用字符数组和字节数组进行读取,而不是字符串。但不幸的是,base64要求是硬编码的

编辑:进一步考虑后,密码可能仍然以未进行GCD的字节数组的形式存在于内存中——字节数组我无法控制,因为它们是Json.NET内部的

因此,我尝试了一个自定义JsonConverter:

public class TokenRequest
{
    public string Username { get; set; }
    [JsonConverter(typeof(ByteConverter))]
    public byte[] Password { get; set; }
}
这与原始的问题相同——Json.NET在为转换器解析值时通过字符串发送值,因此即使转换器的
ReadJson
方法只不过是
returnnewbyte[]{},仍然可以在内存中找到该值

摘要

我希望在.NET Core WebAPI中获得一个纯文本字符串值,并在请求完成后将其从内存中删除,而无需等待垃圾回收

什么样的作品,但不受欢迎

  • 使用
    byte[]
    (注意必须是base64编码)
什么不起作用

  • 使用任何类型的
    JsonConverter
    (Json.NET内部使用字符串)
  • 在任何容量下使用Ngen(可能可行,但不是一种选择)

运行时创建的字符串不会被暂存,除非有明确要求对其进行暂存。我认为这可能只是对实习的一种混淆。我认为您更可能看到的是尚未被垃圾回收的内存(或者已经并没有被重新分配)

您可能想看看这个问题:


正如一些问题回答中提到的:您似乎在防御物理安全问题,而不是代码/数据安全问题。我没有在json.net中使用SecureString,但我怀疑这不会解决您的问题。

字符串实习的好处。我想在发布之前我已经足够了解它了,但如果不是每个字符串都被拘留,那么很明显,它不会永远挂在进程内存中。但是,字符串在被垃圾收集之前可能会在内存中挂起很长一段时间,这对于密码来说似乎仍然是不可取的。@Tninja,你能详细说明一下为什么你认为SecureString不会有帮助吗?@Dealdiane如果密码被发布到web服务上,那么在你可以将其放入SecureString之前,它将在内存中。而且你不应该这么做。永远不要从字符串构造SecureString对象,因为敏感数据已经受到不可变字符串类的内存持久性影响。构造SecureString对象的最佳方法是从一个字符一个字符的非托管源,如Console.ReadKey方法请看。SecureString就足够了,只要我能够在不经过字符串的情况下将其放入内存,并将其保留在内存中一段不确定的时间。我试图限制潜在危害的范围,而不是完全消除它。如果在任何地方使用明文,总会有方法获得它。我不担心恶意攻击;这些需要以不同的方式处理。我试图减少大量密码通过被动方法(如内存转储)意外暴露的可能性。这些是Active Directory帐户,可以访问许多不同的资源。@Tninja我现在明白你的意思了。没有看到整个画面,尤其是
输入
。如果字符串在请求之前已加密并以64位为基数,该怎么办?在接收时,您必须将其转换为字节数组,对其进行解密,并将每个字节(char)存储到SecureString中。内存中仍有字节数组,但已加密。