Сохранение SecureString - PullRequest
       25

Сохранение SecureString

7 голосов
/ 29 сентября 2008

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

Да.

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

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

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

Ответы [ 7 ]

5 голосов
/ 29 сентября 2008

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

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

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

4 голосов
/ 25 ноября 2008

Возможно, вы захотите взглянуть на сравнение хэша пароля.
У вас будет соль из имени пользователя и, возможно, другой константы, за которой следует строка. Затем вы передадите это алгоритму хеширования, например, 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)) и сравнение с сохраненным хешем.

3 голосов
/ 29 сентября 2008

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

3 голосов
/ 29 сентября 2008

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

1 голос
/ 29 сентября 2008

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

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

1 голос
/ 29 сентября 2008

Возможно, вы захотите взглянуть на IsolatedStorageFileStream класс . Он определяет способы записи и хранения файловых данных, которые могут быть доступны только вашей сборке.

Я не думаю, что вы можете использовать SecureString на нем, хотя.

0 голосов
/ 07 сентября 2011

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

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

Простой способ сделать это, например, использовать BCryt Library (, где есть .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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...