Нужно ли шифровать SecureString при сохранении на диск?
Для консольного приложения C# мне нужно сохранить пароль в настройках приложения, но когда я создаю настройку типа System.Security.SecureString
Сам параметр удаляется из обычного текстового файла конфигурации. Поскольку я больше не вижу необработанного значения, я не могу проверить, зашифрованы ли данные при сохранении.
Является SecureString
лучший подход или я должен использовать ProtectedData
просто зашифровать строку?
--EDIT-- Вот тестовый код, который я использовал, чтобы проверить, что 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);
}
1 ответ
Вы не можете сохранить данные, зашифрованные с помощью SecureString. Ключ хранится в памяти и длится до тех пор, пока ваша программа жива. SecureString - это оболочка для встроенной функции CryptProtectMemory.
Если вам нужно, чтобы зашифрованные данные были сохраняемыми (дольше, чем ваша программа существует), вам нужен API защиты данных (DPAPI) и его функция CryptProtectData, которая предоставляется пользователям C# через класс ProtectedData.
SecureString имеет преимущество в том, что он эфемерный; полезный для:
- пароли
- номера кредитных карт
- Номера социального страхования
пока они используются вашей программой, а затем удалены.
DPAPI лучше для длительного хранения. Но остерегайтесь уровней защиты, и вы выбираете тот, который соответствует тому, что вам нужно:
- только расшифровывается мной
- только расшифровывается на этом ПК
- расшифровывается только кем-либо в домене
Если вам необходимо шифрование, которое может выдержать транспортировку на другие сайты или разные домены: CryptProtectData не для вас.
Четыре уровня
- CryptProtectMemory (SecureString в.NET): полезно только в памяти вашего процесса
- CryptProtectData (ProtectedData в.NET): шифрует большой массив данных, и вы можете хранить его где угодно (память, реестр, жесткий диск), но вы должны хранить его самостоятельно.
- CredWrite: шифрует пароль с помощью CryptProtectData и сохраняет его для вас в хранилище паролей Windows (Пуск → Диспетчер учетных данных)
- CredUIPromptForCredentials/CredUIConfirmCredentials: запрашивать у пользователя пароль, шифровать его и сохранять в хранилище паролей (Пуск → Диспетчер учетных данных) с помощью CredWrite.
Как говорится в MSDN,
Значение экземпляра SecureString автоматически защищается с помощью механизма, поддерживаемого базовой платформой, когда экземпляр инициализируется или когда значение изменяется.
Если вы хотите предоставить механизм, позволяющий хранить его только для чтения после сохранения пароля в securestring, вы можете вызвать метод MarkAsReadonly()
в теме.
Для настойчивости вы можете также Hash SecureString
и создать соль для этого. Вы можете получить соль для последующего использования, например, для сравнения. Проверьте этот фрагмент кода, который использует соль над Securestring
,