持久化到磁盘时是否必须加密 SecureString?
Do I have to encrypt SecureString when persisting to disk?
对于 C# 控制台应用程序,我需要在应用程序设置中保留密码,但是当我创建 System.Security.SecureString
类型的设置时,设置本身会从纯文本配置文件中删除。由于我无法再看到原始值,因此我无法验证数据在保存时是否仍处于加密状态。
SecureString
是最好的方法还是我应该使用 ProtectedData
来简单地加密字符串?
--编辑--
这是我用来验证 SecureString
可以持久化的测试代码。
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.Security.SecureString Password
{
get
{
return ((global::System.Security.SecureString)(this["Password"]));
}
set { this["Password"] = value; }
}
static void Main(string[] args)
{
PersistPassword("A-Test-Password");
Console.WriteLine(ReadPassword());
Console.ReadLine();
}
static void PersistPassword(string Password)
{
SecureString ss = new SecureString();
Password.ToCharArray().ToList().ForEach(ss.AppendChar);
Settings.Default.Password = ss;
}
static string ReadPassword()
{
SecureString ss = Settings.Default.Password;
IntPtr ptr = Marshal.SecureStringToCoTaskMemUnicode(ss);
return Marshal.PtrToStringUni(ptr);
}
如 MSDN、
中所述
The value of an instance of SecureString is automatically protected using a mechanism supported by the underlying platform when the instance is initialized or when the value is modified.
如果您想提供一种机制,一旦密码存储在 securestring 中就保持只读状态,那么您可以对其调用 MarkAsReadonly()
方法。
出于持久性目的,您还可以散列 SecureString
并为其创建盐。您可以取回盐以备后用,例如比较目的。查看 this 代码片段,它在 Securestring
.
上使用盐
您无法保存使用 SecureString 加密的数据。密钥保存在内存中,并且只在您的程序处于活动状态时存在。 SecureString 是原生 CryptProtectMemory 函数的包装器。
如果您需要加密数据持久化(比您的程序存在的时间更长),您需要 数据保护 API (DPAPI),它是 CryptProtectData 函数 - 通过 ProtectedData class.
向 C# 用户公开
SecureString 的优点是短暂;适用于:
- 密码
- 信用卡号码
- 社会保险号码
当它们被您的程序使用时 - 然后被删除。
DPAPI 更适合 long-term 存储。但要注意保护级别,并选择适合您需要的级别:
- 只有我能解密
- 只能在此 PC 上解密
- 只能由域中的任何人解密
如果您需要能够传输到不同站点或不同域的加密:CryptProtectData 不适合您。
四个级别
- CryptProtectMemory(.NET 中的 SecureString):仅在进程内存中有用
- CryptProtectData(.NET 中的 ProtectedData):加密数据块,您可以将其存储在任何您喜欢的地方(内存、注册表、硬盘)——但您必须自己收藏。
- CredWrite: 使用 CryptProtectData 加密密码,并将其存储在 Windows 密码库中(开始 →凭证管理器)
- CredUIPromptForCredentials/CredUIConfirmCredentials:提示用户输入密码,加密后保存在密码库中(开始→凭证经理)使用 CredWrite
对于 C# 控制台应用程序,我需要在应用程序设置中保留密码,但是当我创建 System.Security.SecureString
类型的设置时,设置本身会从纯文本配置文件中删除。由于我无法再看到原始值,因此我无法验证数据在保存时是否仍处于加密状态。
SecureString
是最好的方法还是我应该使用 ProtectedData
来简单地加密字符串?
--编辑--
这是我用来验证 SecureString
可以持久化的测试代码。
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.Security.SecureString Password
{
get
{
return ((global::System.Security.SecureString)(this["Password"]));
}
set { this["Password"] = value; }
}
static void Main(string[] args)
{
PersistPassword("A-Test-Password");
Console.WriteLine(ReadPassword());
Console.ReadLine();
}
static void PersistPassword(string Password)
{
SecureString ss = new SecureString();
Password.ToCharArray().ToList().ForEach(ss.AppendChar);
Settings.Default.Password = ss;
}
static string ReadPassword()
{
SecureString ss = Settings.Default.Password;
IntPtr ptr = Marshal.SecureStringToCoTaskMemUnicode(ss);
return Marshal.PtrToStringUni(ptr);
}
如 MSDN、
中所述The value of an instance of SecureString is automatically protected using a mechanism supported by the underlying platform when the instance is initialized or when the value is modified.
如果您想提供一种机制,一旦密码存储在 securestring 中就保持只读状态,那么您可以对其调用 MarkAsReadonly()
方法。
出于持久性目的,您还可以散列 SecureString
并为其创建盐。您可以取回盐以备后用,例如比较目的。查看 this 代码片段,它在 Securestring
.
您无法保存使用 SecureString 加密的数据。密钥保存在内存中,并且只在您的程序处于活动状态时存在。 SecureString 是原生 CryptProtectMemory 函数的包装器。
如果您需要加密数据持久化(比您的程序存在的时间更长),您需要 数据保护 API (DPAPI),它是 CryptProtectData 函数 - 通过 ProtectedData class.
向 C# 用户公开SecureString 的优点是短暂;适用于:
- 密码
- 信用卡号码
- 社会保险号码
当它们被您的程序使用时 - 然后被删除。
DPAPI 更适合 long-term 存储。但要注意保护级别,并选择适合您需要的级别:
- 只有我能解密
- 只能在此 PC 上解密
- 只能由域中的任何人解密
如果您需要能够传输到不同站点或不同域的加密:CryptProtectData 不适合您。
四个级别
- CryptProtectMemory(.NET 中的 SecureString):仅在进程内存中有用
- CryptProtectData(.NET 中的 ProtectedData):加密数据块,您可以将其存储在任何您喜欢的地方(内存、注册表、硬盘)——但您必须自己收藏。
- CredWrite: 使用 CryptProtectData 加密密码,并将其存储在 Windows 密码库中(开始 →凭证管理器)
- CredUIPromptForCredentials/CredUIConfirmCredentials:提示用户输入密码,加密后保存在密码库中(开始→凭证经理)使用 CredWrite