Очистка паролей пользователей

100

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

Когда разработчики PHP рассматривают хеширование паролей пользователей в целях безопасности, они часто склонны думать об этих паролях, как о любых других данных, предоставленных пользователем. Эта тема часто возникает в вопросах PHP, связанных с хранением паролей; разработчик часто хочет очистить пароль, используя такие функции, как escape_string()(в различных итерациях) htmlspecialchars(), addslashes()и другие перед его хешированием и сохранением в базе данных.

Джей Бланшар
источник
1
Вы можете кодировать с помощью base64
MSS
Нет @MSS, вы не должны, потому что base64 кодирует , а не шифрует или хеширует . Пароли всегда следует хешировать .
Джей Бланшар
1
Я имею в виду перед хешем;)
MSS
Вы не должны и не должны делать этого перед хешированием. Это приведет к тому, что вам придется писать ненужный дополнительный код @MSS,
Джей Бланчард,

Ответы:

101

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

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

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

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

PASSWORD_BCRYPT используется для создания новых хэшей паролей с использованием алгоритма CRYPT_BLOWFISH. Это всегда будет приводить к получению хэша в формате криптографии «$ 2y $», который всегда имеет ширину 60 символов.

Требования к пространству для хранения хэша могут меняться по мере добавления к функции различных методов хеширования, поэтому всегда лучше увеличивать тип столбца для сохраненного хеша, например VARCHAR(255)или TEXT.

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

SELECT * FROM `users`;

Может быть хеширован $2y$10$1tOKcWUWBW5gBka04tGMO.BH7gs/qjAHZsC5wyG0zmI2C.KgaqU5G

Посмотрим, как различные методы очистки влияют на пароль -

Пароль I'm a "dessert topping" & a <floor wax>!(В конце пароля есть 5 пробелов, которые здесь не отображаются.)

Когда мы применяем следующие методы обрезки, мы получаем совершенно разные результаты:

var_dump(trim($_POST['upassword']));
var_dump(htmlentities($_POST['upassword']));
var_dump(htmlspecialchars($_POST['upassword']));
var_dump(addslashes($_POST['upassword']));
var_dump(strip_tags($_POST['upassword']));

Полученные результаты:

string(40) "I'm a "dessert topping" & a <floor wax>!" // spaces at the end are missing
string(65) "I'm a &quot;dessert topping&quot; &amp; a &lt;floor wax&gt;!     " // double quotes, ampersand and braces have been changed
string(65) "I'm a &quot;dessert topping&quot; &amp; a &lt;floor wax&gt;!     " // same here
string(48) "I\'m a \"dessert topping\" & a <floor wax>!     " // escape characters have been added
string(34) "I'm a "dessert topping" & a !     " // looks like we have something missing

Что происходит, когда мы отправляем их password_hash()? Все они хешируются, как и запрос выше. Проблема возникает, когда вы пытаетесь проверить пароль. Если мы используем один или несколько из этих методов, мы должны повторно использовать их, прежде чем сравнивать их password_verify(). Следующее не получится:

password_verify($_POST['upassword'], $hashed_password); // where $hashed_password comes from a database query

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


Используете версию PHP ниже 5.5? Вы можете использовать password_hash() пакет совместимости .

Вам действительно не следует использовать хэши паролей MD5 .

Джей Бланшар
источник
13
Нет. Если он создал свой пароль с конечными пробелами, что разрешено, он должен использовать их при входе в систему @DanBracuk
Джей Бланшар,
12
Как так @DanBracuk? Если мы позволим пользователю устанавливать желаемый пароль, включая начальные / конечные пробелы?
Джей Бланшар,
16
Вот почему большинство вещей требует, чтобы вы вводили выбранный пароль дважды. Если пользователь случайно добавил пробелы, он выяснит это, прежде чем продолжить. Если пользователь сделал это специально, то это не проблема.
Однажды я боролся с медведем.
4
@MargaretBloom, эмпирическое правило - это просто эвристика. Иногда нам все же нужно что-то продумать, например, над паролями. Вы говорите: «Никто не знает, как все изменится в будущем», но кажется, что если что-то и изменится, так это то, как мы избегаем данных, прежде чем поместить их в базу данных, и в этом случае пользователи окажутся заблокированными, если их пароли не будут больше соответствует тому, что мы сохранили. В чем опасность отказа от хэшей паролей и опасность от них?
DavidS
3
Точно: вы, конечно, «избежите хэша» в ограниченном смысле правильной передачи его параметризованному SQL-запросу, где некоторый код в вашем соединителе SQL может или не может делать с ним что-либо, что соответствует «экранированию», вы не не знаю и все равно. Для этого вам просто не придется писать какой-то конкретный код, потому что это совершенно рутинно для всех ваших SQL-запросов, если вы ранее не приняли плохих жизненных решений.
Стив Джессоп,
36

Перед хешированием пароля вы должны нормализовать его, как описано в разделе 4 RFC 7613 . В частности:

  1. Дополнительное правило отображения: любые экземпляры пространства, отличного от ASCII, ДОЛЖНЫ отображаться в пространство ASCII (U + 0020); пробелом, отличным от ASCII, является любая кодовая точка Unicode, имеющая общую категорию Unicode "Zs" (за исключением U + 0020).

и:

  1. Правило нормализации: Форма нормализации Unicode C (NFC) ДОЛЖНА применяться ко всем символам.

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

legoscia
источник
3
@DavidS, супер блестящая североамериканская книга для Mac (которую Джо использовал перед отъездом) и плохо интернационализированный компьютер тайваньского интернет-кафе (который Джо пытается использовать для загрузки, это посадочный талон на обратный рейс).
Маргарет Блум,
2
Звучит ура-патриотически. :-) Спасибо хоть.
DavidS
3
Хм. Если вы это сделаете, вам также следует проверить пароли, чтобы отклонять любые, содержащие еще не назначенные символы. Было бы ужасно, если бы пользователь использовал NEWFANGLED SPACE, которое ваше приложение не распознает и, следовательно, хеширует как есть, а затем вы обновляете свою базу данных символов Unicode, и внезапно NEWFANGLED SPACE будет сопоставлен с SPACE перед хешированием, так что (s) он больше не может вводить пароль, который ваше приложение будет хешировать до старого хеша.
ruakh
4
@JayBlanchard Потому что, когда вы нажимаете пробел на одной машине и когда вы нажимаете ее на другой, вы можете получить две разные кодовые точки Unicode, и у них будут две разные кодировки UTF-8, при этом пользователь ничего не знает. Можно было бы возразить, что это проблема, которую вы хотите игнорировать, но RFC 7613 был основан на таких реальных проблемах, это не рекомендация по установке.
Unslander Monica
1
@ruakh После того, как вы решите обрабатывать пароли определенным образом, они должны оставаться такими же, иначе что-то сломается для существующих вариантов использования. Если вы собираетесь изменить метод предварительной обработки в будущем, вам следует сохранить его вместе с предварительно обработанным и хешированным представлением пароля. Таким образом, как только вы получите ввод, вы выбираете метод предварительной обработки / хеширования в зависимости от того, с чем вы сравниваете.
Unslander Monica