代码检测时会出现堆检查问题:
问题描述:
摘要
以不安全的方式存储敏感数据使得可以通过检查堆来提取数据。
解释
存储在内存中的敏感数据(如密码、社会安全号码、信用卡号码等)
如果存储在托管字符串对象中,则可能泄漏。字符串对象没有被钉住,所以垃圾
收集器可以随意重新定位这些对象,并在内存中留下多个副本。这些对象不是
默认情况下加密,所以任何人都可以读取进程的内存将能够看到的内容。
此外,如果进程的内存被交换到磁盘,则字符串的未加密内容将被删除。
写入交换文件。最后,由于字符串对象是不可变的,因此移除字符串的值。
只能由CLR垃圾收集器完成。垃圾回收器不需要运行。
除非CLR内存不足,所以不能保证何时进行垃圾回收。
在应用程序崩溃的情况下,应用程序的内存转储可能会显示敏感数据。
Example 1: The following method returns a password from the console and stores it in an insecure String
object.
public static void UseSecureString(SecureString ss)
{
IntPtr ssAsIntPtr = Marshal.SecureStringToGlobalAllocUnicode(ss);
String ssAsString = Marshal.PtrToStringUni(ssAsIntPtr);
// work with ssAsString
}
Recommendation
Instead of working with the contents of a secure string by converting it to a String, use the Read-family of
methods in the Marshal class.
Example 2: The following method returns a password from the console and stores it in a SecureString
object and is manipulated by the Marshal class.
static void ManipulateSecureString()
{
// SecureString, with some data
SecureString ss = new SecureString();
ss.AppendChar('a');
ss.AppendChar('s');
ss.AppendChar('d');
ss.AppendChar('f');
// copy data as unicode character array to a buffer in unmanaged space
IntPtr ssAsIntPtr = Marshal.SecureStringToGlobalAllocUnicode(ss);
for (Int32 i = 0; i < ss.Length; i++)
{
// multiply 2 because Unicode chars are 2 bytes wide
Char ch = (Char)Marshal.ReadInt16(ssAsIntPtr, i * 2);
// do something with each char
}
// don't forget to free it at the end
Marshal.ZeroFreeGlobalAllocUnicode(ssAsIntPtr);
}
解决方式我是采用SecureString的数据类型:
正常的String类型值,在脱离开作用域之后,其值在内存中并不会被立即销毁,这时如果有人恶意扫描你的内存,程序中所保存的机密信息就会暴露;于是就有了System.Security.SecureString,SecureString表示一个应保密的文本,它在初始化时就已被加密,并且脱离作用域后会被立即销毁;
可以参考:https://www.cnblogs.com/Andrew-XinFei/p/5287948.htm
String类型和SecureString的相互转换:
/// <summary>
/// SecureString 转 string
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static String SecureStringToString(SecureString value)
{
IntPtr bstr = Marshal.SecureStringToBSTR(value);
try
{
return Marshal.PtrToStringBSTR(bstr);
}
finally
{
Marshal.FreeBSTR(bstr);
}
}
/// <summary>
/// Demonstrate how to convert String into SecureString
/// </summary>
public static SecureString StringToSecureString(String value)
{
SecureString password = new SecureString();
char[] pass = value.ToCharArray();
for (int i = 0; i < pass.Length; i++)
{
password.AppendChar(pass[i]);
}
return password;
}
如果这样改不掉的话,也可以直接改变量命名。