Пароль SecureString хранится в базе данных

Я считаю, что неправильно понимаю фундаментальную часть SecureString. Я понимаю, что string являются неизменяемыми, и там пароль или конфиденциальные данные находятся в виде открытого текста в куче.

Я пытаюсь понять, как использовать SecureString в клиентском приложении, которому необходимо проверять хешированный пароль в базе данных?

Вот мой контекст:

  • Я использую клиентское приложение WPF.
  • У меня есть локальная база данных SQL (на машине клиента)
  • Пароли хешируются и хранятся в базе данных.
  • Пользователь пытается войти в мое приложение WPF
  • Элемент управления PasswordBox сохраняет пароль в SecureString через свойство SecurePassword.

Что теперь? Как мне хешировать SecureString БЕЗ преобразования его сначала в строку?

Все, что я получил до сих пор, - это написать методы расширения, конвертирующие SecureString в String, хешировать их и затем отправлять в базу данных для проверки. Но это противоречит всему упражнению!

Должен ли я просто согласиться с тем, что SecureString бесполезен в моем упомянутом контексте, и использовать простой string?


person Niels Filter    schedule 03.06.2015    source источник
comment
Лично я нахожу очень мало пользы от SecureString - они очень мало добавляют безопасности приложению, несмотря на все усилия, которые они прилагают для правильного использования. В конце концов, действительно преданный злоумышленник получит ваш пароль, потому что он должен храниться в памяти где-то ... идея, что SecureStrings усложнит задачу, верна, но если злоумышленник уже глядя на память, я предполагаю, что они достаточно преданы делу, чтобы в любом случае пройти через это.   -  person Alastair Campbell    schedule 03.06.2015
comment
Пусть база данных занимается паролем. Отправьте имя пользователя и пароль в хранимую процедуру, которая вернет, была ли аутентификация успешной. Вы можете разобраться со всем, что связано с шифрованием в этой процедуре.   -  person Mike Eason    schedule 03.06.2015
comment
@MikeEason Отправить пароль в виде открытого текста в хранимую процедуру? Никогда!   -  person Sami Kuhmonen    schedule 03.06.2015
comment
Я хочу сделать предупреждение / дополнение к этому, поскольку это зависит от некоторых деталей. например, вам нужно безопасное соединение. в противном случае каждый мог прочитать пароль из сетевого потока. Если он использует защищенные строки, это означает, что он хочет защитить свои пароли;) @Niels, посмотри на мой ответ   -  person Boas Enkler    schedule 03.06.2015
comment
@SamiKuhmonen Ну, я не эксперт в этом вопросе, было бы разумно зашифровать пароль перед его отправкой, однако тогда потребуется, чтобы сервер и приложение использовали один и тот же ключ шифрования (?). Я хотел бы увидеть грандиозное решение этой проблемы, если оно есть!   -  person Mike Eason    schedule 03.06.2015
comment
Пароли @MikeEason не должны быть зашифрованными, так как это предполагает, что их можно расшифровать. Скорее они должны быть хешированы с односторонней функцией. Затем это сохраняется в базе данных, и отправленное пользователем значение также хешируется, и они сравниваются.   -  person Sami Kuhmonen    schedule 03.06.2015
comment
Сами прав, шифрование в этом сценарии всегда рискованно. Возможно, немного лучше с асимметричными стратегиями (например, RSA), но это похоже на совершенно другой подход :)   -  person Boas Enkler    schedule 03.06.2015
comment
@MikeEason Нет ключа шифрования, только общий алгоритм хеширования. Более или менее, клиент принимает любой ввод, введенный пользователем, возможно, с солью, выполняет какой-то алгоритм на нем (честно говоря, не имеет значения, какой тип алгоритма - он просто должен быть повторяемым, необратимым и желательно с низкой вероятностью коллизий), затем проверяет, имеет ли база данных тот же хэш, который, очевидно, сохраняется в базе данных при создании учетной записи пользователя.   -  person Alastair Campbell    schedule 05.06.2015


Ответы (1)


SecureString представлен в виде байта [], вы можете закодировать байты, например. с битконвертером и сохраните результат. Кроме того, SecureString - это шифрование, а не хеш, поскольку его можно расшифровать. (увидеть ниже)

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

Специально для паролей предпочтительнее использовать хэш-алгоритмы (например, SHA256). Они не могут быть зашифрованы (например, сумма цифр). В случае использования функциональности входа в систему вы должны зашифровать ввод пользователя и сравнить хеши пользователя и тот, который находится в базе данных. (подробности см. ниже) Я также предлагаю добавить динамические критерии, такие как идентификатор пользователя, в hashinput, чтобы 2 пользователя с одинаковым паролем имели разные хеши.

С этой стратегией у вас нет риска с паролями пользователя, и поэтому, если данные будут утечкой, это не будет проблемой на данном этапе.

Вот краткий обзор использования хэш-алгоритмов.

Итак (если задана защищенная строка) сначала расшифруйте SecureString

String SecureStringToString(SecureString value){
  IntPtr valuePtr = IntPtr.Zero;
  try{
    valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
    return Marshal.PtrToStringUni(valuePtr);
  }
  finally{
    Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
  }
}

Чем хешировать, например, с помощью SHA256. Из этого сообщения

  using (SHA256 hash = SHA256Managed.Create()) {
    Encoding enc = Encoding.UTF8;

    //the user id is the salt. 
    //So 2 users with same password have different hashes. 
    //For example if someone knows his own hash he can't see who has same password
    string input = userInput+userId;
    Byte[] result = hash.ComputeHash(enc.GetBytes(input));

    foreach (Byte b in result)
      Sb.Append(b.ToString("x2")); //You could also use other encodingslike BASE64 
  }

Сохраните этот хеш-сумм. В зависимости от вашей кодировки это может выглядеть так:

ac5b208b4d35ec79fa7c14b7a31f9c80392cdab2bc58bc5b79bcfe64b044d899

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

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

PS: это только один вариант. Но главное - никогда нигде не хранить незашифрованные пароли. Лучше никогда их не узнавать и не менять, чтобы их расшифровать.

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

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

person Boas Enkler    schedule 03.06.2015
comment
Также желательно добавить некоторую соль в процесс хеширования (просто добавьте несколько постоянных случайных байтов к байтам пароля). Это затруднит использование радужных таблиц и других атак на хеши. Но это также стоит отдельного поста, и информацию об этом можно найти в Интернете. - person Sami Kuhmonen; 03.06.2015
comment
Правильно ! Как уже упоминалось выше, идентификатор пользователя:) Также это предотвращает некоторые атаки, если пользователь может узнать свой хэш, он может искать других пользователей с таким же хешем. без соли он мог войти со своим паролем. - person Boas Enkler; 03.06.2015
comment
Ах, правда, внутри кода не заметил. Извини :) - person Sami Kuhmonen; 03.06.2015
comment
Я прояснил это с помощью комментария в коде :) - person Boas Enkler; 03.06.2015
comment
@Boas Enkler, Спасибо за развернутый ответ. Меня устраивает процесс хеширования и т. Д., И я согласен с вами. Однако вы упомянули, что я должен расшифровать SecureString, а затем хэшировать, но пример расшифровки и опубликованная вами ссылка возвращает SecureString в строку, побеждая всю цель, которую я пытаюсь достичь. Тогда я мог просто использовать строку. Я неправильно понял? - person Niels Filter; 03.06.2015
comment
Защищенная строка нужна только в том случае, если у вас есть объекты с паролем в оперативной памяти. - person Boas Enkler; 03.06.2015
comment
Если мой пост решил ваш вопрос, пожалуйста, отметьте его как решение - person Boas Enkler; 04.06.2015
comment
@Boas, а у меня в оперативке пароль хранится? Я думаю, у нас недоразумение. Когда я захватываю пароль от пользователя, значение сохраняется в ОЗУ (отсюда и потребность в SecureString). Если вы можете показать мне способ создания хэша из экземпляра SecureString, не возвращаясь сначала к String, я отмечу ваш ответ как решение. - person Niels Filter; 04.06.2015
comment
Как описано выше. Сначала расшифруйте защищенную строку (первый пример SecureStringToString), затем вы можете хешировать пароль и сохранить его в базе данных. - person Boas Enkler; 04.06.2015
comment
Я ценю помощь, пожалуйста, перечитайте мой вопрос. Есть ли способ хешировать SecureString, БЕЗ предварительного преобразования в string!. - person Niels Filter; 04.06.2015
comment
Вам нужно сразу перейти от SecureString к byte[] без промежуточного string шага! - person Gabe; 04.06.2015