Рекомендации: пароли для посола и перца?
Я натолкнулся на дискуссию, в ходе которой я узнал, что то, что я делал, на самом деле не засолил пароли, а перебил их, и с тех пор я начал выполнять обе функции с такой функцией:
hash_function($salt.hash_function($pepper.$password)) [multiple iterations]
Игнорирование выбранного алгоритма хеширования (я хочу, чтобы это было обсуждение солей и перцев, а не конкретных алгоритмов, но я использую безопасный), это безопасный вариант или я должен делать что-то другое? Для тех, кто не знаком с условиями:
Соль - это случайно сгенерированное значение, которое обычно хранится со строкой в базе данных и предназначено для того, чтобы исключить использование хеш-таблиц для взлома паролей. Поскольку у каждого пароля есть своя собственная соль, все они должны быть взломаны индивидуально, чтобы взломать их; однако, поскольку соль хранится в базе данных с хэшем пароля, компрометация базы данных означает потерю обоих.
Перец - это статическое значение для всего сайта, хранящееся отдельно от базы данных (обычно жестко запрограммированное в исходном коде приложения), которое должно быть секретным. Он используется для того, чтобы компрометация базы данных не привела к переборам всей таблицы паролей приложения.
Есть ли что-то, чего я пропускаю, и является ли засолка и засыпка моих паролей лучшим вариантом для защиты безопасности моего пользователя? Есть ли потенциальный недостаток безопасности в этом?
Примечание. Предположим, что в целях обсуждения приложение и база данных хранятся на разных компьютерах, не разделяют пароли и т. Д., Поэтому нарушение работы сервера базы данных не означает автоматически нарушение работы сервера приложений.
4 ответа
Хорошо. Поскольку мне нужно писать об этом снова и снова, я сделаю один последний канонический ответ только для перца.
Кажущийся перевернутый перец
Кажется совершенно очевидным, что перцы должны сделать хеш-функции более безопасными. Я имею в виду, что если злоумышленник получит только вашу базу данных, то пароли ваших пользователей должны быть в безопасности, верно? Кажется логичным, верно?
Вот почему так много людей считают, что перец - хорошая идея. Это имеет смысл".
Реальность перца
В сферах безопасности и криптографии "иметь смысл" недостаточно. Что-то должно быть доказуемым и иметь смысл, чтобы это считалось безопасным. Кроме того, он должен быть осуществим в поддерживаемом виде. Самая безопасная система, которую невозможно обслуживать, считается небезопасной (потому что, если какая-либо часть этой защиты выходит из строя, вся система разваливается).
И перцы не подходят ни доказуемым, ни обслуживаемым моделям...
Теоретические проблемы с перцем
Теперь, когда мы подготовили почву, давайте посмотрим, что не так с перцем.
Вводить один хэш в другой может быть опасно.
В вашем примере вы делаете
hash_function($salt . hash_function($pepper . $password))
,Из прошлого опыта мы знаем, что "просто" добавление одного хеш-результата в другую хеш-функцию может снизить общую безопасность. Причина в том, что обе хеш-функции могут стать целью атаки.
Вот почему такие алгоритмы, как PBKDF2, используют специальные операции для их объединения (в этом случае hmac).
Дело в том, что, хотя это не имеет большого значения, это также не тривиальная вещь, чтобы просто бросить вокруг. Криптосистемы предназначены для того, чтобы избежать случаев "должен работать", и вместо этого сосредотачиваются на случаях "предназначен для работы".
Хотя это может показаться чисто теоретическим, на самом деле это не так. Например, Bcrypt не может принимать произвольные пароли. Так мимоходом
bcrypt(hash(pw), salt)
может действительно привести к гораздо более слабому хешу, чемbcrypt(pw, salt)
еслиhash()
возвращает двоичную строкуРаботаем против дизайна
Bcrypt (и другие алгоритмы хеширования паролей) предназначены для работы с солью. Понятие перца никогда не было введено. Это может показаться мелочью, но это не так. Причина в том, что соль не секрет. Это просто значение, которое может быть известно злоумышленнику. С другой стороны, перец, по определению, является криптографическим секретом.
Текущие алгоритмы хэширования паролей (bcrypt, pbkdf2 и т. Д.) Предназначены для того, чтобы принимать только одно секретное значение (пароль). Добавление еще одного секрета в алгоритм вообще не изучалось.
Это не значит, что это небезопасно. Это означает, что мы не знаем, безопасно ли это. И общая рекомендация по безопасности и криптографии: если мы не знаем, это не так.
Поэтому, пока алгоритмы не будут разработаны и проверены криптографами для использования с секретными значениями (перцами), современные алгоритмы не должны использоваться с ними.
Сложность - враг безопасности
Хотите верьте, хотите нет, но сложность - враг безопасности. Создание алгоритма, который выглядит сложным, может быть безопасным или нет. Но шансы довольно значительны, что это не безопасно.
Значительные проблемы с перцем
Это не ремонтопригодно
Ваша реализация перца не позволяет поворачивать ключ перца. Поскольку перец используется на входе в одностороннюю функцию, вы никогда не сможете изменить перец в течение срока действия значения. Это означает, что вам нужно придумать несколько хитрых хаков, чтобы он поддерживал ротацию клавиш.
Это чрезвычайно важно, так как это требуется всякий раз, когда вы храните криптографические секреты. Отсутствие механизма поворота ключей (периодически и после нарушения) является огромной уязвимостью безопасности.
И ваш текущий подход перца потребовал бы, чтобы каждый пользователь либо полностью утратил свой пароль при ротации, либо подождал, пока его следующий логин не сменится (что может быть никогда)...
Что делает ваш подход незамедлительным.
Это требует от вас, чтобы свернуть свой собственный крипто
Поскольку ни один из существующих алгоритмов не поддерживает концепцию перца, он требует от вас либо составления алгоритмов, либо изобретения новых для поддержки перца. И если вы не можете сразу понять, почему это действительно плохо:
Любой, от самого невежественного любителя до лучшего криптографа, может создать алгоритм, который он сам не сможет сломать.
НИКОГДА не катите свой собственный крипто...
Лучший путь
Итак, из всех проблем, описанных выше, есть два способа справиться с ситуацией.
Просто используйте алгоритмы, как они существуют
Если вы используете bcrypt или scrypt правильно (с высокой стоимостью), все пароли словаря, кроме самых слабых, должны быть статистически безопасными. Текущая запись для хэширования bcrypt со стоимостью 5 - 71 тыс. Хешей в секунду. При такой скорости взлома даже 6-символьного случайного пароля потребуются годы. И учитывая, что моя минимальная рекомендуемая стоимость равна 10, это уменьшает число хэшей в секунду в 32 раза. Таким образом, мы будем говорить только о 2200 хэшах в секунду. В таком случае, даже некоторые словарные фразы или модификации могут быть безопасными.
Кроме того, мы должны проверять эти слабые классы паролей у входа и не допускать их. По мере того, как взлом паролей становится все более сложным, также должны соблюдаться требования к качеству паролей. Это все еще статистическая игра, но с надлежащей техникой хранения и надежными паролями все должны быть практически в безопасности...
Зашифруйте выходной хэш до хранения
В области безопасности существует алгоритм, разработанный для обработки всего, что мы сказали выше. Это блочный шифр. Это хорошо, потому что это обратимо, поэтому мы можем вращать ключи (ууу! Ремонтопригодность!). Это хорошо, потому что используется по назначению. Это хорошо, потому что это не дает пользователю никакой информации.
Давайте посмотрим на эту строку снова. Допустим, злоумышленник знает ваш алгоритм (который необходим для безопасности, в противном случае это безопасность через неизвестность). При традиционном перцовом подходе злоумышленник может создать сторожевой пароль, и, поскольку он знает соль и результат, он может перебить перец. Хорошо, это длинный выстрел, но это возможно. С шифром злоумышленник ничего не получает. А так как соль рандомизирована, пароль дозорного даже не поможет ему / ей. Таким образом, лучшее, что у них осталось, это атаковать зашифрованную форму. Это означает, что они сначала должны атаковать ваш зашифрованный хеш, чтобы восстановить ключ шифрования, а затем атаковать хэши. Но есть много исследований по атаке шифров, поэтому мы хотим положиться на это.
TL / DR
Не используйте перец. С ними связано множество проблем, и есть два более эффективных способа: не использовать какой-либо секрет на стороне сервера (да, это нормально) и шифровать выходной хэш с использованием блочного шифра перед хранением.
Во-первых, мы должны говорить о точном преимуществе перца:
- Перец может защитить слабые пароли от атаки по словарю, в особом случае, когда злоумышленник имеет доступ для чтения к базе данных (содержащей хэши), но не имеет доступа к исходному коду с перцем.
Типичным сценарием может быть SQL-инъекция, выброшенные резервные копии, удаленные серверы... Эти ситуации не так редки, как кажется, и часто не под вашим контролем (хостинг на сервере). Если вы используете...
- Уникальная соль на пароль
- Алгоритм медленного хеширования, такой как BCrypt
... надежные пароли хорошо защищены. При таких условиях почти невозможно взломать надежный пароль, даже когда соль известна. Проблема заключается в слабых паролях, которые являются частью словаря грубой силы или являются их производными. Атака по словарю покажет их очень быстро, потому что вы тестируете только самые распространенные пароли.
Второй вопрос, как применять перец?
Часто рекомендуемый способ применить перец - это объединить пароль и перец перед передачей его хэш-функции:
$pepperedPassword = hash_hmac('sha512', $password, $pepper);
$passwordHash = bcrypt($pepperedPassword);
Есть и другой, еще лучший способ:
$passwordHash = bcrypt($password);
$encryptedHash = encrypt($passwordHash, $serverSideKey);
Это не только позволяет добавить секрет на стороне сервера, но также позволяет обмениваться $ serverSideKey, если это необходимо. Этот метод включает в себя немного больше работы, но если код когда-то существует (библиотека), нет причин не использовать его.
Я хочу, чтобы это было обсуждение соли и перца, а не конкретных алгоритмов, но я использую безопасный
Каждая известная мне функция безопасного хеширования паролей принимает пароль и соль (и секрет / перец, если они поддерживаются) в качестве отдельных аргументов и выполняет всю работу самостоятельно.
Просто потому, что вы объединяете строки и что ваш hash_function
принимает только один аргумент, я знаю, что вы не используете ни один из хорошо протестированных, хорошо проанализированных стандартных алгоритмов, а вместо этого пытаетесь использовать свой собственный. Не делай этого.
Argon2 победил в конкурсе по хешированию паролей в 2015 году, и, насколько мне известно, это по-прежнему лучший выбор для новых проектов. Он поддерживает перец через параметр K (называемый "секретное значение" или "ключ"). Я не знаю причин не использовать перец. В худшем случае перец будет скомпрометирован вместе с базой данных, и вам будет не хуже, чем если бы вы его не использовали.
Если вы не можете использовать встроенную поддержку перца, вы можете использовать одну из двух предложенных формул из этого обсуждения:
Argon2(salt, HMAC(pepper, password)) or HMAC(pepper, Argon2(salt, password))
Важное примечание: если вы передаете вывод HMAC (или любой другой функции хеширования) в Argon2 (или любую другую функцию хеширования пароля), либо убедитесь, что функция хеширования пароля поддерживает встроенные нулевые байты, либо закодируйте значение хеш-функции (например, в base64), чтобы гарантировать отсутствие нулевых байтов. Если вы используете язык, строки которого поддерживают встроенные нулевые байты, то вы, вероятно, в безопасности, если только этот язык не PHP, но я бы все равно проверил.
Смысл соли и перца заключается в том, чтобы увеличить стоимость предварительно вычисленного поиска пароля, называемого радужным столом.
В общем, попытка найти коллизию для одного хэша трудна (при условии, что хеш безопасен). Тем не менее, с помощью коротких хэшей можно использовать компьютер для генерации всех возможных хешей для поиска на жестком диске. Это называется радужным столом. Если вы создадите радужную таблицу, вы сможете выйти в мир и быстро найти правдоподобные пароли для любого (несоленого).
Смысл перца в том, чтобы сделать радужную таблицу, необходимую для взлома вашего списка паролей, уникальной. Таким образом, тратить больше времени на атакующего, чтобы построить радужный стол.
Смысл, однако, в том, чтобы сделать радужную таблицу для каждого пользователя уникальной для пользователя, что еще больше увеличивает сложность атаки.
Действительно, компьютерная безопасность почти никогда не делает ее (математически) невозможной, просто математически и физически неосуществимой (например, в защищенных системах потребуется вся энтропия во вселенной (и даже больше) для вычисления пароля одного пользователя).
Не вижу хранения в коде исходного кода значения, имеющего отношение к безопасности. Это безопасность через неизвестность.
Если хакер получит вашу базу данных, он сможет начать перебор ваших паролей. Хакеру не понадобится много времени, чтобы определить ваш перец, если ему удастся взломать несколько паролей.