Подтвердить что ты не робот

Эффективное шифрование паролей

Я рассмотрел вопрос StackOverflow, "Шифрование паролей/уровень данных AES AES или AES уровня" , и я хотел бы эффективно и эффективно хешировать мои пароли при регистрации (веб-приложение), а затем проверить их правильность при входе в систему. Я использую VB, но удобен с использованием С#.

Я хотел бы использовать класс шифрования Джеффа Этвуда, описанный в ".NET Encryption Simplified" , поскольку это очень легко понять. У него класс хэширования, но я понятия не имею, как "войти" и сравнить хэши после их хэширования. Это демонстрация Джеффа его хеш-методов с использованием его класса Encryption:

Sub DemoHash()
    Dim d As New Encryption.Data( _
        "{ts '2004-10-09 08:10:04'}The world is beautiful and needs caring by its children")

    Dim hash As New Encryption.Hash(Encryption.Hash.Provider.SHA1)
    Dim hash2 As New Encryption.Hash(Encryption.Hash.Provider.SHA256)
    Dim hash3 As New Encryption.Hash(Encryption.Hash.Provider.SHA384)
    Dim hash4 As New Encryption.Hash(Encryption.Hash.Provider.SHA512)
    Dim hash5 As New Encryption.Hash(Encryption.Hash.Provider.MD5)
    Dim hash6 As New Encryption.Hash(Encryption.Hash.Provider.CRC32)

    hash.Calculate(d)
    hash2.Calculate(d)
    hash3.Calculate(d)
    hash4.Calculate(d)
    hash5.Calculate(d)

    Console.WriteLine("SHA1:   " & hash.Value.Hex)
    Console.WriteLine("SHA256: " & hash2.Value.Hex)
    Console.WriteLine("SHA384: " & hash3.Value.Hex)
    Console.WriteLine("SHA512: " & hash4.Value.Hex)
    Console.WriteLine("MD5:    " & hash5.Value.Hex)
    Console.WriteLine("CRC32:  " & hash6.Calculate(d).Hex)
    Console.WriteLine()

    Dim salt As New Encryption.Data("salty!")
    Console.WriteLine("Salted CRC32:  " & hash6.Calculate(d, salt).Hex)

    Console.WriteLine("Press ENTER to continue...")
    Console.ReadLine()
End Sub

Итак, мои вопросы:

  • Я могу зашифровать пароль (хотя я не собираюсь его хранить) и хешировать строку. Если бы у меня был пользователь, называемый "barry" с паролем "fishlegs", как лучше всего сохранить его пароль и получить его?

  • В SQL Server; является бинарным или nvarchar лучшим вариантом для хранения хэша?

  • Основываясь на "барри" и его пароле, что эффективно хранит хэш? Является ли это шифрование "рыбьего жира", приложенное к соли?

Криптография сложная!

Спасибо всем, кто может помочь...

4b9b3361

Ответ 1

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

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

Возьмем MD5 как пример функции хэширования. Если я запустил MD5 в строке "пароль", я всегда получаю результат "5f4dcc3b5aa765d61d8327deb882cf99" . Однако, если бы вы просто дали кому-то эту строку результата ( "5f4d..." ), им не удастся применить некоторый математический процесс для "реверсирования" функции и выяснить, что она исходит из "пароля".

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

Теперь, даже если невозможно "перевернуть" хеш-функцию, тот факт, что один и тот же ввод всегда дает один и тот же результат, означает, что кто-то может просто создать большую базу данных пар ввода/вывода и использовать это для эффективного обратного преобразования хэши. Это называется "радужным столом". Многие из них доступны в Интернете, поэтому небезопасно использовать простое хеширование, на случай, если ваша база данных когда-либо скомпрометирована. То есть, хотя математически невозможно взять "5f4dcc3b5aa765d61d8327deb882cf99" и выяснить, что он пришел из запуска MD5 на "password", это очень легко определить на практике. Все, что вам нужно сделать, - запустить каждое слово в словаре через MD5 и сохранить результаты, и вы можете легко сменить простые пароли.

Здесь происходит "засоление". Если вы создаете случайную "соль" для каждого пользователя и прикрепляете ее к своему паролю, он эффективно разрушает таблицы радуги. Например, скажем, что тот же пользователь выше регистрирует свой пароль как "пароль". Мы генерируем случайную 8-значную соль для прикрепления к их паролю перед его хэшированием. Скажем, что это "A4BR82QX". Теперь вместо хэширования "password" мы имеем хеш "A4BR82QXpassword". Это дает результат "87a4ba071c8bcb5efe457e6c4e6c4490", поэтому мы сохраняем это в базе данных вместе с солевой струной. Затем, когда этот пользователь пытается войти в систему, вместо прямого хэширования и сравнения пароля, который они ввели в форме входа, мы берем то, что они ввели, добавьте "A4BR82QX" перед ним снова и хэш. Как и раньше, если он совпадает с сохраненным хешем, мы знаем, что они ввели правильный пароль.

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

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

Итак, следующий шаг - найти медленныйхэш-функции, и используйте это вместо быстрого, например MD5. Наличие вашего сайта займет дополнительные пару секунд, чтобы проверить, что вход в систему не имеет большого значения. Но когда кто-то пытается создать таблицы радуги, чтобы взломать пароль, каждая запись занимает несколько секунд, это абсолютный убийца. Я написал достаточно здесь, поэтому я просто закончу, связавшись с этой статьей, в которой подробно описывается выбор хорошей медленной функции хеширования: Достаточно с таблицами Rainbow: что вам нужно знать о безопасных схемах паролей.

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

Ответ 2

Хорошо, так что пара вещей о классе Джеффа в первую очередь. SHA1 и MD5 теперь устарели. CRC32 не подходит для паролей. Во-вторых, вы должны солить каждый хеш, предпочтительно с другим значением соли. Обычно для этого вы выбираете криптографически случайный блок данных, но при нажатии вы можете использовать имя пользователя. Солить префикс или суффикс значения соли где-то в этом процессе. Я склонен хешировать пароль, хешировать соль, комбинировать два, затем снова хэш. Но вы можете поменять местами вокруг, это не имеет большого значения, если вы согласны.

Поэтому, вместо того, чтобы путать вещи с классом Джеффа, сделайте это классическим способом.

Во-первых, случайная генерация соли.

public static byte[] GetRandomSalt()
{
  int minSaltSize = 16;
  int maxSaltSize = 32;

  Random random = new Random();
  int saltSize = random.Next(minSaltSize, maxSaltSize);
  saltBytes = new byte[saltSize];
  RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
  rng.GetNonZeroBytes(saltBytes); 
  return saltBytes;
}

Затем хеширование

public static byte[] ComputeHash(string plainText)
{
  byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
  HashAlgorithm hash = new SHA256Managed();
  return hash.ComputeHash(plainTextWithSaltBytes);
}

Итак, это вычислит хэш SHA256 и вернет его как массив байтов.

Если вы посолились, вы сделали бы что-то вроде следующего

byte[] passwordHash = ComputeHash(password);
byte[] salt = GetRandomSalt();
byte[] saltHash = ComputeHash(salt);

byte[] hashWithSaltBytes = new byte[hashBytes.Length + saltBytes.Length];
for (int i=0; i < hashBytes.Length; i++)
  hashWithSaltBytes[i] = hashBytes[i];
for (int i=0; i < saltBytes.Length; i++)
  hashWithSaltBytes[hashBytes.Length + i] = saltBytes[i];

И тогда, если вам скучно хеш это снова, или оставить как есть.

Чтобы превратить массив байтов в строку, если вы не хотите хранить байты, вы можете использовать

string hashValue = Convert.ToBase64String(hashWithSaltBytes);

Сравнение строк проще, чем сравнение байтов, где вам нужно выполнять итерацию по каждому массиву, вплоть до вас. Просто помните, если вы используете случайные соли, вам нужно их хранить рядом с паролем.

Ответ 3

  • Возьмите пароль пользователя Секрет! ".
  • Создайте случайную соль из нескольких байтов " s4L75a1T".
  • Соедините их с " s4L75a1TSecret!".
  • Вычислить хэш b9797a5b683804eb195b6ba2a5e368ae74394cd3 "(это SHA-1 в гексагоне)
  • Сохраняйте хэш и соль (как шестую строку, строку Base64, так и все, что вам нравится) в базе данных вместе с именем пользователя и другой информацией пользователя (в примере соль является простой строкой и хешем кодируется Base64).
    FirstName    LastName    Salt        Hash
    -----------------------------------------------------------------
    John         Doe         s4L75a1T    uXl6W2g4BOsZW2uipeNornQ5TNM=

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

Ответ 4

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

Ответ Чада выше - превосходное поэтапное объяснение вовлеченных понятий.

Этот вопрос был доведен до смерти во всем Интернете; не только для; серьезно - простой веб-поиск должен найти вам довольно полное руководство.

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

Ответ 5

Я считаю, что процесс выглядит так: Создайте случайную соль, поэтому "fishlegs" + "r4nd0mS4lt", чтобы получить "fishlegsr4nd0mS4lt". Тогда вы хеш, скажем, с MD5 (хотя вы можете использовать SHA256, чтобы быть более безопасным), чтобы получить: 593d5518d759b4860188158ef4c71f28. Храните это и случайно сгенерированную соль. Когда пользователь входит в систему, добавьте случайную соль, а затем проверьте, совпадает ли его введенный пароль с солью с хешем в базе данных.

Ответ 6

То, что вы, по сути, хотите сделать, это:

A) При создании учетной записи вы получаете имя пользователя и пароль от пользователя, вы используете их вместе со своей солью и сохраняете результирующую строку в своей базе данных, например:

Dim sUserName = "barry"
Dim sPassWord = "fishlegs"
Dim mySalt = "A deliciously salty string! fillED WIth all KindS of Junkk(&^&*(£"
Dim d As New Encryption.Data(mySalt + sUserName + sPassWord)
Dim hash As New Encryption.Hash(Encryption.Hash.Provider.SHA256)
hash.Calculate(d)
Dim sTheSaltedHashedUnPassCombination = hash.Value.Hex;
SavenewPasswordHashToDatabase(sTheSaltedHashedUnPassCombination)

Вы никогда не храните sPassWord.

B) Когда пользователь входит в систему, вы выполняете точно такую ​​же операцию с предоставленным именем пользователя и паролем, а затем сравниваете полученный хэш с ранее сохраненным значением в базе данных, чтобы использовать:

Dim sThePreviouslyCreatedHashFromTheDatabase = GetHashForUserFromDatabase(usernameProvided)
Dim mySalt = "A deliciously salty string! fillED WIth all KindS of Junkk(&^&*(£"
Dim d As New Encryption.Data(mySalt + usernameProvided+ passwordProvided)
Dim hash As New Encryption.Hash(Encryption.Hash.Provider.SHA256)
hash.Calculate(d)
Dim sTheSaltedHashedUnPassCombination = hash.Value.Hex;
if (sThePreviouslyCreatedHashFromTheDatabase.Equals(sTheSaltedHashedUnPassCombination))
    'UN & Password Valid!
else
    'UN & PW Invalid!
end

(Простите любые ошибки, VB на мой язык)

Чтобы ответить на ваши вопросы:

1) См. выше. Никогда не храните пароль напрямую, сохраняйте хешированное значение

2) используйте char (X), количество символов, возвращаемых из хэша, является постоянным, поэтому вы можете дать ему известный размер хранилища.

3) То, что вы эффективно сохраняете, - это пароль для пользователя, соленый с их именем пользователя, а также соленый с константой на вашем сервере. Это будет строка фиксированной длины, и вы не сможете изменить эту строку обратно в отдельное имя пользователя и пароль.

Ответ 7

  • Весь смысл хэширования заключается в том, что вы храните хеши, а не пароли открытого текста, и их невозможно восстановить (по крайней мере, с большим трудом). Хеш-функции предназначены для односторонних действий, поэтому поиск невозможно - это их самая суть.
  • nchar[n], вероятно, лучший вариант, поскольку общие алгоритмы хеширования дают результаты постоянной длины (SHA1 выводит 160-битный хэш). Общей практикой является преобразование хэша в Base64, чтобы его можно было сохранить как текст ASCII.
  • Соль - это просто метод, который добавляет случайные биты к хешу, чтобы усложнить процесс взлома. Каждый дополнительный бит соли означает, что взломщик грубой силы должен занимать в два раза больше (и использовать вдвое больше памяти).

Ответ 8

ASP.NET включает в себя основанный на SQL поставщик членства, который позволяет вам создавать, хранить и проверять encryped или hashed пароли, без необходимости делать что-либо - как говорит Эрик Липперт:

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