Трой Хант: У нашего хэширования паролей нет одежды

  1. Быстрый результат хеширования
  2. Краткое описание практики паролей
  3. Поставщик членства ASP.NET
  4. Трещины на скорости графических процессоров
  5. Создание тестовой среды
  6. Взлом пароля на основе словаря
  7. растрескивание
  8. Как мы это исправим?
  9. «Исправление» ASP.NET хеширования паролей
  10. Влияние медленных хэшей на скорость (и нагрузку на процессор)
  11. Забудьте общее руководство по надежности пароля
  12. Напоследок несколько практических советов
  13. Ресурсы

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

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

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

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

Быстрый результат хеширования

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

Нам напомнили об этом на днях, когда WHMCS был нарушен и просочились тысячи деталей аккаунта , В этом случае оказывается, что для обхода безопасности хоста была использована некоторая базовая социальная инженерия, что позволило получить доступ к базе данных учетных записей пользователей. Это была похожая история с LinkedIn чуть позже, когда 6 миллионов паролей были выставлены через (пока) неизвестные или нераскрытые средства. Раскрытие паролей в хранилище происходит. Много.

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

Хитрость заключается в том, чтобы гарантировать, что попытка «сломать» хэширование превысит значение, которое получат преступники. Ничто из этого не о том, чтобы быть «непослушным»; Речь идет о том, чтобы сделать трудность, не стоящую усилий . В этом случае, когда я говорю «сломать» или «взломать», я говорю о пересчете хэшей, а не об обнаружении слабых мест в самих алгоритмах. Я буквально говорю о взятии простой текстовой строки, ее хешировании и сравнении с паролем, который уже находится в хранилище. Если они совпадают, то я только что обнаружил пароль в виде простого текста.

Краткое описание практики паролей

Перво-наперво - мы сосем при выборе паролей. Долгое время. Когда я проанализировал одно из нарушений Sony В прошлом году я нашел несколько довольно дрянных практик:

  1. 93% были длиной от 6 до 10 символов
  2. 45% состояли исключительно из строчных букв
  3. 36% были найдены в словаре общих паролей
  4. 67% были повторно использованы одним и тем же лицом в совершенно не связанных между собой услугах (Gawker)
  5. Только 1% из них содержали не алфавитно-цифровой символ

Это означает, что в шкале потенциальных паролей, то есть с использованием всех доступных символов и их длинных и уникальных паролей, пароли соответствуют очень и очень предсказуемым шаблонам. На самом деле вам нужно только взять сильно ограниченный диапазон (например, строчные буквы от 6 до 8 символов), и вы собираетесь охватить значительное количество паролей. Или, в качестве альтернативы, вы берете список общих паролей в «словаре» паролей, и вы получите аналогичный результат. Подробнее об этом в ближайшее время.

Поставщик членства ASP.NET

Я был сторонником поставщика членства ASP.NET по ряду причин:

  1. Крайне легко создать средства регистрации, входа в систему и управления учетными записями.
  2. В шаблонах Visual Studio для веб-сайтов ASP.NET эта функциональность уже встроена.
  3. Базовая база данных и доступ к данным генерируются автоматически, сохраняя много ручного «стандартного» кодирования.
  4. По умолчанию механизм хранения паролей использует защищенный хеш-код SHA1.

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

Во-первых, давайте посмотрим на соль. Это 16-байтовая криптографически случайная строка, сгенерированная RNGCryptoServiceProvider, затем закодированная Base64:

приватная строка GenerateSalt () {byte [] data = new byte [0x10]; новый RNGCryptoServiceProvider (). GetBytes (данные); return Convert .ToBase64String (data); }

Затем соль передается методу EncodePassword вместе с паролем и форматом, в котором мы хотели бы сохранить пароль (на данный момент мы только предполагаем SHA1). Этот метод немного длинен, но я собираюсь включить все это, потому что я знаю, что некоторые люди хотели бы выделить его:

приватная строка EncodePassword (передача строки, int passwordFormat, соль строки) {if (passwordFormat == 0) {return pass; } byte [] bytes = Encoding .Unicode.GetBytes (pass); byte [] src = Convert .FromBase64String (salt); byte [] inArray = null; if (passwordFormat == 1) {HashAlgorithm hashAlgorithm = this. GetHashAlgorithm (); if (hashAlgorithm - это KeyedHashAlgorithm) {KeyedHashAlgorithm алгоритм2 = (KeyedHashAlgorithm) hashAlgorithm; if (gorith2.Key.Length == src.Length) {gorith2.Key = src; } else if (gorith2.Key.Length <src.Length) {byte [] dst = новый байт [алгоритма2.Key.Length]; Buffer .BlockCopy (src, 0, dst, 0, dst.Length); алгоритма2.Key = dst; } else {int num2; byte [] buffer5 = новый byte [gorith2.Key.Length]; for (int i = 0; i <buffer5.Length; i + = num2) {num2 = Math .Min (src.Length, buffer5.Length - i); Buffer .BlockCopy (src, 0, buffer5, i, num2); }gorith2.Key = buffer5; } inArray =gorith2.2.ComputeHash (bytes); } else {byte [] buffer6 = новый байт [src.Length + bytes.Length]; Buffer .BlockCopy (src, 0, buffer6, 0, src.Length); Buffer .BlockCopy (байты, 0, буфер6, src.Length, байты.Length); inArray = hashAlgorithm.ComputeHash (buffer6); }} else {byte [] buffer7 = новый байт [src.Length + bytes.Length]; Buffer .BlockCopy (src, 0, buffer7, 0, src.Length); Buffer .BlockCopy (байты, 0, buffer7, src.Length, bytes.Length); inArray = это. EncryptPassword (buffer7,
этот . _LegacyPasswordCompatibilityMode); } return Convert .ToBase64String (inArray); }

Обратите внимание, что перед хэшированием пароля соль кодируется Base64 (строка 8 выше), поэтому, когда вы видите соль в базе данных, вы должны помнить, что это не строка, которая использовалась в реальном процессе посола. Например, когда мы видим соль "AB1ZYgDjTR4alp4jYq4XoA ==", это кодированное значение исходных байтов. Сам хешированный пароль также кодируется Base64 перед сохранением на уровне данных.

Трещины на скорости графических процессоров

Это AMD Radeon HD 7970 :

Это высококачественная потребительская видеокарта, которая продается в Австралии по цене около 500 долларов. Я купил один на днях частично для того, чтобы управлять большим количеством экранов, чем разрешал мой старый, и частично для того, чтобы лучше понять, что происходит с хэшированием. Это где hashcat приходит. Видите ли, используя hashcat для использования мощности графического процессора в 7970, вы можете генерировать до 4.7393 миллиардов хешей в секунду . Это верно, миллиард как в «кровавом посту».

Различные алгоритмы хеширования выполняются с разной скоростью, и это ключевая концепция этой статьи. Оценка 4.7B относится к MD5, который считается устаревшим. Варианты SHA, как правило, предпочтительны (как в случае с поставщиком членства), и скорость для SHA1 падает до «простых» хэшей в 2.2B в секунду.

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

Создание тестовой среды

Давайте вернемся к тому анализу паролей Sony, о котором я упоминал ранее. В этом нарушении было почти 40 000 паролей в виде простого текста (в зависимости от того, как вы его обманули), и я собираюсь использовать их для восстановления «защищенных» учетных записей с помощью поставщика членства ASP.NET. Я делаю это потому, что хочу использовать реалистичные пароли в этой демонстрации, чтобы мы получили реальное представление о том, как все это работает.

Я подключился к Visual Studio 2010 и создал совершенно новое приложение MVC 3, работающее в .NET 4, а затем создал сценарий для создания учетной записи на основе паролей Sony. Как это работает? Просто перечисляя логику создания аккаунта:

foreach (переменная пароль в паролях) {MembershipCreateStatus createStatus; Членство .CreateUser ("user" + i, // Имя пользователя password.Password, // Пароль "[email protected]", // Email null, // Вопрос о пароле null, // Пароль верный, // Утверждено null, // ключ провайдера createStatus); // Статус i ++; }

Как только это запустится, вот что мы получаем в базе данных:

Как только это запустится, вот что мы получаем в базе данных:

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

Мы предполагаем, что эта база данных была взломана. Конечно, мы придерживались всех хороших рекомендаций по разработке приложений в таких источниках, как OWASP Top 10 но в конечном счете зло победило добро, и хешены там в дикой природе.

Чтобы начать взламывать эти хэши, нам нужно поместить их в формат, понятный хэш-кату. Способ, которым hashcat имеет дело с хешами, заключается в том, что он определяет определенный тип хешей и требует список хешей соответствующей структуры. В этом случае мы будем использовать шаблон EPiServer ,

Что такое EPiServer? EPiServer является продуктом «управления контентом, сообществом и социальными сетями, коммерцией и коммуникацией», но для нас важно то, что он находится поверх поставщика членства ASP.NET (что, вероятно, было бы более подходящим названием для использования hashcat).

Формат, который нам нужно использовать, включает четыре «столбца», разделенных звездочкой:

  1. Хеш-подпись - «$ episerver $»
  2. Версия - это все «0», что подразумевает SHA1
  3. Закодированная в base64 соль
  4. Base64 кодированный хеш

Это легко вывести из SQL Server, так что в итоге мы получим текстовый файл с именем «MembershipAccounts.hash», который выглядит следующим образом:

$ EPiServer $ * 0 * Z5 + ghPUN6L8bVjdZFLlknQ == * dGOIcZDFNETO8cyY4i0BGcOD + мг = $ EPiServer $ * 0 * detWsWTuzxI21nzefT6tNQ == * FbVX28Yaw5tPGj2sZUS38Cm5obk = $ EPiServer $ * 0 * yZmUqUTKjod0TjBgS6y74w == * dWsNk9FEB8uAcPGhuzgKw + EdYF0 = $ EPiServer $ * 0 * = heFEX9ej5vTa9G7X5QB8Fw = * TR2abu7N2xxqXxleggRXIBuqhr8 = $ EPiServer $ * 0 * xffmFD4ynyLnMkdzvbvuLw == * + 1aODh + RowjblZupczhVuZzkmvk = $ EPiServer $ * 0 * е ++ 8ztWilfow0nli7Tk2PA == * acTusUU8a11uSaKbr / EKo7NNFNk = $ EPiServer $ * 0 * qjAbSa51wjAxxBIVYu98Rg == * YIFas6OtzjQ3aKoOelIBjA9BvNM = .. ,

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

Взлом пароля на основе словаря

Когда мы говорим о «взломе» хэшей, мы на самом деле просто говорим о массовом их восстановлении, и мы можем сделать это несколькими способами. Простой, но трудоемкий способ - просто работать с набором символов и диапазоном, например строчными буквами от 6 до 9 символов. На самом деле это покрыло бы 82% паролей Sony, но привело бы к 104 459 430 739 968 возможностям (это было бы 104 трлн ), поэтому даже при скоростях графического процессора вы смотрите на часы на пароль, так как каждый из них должен подвергаться уникальной атаке из-за соли. Это означало бы сделать это:

SHA1 (соль + «аааааа»)
SHA1 (соль + «аааааб»)


SHA1 (соль + «ааааак»)


...

Вплоть до 9 символов и весь алфавит. Но это не то, как люди создают пароли - это слишком случайно. Конечно случайным образом люди должны создавать пароли - но они этого не делают. Реальность такова, что большинство людей соответствуют гораздо более предсказуемым шаблонам паролей; на самом деле они настолько предсказуемы, что у нас есть пароли «словари».

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

«Достаточно» - очень важная концепция, когда мы говорим о взломе паролей; Речь идет не обязательно о том, чтобы полностью разбить каждый из них и разрешить простой текст, а о том, чтобы добиться достаточного успеха, чтобы оправдать цель . Конечно, цель будет отличаться между злодеями, но вопрос для нас как разработчиков и владельцев приложений заключается в том, «сколько достаточно?». Я имею в виду, сколько достаточно, чтобы оставить нас в очень затруднительном положении (даже в большей степени, чем факт наших данных). был нарушен в первую очередь)? Четверть из них? Половина из них? Может быть, только один из них?

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

Словарь, который я выбрал для этого упражнения, является одним из InsidePro соответственно называется hashkiller (на самом деле, они называют это hashkiller.com, но на этом URL ничего нет). Это файл размером 241 МБ, содержащий 23 685 601 «слово» в виде простого текста, по одному на строку. Почему кавычки вокруг слов? Потому что он содержит такие вещи, как «!!! $ @@@ »(пробелы там как найдены),« !!!!!! 888888 »и« !!!!!!! # @ ##### ». Он также содержит 5144 вариаций слова «сиська» (да - я проверял), так что, как вы можете видеть, он не лишен разнообразия.

растрескивание

Процесс взлома очень прост; у вас есть два ввода, которые представляют собой список солей с хэшами, а затем есть словарь паролей. Они передаются в команду hashcat с параметром, указывающим тип хэшей, с которым мы имеем дело, - это формат EPiServer («-m 141»). Вот как выглядит команда:

oclHashcat-plus64.exe -m 141 MembershipAccounts.hash hashkiller.com.dic

Я хочу попытаться дать представление о том, насколько быстро выполняется этот процесс, поэтому я скомпилировал начало и конец в короткометражном видео (оно будет обобщено далее, если вы хотите пропустить):

Впечатляет? Довольно, но тоже немного страшно. Давайте внимательнее посмотрим на резюме после того, как все выполнится:

Давайте внимательнее посмотрим на резюме после того, как все выполнится:

То, что мы когда-то считали «безопасным» - это соленые хэши SHA - только что стерто с лица земли. Фактически, за время, которое требуется для просмотра пары эпизодов «Семейного парня», мы взломали 24 710 хэшей или 63% от общего размера выборки. Остальные 37% просто не были в словаре паролей, а были более крупным словарем и, возможно, сидели в трилогии «Властелин колец», и показатель успеха был бы намного выше. Дело в том, что это тривиальное количество времени, которое нужно потратить на взлом значительной части хэшей.

Более того, там есть пароли, которые многие считают «надежными». Как насчет «волейбола6» - 11 символов двух разных типов. Далее в списке был «zaq1 @ WSX» - 8 символов верхнего, нижнего числа и символа, что, безусловно, достаточно для прохождения большинства политик безопасности, даже если они хранятся в виде «защищенного» соленого хэша, совершенно бесполезного.

Все эти взломанные пароли теперь были сохранены в файл с именем «hashcat.pot». Вот что внутри:

$ EPiServer $ * 0 * v4jLrMuwxHVEwNtBY + euWQ == * seag5UHhUX / 9XGF0dsuWWqM2OPo =: whitecastle $ EPiServer $ * 0 * 5HiaCQ2PHw8UKtoefcAabg == * = Nb6oPKomz8x5Y9X6KlMiUOWgs1M: WebPassword $ EPiServer $ * 0 * ос / gaXQHQysUSN3fZXHRgQ == * KOEWcq1m93n / 1KnZ0gc6FG7zfAU =: wirerainbow $ EPiServer $ * 0 * 7 + gtThgiDqtujPfOmQlIrA == * FBdRyZ5dQe7r / LmSjWRtbxfadW0 =: грушанки $ EPiServer $ * 0 * 4zWWZXGhGYoUuO / H3GHKuw == * = kqBQ1o7O09aiu1E3UcvXFv5kOIw: youngatheart $ EPiServer $ * 0 * Ж + wcPWP3eq9I9borAQk99g == * tgdFnRZgC6 + 1SDMjqPF8QZNioLw = : yadayadayada $ EPiServer $ * 0 * WexfxdXwQEGxn / s3BcK6kw == * M4fi / JsHJfN3igxNUwkVdm4qiuo =: whoisjohngalt $ EPiServer $ * 0 * vhfZBwOEC6mqUQ / xCYvp5Q == * x6exTBH1npMOxaA4oMTlN6Mcrw4 =: whiteboyasian $ EPiServer $ * 0 * n4CwNpXE4nzCRoOodOweBg == * ksMShFJRFpHSjZcQBcdNdSjIVLU =: yaddayaddayadda $ EPiServer $ * 0 * s7VI8VOJFnJ276hEhE6bCQ == * rNENDk8rRazL2LVmPaGNS7o5pIw =: yaddayaddayadda

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

Еще одна вещь, прежде чем мы продолжим; Вы заметили, что скорость взлома была «всего» 258,7 М в секунду? Что случилось с теоретической пропускной способностью пары миллиардов хэшей SHA1 в секунду? Проблема заключается в том, что более высокая пропускная способность может быть достигнута только при «мутациях» значений словаря паролей или при работе с различными возможностями паролей непосредственно в графическом процессоре. Другими словами, если вы позволите графическому процессору принимать значение словаря, то преобразуйте его во множество различных возможностей, и это может работать намного быстрее. GPU не может достаточно быстро вводить пароли узкое место - добиться такого же уровня пропускной способности, чтобы эффективно иметь список паролей.

Вы можете наблюдать, как GPU работает только на половине его потенциала; вот что Аппаратный монитор MSI Afterburner Я должен был сказать о 7970, работающем непосредственно через словарь слева, против применения мутаций к словарю справа:

Вы можете наблюдать, как GPU работает только на половине его потенциала;  вот что   Аппаратный монитор MSI Afterburner   Я должен был сказать о 7970, работающем непосредственно через словарь слева, против применения мутаций к словарю справа:

Видите использование графического процессора% на вторых графиках? Когда 7970 начинает приближаться к этому максимальному использованию, и вентилятор набирает обороты, все начинает звучать немного реактивно-на-макс-тяге. Но в конечном счете, хотя скорость прямого хэширования словаря может быть ниже, точность значительно выше, и время для получения значимых результатов является более благоприятным.

Как мы это исправим?

Так что это плохая новость - ваши соленые хэши SHA практически бесполезны против большинства паролей, которые обычно создают пользователи . Поставщик членства в ASP.NET теперь обеспечивает не более чем тонкий вид защиты паролем в хранилище. И не думайте, что вы можете это исправить, зайдя в SHA256, реализованный в System.Web.Providers Это едва ли лучше, чем SHA1 с точки зрения скорости, с которой вы создаете хэши. Нам нужна лучшая мышеловка.

Вот проблема:

Вот проблема:

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

Но давайте рассмотрим здесь немного контекста. Нужно ли нам иметь возможность генерировать 4,7 миллиарда хэшей паролей в секунду? Это похоже на то, как если бы все население Facebook превысило 900 миллионов и последовательно хэшировали каждый пароль 5 раз каждую секунду . И это на потребительском оборудовании. Нет, нам не нужно приближаться к этому.

Проблема в том, что такие алгоритмы, как MD5 и SHA, были разработаны для демонстрации целостности данных при высокой скорости вычислений, а не для обеспечения механизма хранения паролей; криптографические хеш-функции не являются хеш-функциями пароля , Даже если бы они были «безопасными» для хранения паролей при разработке, MD5 работает уже 20 лет, поэтому по закону Мура у нас теперь есть процессоры, которые теперь работают в восемь тысяч раз быстрее .

Существуют различные подходы к возвращению жизни к старым алгоритмам; растяжение ключа Например, если слишком быстрый алгоритм «замедляется», повторяя его снова и снова, возможно, тысячи раз. Но руководство вокруг таких как MD5 и SHA ясно и OWASP резюмирует это довольно кратко :

Общие алгоритмы хеширования (например, MD5, SHA-1/256/512) не рекомендуются для хранения паролей. Вместо этого следует использовать алгоритм, специально разработанный для этой цели.

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

Изменить: я был немного расплывчатым здесь, и несколько человек позвонили мне по этому поводу. Концепция увеличения усилия, необходимого для выполнения хэш-функции, часто реализуется путем растягивания ключа, и это действительно modus operandi PBKDF2. Фактически, PBKDF2 затем может быть применен к алгоритму, такому как SHA, так что строго говоря, SHA все еще используется, только не так, как мы знаем его в форме единой итерации. Тогда возникает вопрос о том, сколько итераций достаточно, о чем я расскажу чуть ниже.

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

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

Очевидно, что способность увеличивать рабочую нагрузку важна, если мы не хотим, чтобы в ближайшем будущем мы снова были пойманы законом Мура. Все, что нам нужно, это способ интегрировать это в нашу существующую работу.

«Исправление» ASP.NET хеширования паролей

К счастью, существует ряд решений для реализации более сильных алгоритмов хеширования в ASP.NET. Для начала есть Реализация Zetetic bcrypt и PBKDF2 для провайдера членства , Отличительной особенностью этого подхода является то, что вы можете поместить его прямо в существующее приложение. от NuGet :

Зетик использует bcrypt.net так что вы всегда можете просто пойти и взять его напрямую, если вы не хотите реализовывать весь членский провайдер. К сожалению, у Zetetic есть один существенный недостаток - требует установки GAC и модификации machine.config , Это прискорбно, так как исключает многие размещенные среды, которые я использую для ASafaWeb с AppHarbor , Я могу развернуть в приложении практически все, что мне нравится , но я никак не могу приблизиться к GAC или machine.config в общей среде.

Тогда есть реализации, такие как CryptSharp от Крис Макки что делает его чрезвычайно простым для реализации bcrypt и PBKDF2 наряду с другими, такими как SCrypt и Blowfish. Нет прямой интеграции с провайдером членства, но также нет зависимости от GAC или machine.config.

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

Влияние медленных хэшей на скорость (и нагрузку на процессор)

Замедление хеширования может быть просто замечательно для безопасности, но какое еще негативное влияние это может оказать? Ну, во-первых, процесс входа будет медленнее. Но давайте будем прагматичны в этом - если упражнение, которое должно происходить не более одного раза за сеанс на другом конце всей этой сетевой задержки и времени рендеринга браузера, добавляет, скажем, 200 мс к процессу, имеет ли это значение? Большинство будет утверждать «нет» - это незаметное количество времени незначительного увеличения существующего времени ожидания пользователя, и оно добавляется к нечастому процессу.

Но как насчет издержек на самом сервере? Я имею в виду, являются ли более медленные алгоритмы хеширования достаточно вычислительно дорогими, чтобы оказывать неблагоприятное влияние на ресурсы до такой степени, что это будет стоить денег за большее количество ресурсов? Некоторые говорят «да» Это вызывает беспокойство и то, что при достаточном одновременном хешировании это будет иметь серьезные негативные последствия. В этом примере 100 одновременных потоков потребляли 95% ресурсов ЦП в течение 38 секунд, поэтому очевидно, что это проблема.

Я хотел бы иметь эту проблему! Представьте себе масштаб, которого вам нужно достичь, чтобы иметь 100 отдельных лиц, которые одновременно пытаются хэшировать пароль с помощью входа в систему, регистрации или смены пароля - что за великолепная проблема! Чтобы достичь масштаба, в котором медленное хеширование оказывает такое влияние - или даже только 10% от этих чисел - вы говорите о серьезно большом приложении. Рассмотрим один вход в систему за сеанс, использование функции «запомнить меня» (правильно или неправильно), частоту использования, а затем сопоставьте это с процессом, который, даже если он намеренно медленный, вероятно, находится где-то в диапазоне 100 мс. Но, конечно, при использовании адаптивного алгоритма хеширования, такого как bcrypt, он не должен составлять 100 мс, он может быть вдвое меньше или вдвое больше, или что вы решите, - это правильный баланс скорости и риска для безопасности на оборудовании, которое вы используете сегодня . Давайте проясним, что это определенно нужно учитывать, но многим из нас не о чем беспокоиться.

Частично проблема заключается в том, что когда мы применяем хеширование для хранения паролей, мы делаем это на процессоре, который работает медленно, но затем, когда кто-то пытается его взломать, он делает это на G PU, что быстро. , Создание более высокой рабочей нагрузки может в равной степени применяться к обоим процессорам, но это наносит ущерб тому, который предназначен для законного хеширования, намного сильнее, чем тот, который часто используется для гнусных целей. Это просто нечестно!

Одна школа мысли заключается в использовать хеширование GPU на сервере эффективно выровнять игровое поле. Если процессор действительно В 150 раз медленнее хешировать пароли тогда не имеет ли смысл перенести этот процесс на графический процессор, а затем просто увеличить рабочую нагрузку до приемлемого предела? Это вполне может быть идеальным решением, хотя, конечно, вам нужно иметь доступное оборудование (и вы не найдете быстрых графических процессоров уже на большинстве серверов), а также код, отвечающий за хеширование, предназначенный для графического процессора, который определенно не позиция по умолчанию для большинства серверных реализаций хеширования.

Но это немного заинтриговало меня; Каково на самом деле влияние медленного хеширования в живой среде? И есть ли большая разница в скорости между вариантами SHA и bcrypt, или даже MD5 в этом отношении? Поэтому я создал демо, чтобы помочь дать некоторый контекст и выложить его здесь: https://asafaweb.com/HashSpeed

com/HashSpeed

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

Из этого можно извлечь несколько уроков:

  1. Условно говоря, скорость SHA1 и SHA256 также близка к каждому и даже близка к MD5 - максимум около 15%.
  2. SHA512 может показаться немного медленнее, но все еще слишком быстр для хеширования паролей (hashcat требует 73 миллиона в секунду в графическом процессоре 7970).
  3. Существует огромная разница между вариантами MD5 и SHA по сравнению с bcrypt даже с небольшим количеством раундов (по умолчанию bcrypt.net равен 10, что в 32 раза медленнее, чем с 5 раундами).

Когда вы можете настроить издержки обработки алгоритма хеширования, на самом деле не так много аргументов, чтобы добавить неприемлемые издержки в среду. Слишком медленно? Ускорить это. Это не значит, что вы все равно будете спускаться до скоростей на основе SHA; никогда не должно быть случая хэширования пароля менее миллисекунды, как показано в примере выше.

Забудьте общее руководство по надежности пароля

Одна вещь, которую я всегда находил немного забавной - особенно в свете ранее сделанного взлома, - это руководство типа «Потребуется X дней, недель, месяцев, чтобы взломать конкретный пароль. Позвольте мне продемонстрировать с паролем «00455455mb17», используя Сайт Passfault :

Хорошо, что надо сделать это! Проблема в том, что мы взломали его за 45 минут. На самом деле, точнее, мы взломали эту и 24,709 других, но давайте не будем расстраиваться. Выбор пароля (а точнее, взлом) не подчиняется простым правилам энтропии, нет, уникальность абсолютно необходима для их защиты, и, наоборот, предсказуемость является ключевой частью их взлома.

Напоследок несколько практических советов

Итак, что мы можем сделать из этого упражнения? Позвольте мне подвести итог:

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

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

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

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

<add name = "AspNetSqlMembershipProvider" minRequiredPasswordLength = "30"
minRequiredNonalphanumericCharacters = "5" />

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

Но позвольте мне закончить это следующей цитатой из предисловия Брюса Шнайера. Прикладная криптография :

В этом мире существует два вида криптографии: криптография, которая не дает вашей младшей сестре читать ваши файлы, и криптография, которая не дает крупным правительствам читать ваши файлы.

Похоже, что это действительно так, и, к сожалению, SHA сейчас твердо относится к первой категории.

Ресурсы

  1. Вы уверены, что соли SHA-1 + достаточно для паролей?
  2. Скорость хеширования
  3. Какие-нибудь эксперты по безопасности рекомендуют bcrypt для хранения пароля?
  4. Как безопасно хранить пароль
  5. Безопасное хранение паролей
  6. На пути к более безопасному хешированию паролей в ASP.NET
Безопасность .СЕТЬ Пароли

Как это работает?
Конечно, цель будет отличаться между злодеями, но вопрос для нас как разработчиков и владельцев приложений заключается в том, «сколько достаточно?
Был нарушен в первую очередь)?
Четверть из них?
Половина из них?
Может быть, только один из них?
Почему кавычки вокруг слов?
Еще одна вещь, прежде чем мы продолжим; Вы заметили, что скорость взлома была «всего» 258,7 М в секунду?
Что случилось с теоретической пропускной способностью пары миллиардов хэшей SHA1 в секунду?
Как мы это исправим?