【发布时间】:2016-06-15 10:00:42
【问题描述】:
这里关于托管环境中内存分配的大多数答案都说“您不需要为这些事情烦恼,让平台来处理它”。事实上,在某些情况下,您确实需要担心这些事情。 我有一个对象列表,在内存转储的情况下,我不想在连续地址的直线行上按顺序分配。我要他们分散。 有什么办法(一个技巧或黑客会做)来确保对象不是按顺序分配的,并且不能被识别为内存转储中的一个序列? 谢谢!
编辑: 这样做的原因是我试图规避 MySQL for .NET 要求我将敏感数据作为连接字符串传递的方式。我的想法是将所有内容保存在一个分散的字符列表中,然后在 connection.Open() 之前组装它,然后立即处理它。有没有更好的办法?我宁愿不要像那样将数据库凭据保存在内存中。
结论:似乎不可能通过分散敏感数据来防止内存转储。在我的具体情况下,我将尽可能使用 SecureString,并将寻找其他方法不将未加密的密码暴露给 MySQL。
更新:经过一番挖掘,这就是我最终要做的事情:我所有的 SQL 都由本地服务执行,帐户仅限于存储过程和 localhost。为了请求 SP 调用,客户端必须通过 SHA512 哈希密码 + salt 进行身份验证。在客户端,密码从文本框中逐个字符地读取,并附加到安全字符串上,然后将文本替换为系统密码字符。然后对安全字符串进行哈希处理,并将原始数据清零,如下所示:
public static string GetSHA512(SecureString secureInput)
{
if (secureInput == null)
throw new ArgumentNullException("securePassword");
IntPtr unmanagedString = IntPtr.Zero;
byte[] dataUnmanaged = new byte[secureInput.Length];
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocAnsi(secureInput);
Marshal.Copy(unmanagedString, dataUnmanaged, 0, dataUnmanaged.Length);
using (SHA512 shaM = new SHA512Managed())
{
byte[] hash = shaM.ComputeHash(dataUnmanaged);
int i = 0;
while (i < dataUnmanaged.Length)
{
dataUnmanaged[i] = 0;
i++;
}
StringBuilder hex = new StringBuilder(hash.Length * 2);
foreach (byte b in hash)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
}
finally
{
int i = 0;
while (i < dataUnmanaged.Length)
{
dataUnmanaged[i] = 0;
i++;
}
Marshal.ZeroFreeGlobalAllocAnsi(unmanagedString);
}
}
生成的哈希值进一步使用随机盐进行哈希处理,并与盐一起发送到服务进行确认。服务用盐重新散列其散列并进行比较。一旦获得批准,将通过不断更改客户端和服务器跟踪的唯一会话 ID 来进行进一步的身份验证。任何劫持和会话立即失效。这样,密码只使用一次,只传输双散列,并尽可能短地存储在 SecureString 中。 这是我能想到的最好的。如果有新内容我会进一步更新,谢谢大家。
【问题讨论】:
-
没有。垃圾收集器无论如何都会重新排列它们。即使它们在内存中没有“排序”,它们也很容易找到。让我提一下WinDbg + SOS +
!dumpheap -
感谢您的评论。我根本不精通内存转储,所以我不知道 SOS 是什么,但根据您的估计,从内存转储中按照原始顺序从集合中查找对象有多容易?另外,你是说GC会按照集合中的顺序对内存中的对象进行排序?
-
@Daniel “从内存转储中按照原始顺序从集合中查找对象有多容易?”。这是一个相当简单的任务。
-
找到有问题的列表肯定需要一些时间,因为转储中通常有很多列表(如果不是 HelloWorld)。完成后,很简单:stackoverflow.com/q/2198805/480982
-
使用
SecureString和加密代替。
标签: c# memory memory-management allocation