Сохранение SecureString

Одно из пожеланий, которые у меня есть для программы, над которой я работаю, заключается в том, чтобы иметь возможность сохранять список учетных данных, которые вводят пользователи, чтобы ими можно было делиться. Конкретный вариант использования, вызвавший этот запрос, заключался в использовании нашей программы в большой корпоративной сети, состоящей из довольно хороших локальных сетей, соединенных нестабильной глобальной сетью. Идея заключалась в том, что вместо того, чтобы наша программа боролась с глобальной сетью, когда она не работает, они должны были отправить файл «конфигурации», содержащий тщательно охраняемые учетные данные администратора, запустить его в каждой локальной сети, заархивировать результаты и отправить по электронной почте. назад.

Ага.

Мой первоначальный инстинкт - насмехаться над этой просьбой - сохранение паролей? правда? и, конечно же, сетевое подразделение компании предпочло бы, чтобы вы попытались продать любые продукты WAN, которые у них есть, но оказалось, что один из классов, для которых я использую учетные данные, может принимать SecureString, и, Что ж, всегда полезно искать способы сэкономить людям немного усилий. Это заставило меня задуматься:

Можно ли сохранить зашифрованную SecureString, чтобы я мог сохранить конфиденциальные данные в файл и открыть его в другом месте?

Что вы думаете, переполнение стека?


person Merus    schedule 29.09.2008    source источник
comment
Как вы имеете в виду общий доступ в случае сбоя сети? Можете ли вы уточнить это, пожалуйста?   -  person Justin Bozonier    schedule 29.09.2008


Ответы (7)


В SecureString нет поддержки сохранения, он предназначен для защиты управляемой строки в памяти и используется только для взаимодействия с неуправляемыми API. Если бы пароль хранился в экземпляре System.String, безопасность была бы меньше из-за природы System.String. Существование сборки мусора и интернирования будет удерживать пароль в памяти дольше, чем необходимо. Кроме того, из-за множества отличных инструментов отладки для .NET было бы значительно проще получить доступ к строке через отражение или другой API .NET даже без увеличения времени жизни.

Если вы собираетесь сохранить пароль на диске, ваша безопасность сильно скомпрометирована. Если кто-то имеет физический доступ к машине или удаленный доступ на уровне администратора, то лучшее, что вы можете сделать, — это усложнить задачу, но никогда не делать ее невозможной. Используйте API шифрования, храните его в безопасном месте, настраивайте права доступа.

Помимо всего этого, Мерус, я бы посоветовал вам попытаться улучшить систему в целом, потому что для варианта использования, который вы описываете (при условии, что я его понимаю), вам лучше хранить хэш, чем фактический пароль.

person nedruod    schedule 29.09.2008
comment
Я надеялся, что SecureString сделает за меня хэш. Я знаю лучше, чем свернуть свою собственную хеш-функцию. - person Merus; 29.09.2008
comment
В powershell можно сохранить SecureString любым способом с помощью С# ?? stackoverflow.com/questions/11174425/ - person Kiquenet; 02.07.2012

Возможно, вы захотите сравнить хэш пароля.
У вас будет соль, состоящая из имени пользователя и, возможно, какой-то другой константы, за которой следует строка. Затем вы передадите это алгоритму хеширования, например SHA1*.
Например,

using System.Security.Cryptography;

public byte[] GetPasswordHash(string username, string password, string salt)
{
    // get salted byte[] buffer, containing username, password and some (constant) salt
    byte[] buffer;
    using (MemoryStream stream = new MemoryStream())
    using (StreamWriter writer = new StreamWriter(stream))
    {
        writer.Write(salt);
        writer.Write(username);
        writer.Write(password);
        writer.Flush();

        buffer = stream.ToArray();
    }

    // create a hash
    SHA1 sha1 = SHA1.Create();
    return sha1.ComputeHash(buffer);
}

Затем вы сравните результат для GetPasswordHash(username, expectedPassword, salt) с GetPasswordHash(username, givenPassword, salt).
Если вы реализуете свой собственный список пользователей с именами пользователей и паролями, вы можете сохранить только хэш (GetPasswordHash(username, givenPassword, salt)) и сравнить его с сохраненным хэшем.

person configurator    schedule 25.11.2008
comment
иногда сравнение заданного пароля не является задачей, а сама программа хочет использовать пароли для авторизации в другой системе. Как и почтовый клиент, используйте пароль для авторизации на SMTP-сервере. что мы можем сделать в этой ситуации - person Siva Sankaran; 29.11.2012
comment
@Sankaran: В каждом случае есть свое решение. Большинство современных API уже принимают хэши паролей; у некоторых есть ключи API, поэтому вам даже не нужно знать хэш пароля. Чтобы использовать более старые API, которые поддерживают только использование пароля напрямую, у вас не было бы другого выбора, кроме как сохранить сам пароль. В этом случае я бы использовал какое-то шифрование, хотя это довольно бесполезно. - person configurator; 29.11.2012
comment
MD5 совершенно не подходит для выбора алгоритма хеширования. Вам нужен bcrypt или scrypt, или хотя бы по крайней мере sha1 (и даже это не очень рекомендуется). - person Joel Coehoorn; 23.03.2015
comment
@JoelCoehoorn: абсолютно верно. Наверное, в 2008 году я этого не знал. Я соответственно обновил сообщение, чтобы использовать SHA1, потому что, в отличие от bcrypt, SHA1 встроен в .Net. - person configurator; 28.03.2015

Если вы имеете в виду сохранение зашифрованных байтов SecureString, то это не сработает - ключ для SecureString привязан к пользователю и процессу. Прочитайте эти байты в другом процессе или для другого пользователя, и нет никакого способа расшифровать строку.

person Michael Burr    schedule 29.09.2008

Это нарушило бы точку SecureString, которая гарантированно будет находиться в памяти. Поэтому, если вы сохраняете его в файл, вы можете также сохранить его как обычную строку, поскольку она больше не является «безопасной».

person Spodi    schedule 29.09.2008


SecureString не является сериализуемым, поэтому вы не можете просто сохранить его с помощью некоторых поставляемых сериализаторов (двоичных, XML и т. д.).

вы также не можете просто получить доступ, например. свойство «Пароль» из объекта securestring, поскольку такого не существует. Вы должны использовать Marshalling и немного сантехники, чтобы сделать это. если вы хотите где-то хранить учетные данные пользователя, я предлагаю зашифровать их самостоятельно, так как это облегчает дальнейшую разработку. после оценки подхода SecureString мы решили реализовать что-то сами, но это только мои 2 цента.

person Joachim Kerschbaumer    schedule 29.09.2008

Как указано здесь, SecureString — не лучший способ использования в этом сценарии.

Если бы мне нужно было поделиться учетными данными пользователя, я бы, вероятно, поделился именем пользователя и хешированным паролем с солью, чтобы вы были в безопасности и делитесь только представлением пароля, а не его содержимым.

Простой способ сделать это, например, использовать библиотеку BCryt (где есть представление .NET) и просто разместить представление имени пользователя и пароля в таблице, готовой к совместному использованию.

Вот как вы будете его использовать:

StringBuilder sb = new StringBuilder();

// run ADO.NET / Entity Framework / etc and query your DB with something like:
"SELECT user_id, username, password FROM [TblUsers];"

// loop through the results

sb.AppendFormat(
       "INSERT INTO [TblSharedUsers] SELECT '{0}','{1}','{2}'",            
           dr["id"], dr["username"],
           BCrypt.HashPassword(dr["password"], BCrypt.GenerateSalt(12));
       );

// then run sb.ToSTring() agains your db

на стороне клиента вы можете создать новый AuthenticationProvider (чтобы его было легко изменить, когда сеть недоступна, используя IoC и DI), который читает из TblSharedUsers и проверяет пароль пользователя, например

string userPassword = Request["password"];

"SELECT id, password FROM [TblSharedUsers] WHERE username = @usr;"

if( BCrypt.CheckPassword(userPassword, dr["password"]) )
    // User can log in
else
    // Credentials are invalid

Я надеюсь, что это поможет кому-то с той же проблемой.

person balexandre    schedule 07.09.2011