Лучшие практики для кодов подтверждения электронной почты

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

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

md5("xxxxxxxxx".$username."xxxxxxxxxxx".$timestamp."xxxxxxxxx"); 

Где $ timestamp относится к времени создания пользователя. В целом я был очень доволен этим, но потом я подумал, достаточно ли это достаточно безопасно? А как насчет возможности столкновения? И мне также нужно генерировать коды для сброса пароля и т. Д. Если бы я использовал подобную методологию, столкновение могло бы привести к тому, что один пользователь случайно сбросит пароль другого пользователя. И это не хорошо.

Итак, как вы это делаете? Мои мысли были таблицей следующего формата:

 codePK (int, aI), userID (int), type (int), code (varchar 32), date (timestamp) 

Где «тип» будет 1, 2 или 3, что означает «активация», «изменение электронной почты» или «сброс пароля». Это хороший способ сделать это? У вас есть лучший способ?

Используя метод, аналогичный вышеизложенному, могу ли я автоматически удалить что-нибудь в течение двух дней без использования cron-заданий? Мой хост (nearfreespeech.net) не поддерживает их. Если это вообще возможно, я бы хотел избежать выполнения cron-задания на внешнем хосте, который wget – это скрипт, который удаляет все, так как это просто messy = P.

Благодаря!
скуловая кость

Обновить:
Чтобы пояснить: я понял, что единственным способом безопасного и безопасного решения этой задачи является использование базы данных, чего пыталась избежать первоначальная функция. Мой вопрос заключается в том, как следует структурировать таблицу (или таблицы?). Кто-то предложил мне покончить с CodePK и просто сделать код ПК. Короче говоря, мой вопрос: это то, что вы делаете?

Solutions Collecting From Web of "Лучшие практики для кодов подтверждения электронной почты"

Когда мне нужны эти трюки, это, как правило, одна из двух причин, упомянутых вами:

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

Конечно, было бы много других случаев, когда вы решили использовать такую ​​конструкцию.

Прежде всего, вы всегда должны использовать какую-то соль, которая скрыта и что только вы знаете. Обратите внимание, что эта соль должна отличаться для каждого пользователя. Соль может быть, например, рассчитана как sha256(something random) . Затем эта соль должна быть сохранена в базе данных вместе с именем пользователя и паролем (хэшируется солью).

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

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

Что это в основном сводится к:

  • Хешируйте пароли пользователей с помощью уникальной соли для пользователя ( и, возможно, глобальной секретной соли).
  • Генерируйте ключ путем хэширования ряда случайных или псевдослучайных источников, таких как timestamps, mt_rand() или даже random.org, если вам действительно нужны случайные вещи.
  • Никогда не используйте свою глобальную соль или соль, которая уникальна для пользователя для хэширования всего, к чему пользователь получает доступ, включая ключи сброса пароля, ключи активации и т. Д.

Пожалуйста, не то чтобы я ни в коем случае не был экспертом по вопросам безопасности, и я, вероятно, забыл о нескольких вещах, и, возможно, я упомянул о некоторых очень плохих вещах. Только мои 5 центов 😉

Зачем использовать любые данные пользователя в качестве основы для ключа авторизации?

Я предполагаю, что вы храните деактивированные данные в базе данных, поэтому почему бы просто не добавить дополнительную запись, которая является просто случайным ключом (возможно, uniqid md5 с некоторыми дополнительными манипуляциями), а затем проверить на это?

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

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

Почему бы не создать уникальный индекс кода? Значит, никогда не будет столкновения?

Кроме того, если вам не нужно создавать хэш из пользовательского ввода и сопоставлять его с хэшем базы данных (подтверждение по электронной почте, сброс пароля и т. Д.) – вы можете добавить случайную строку в тело хэша, например, md5('xxx'.$username.'xxx'.time().'xxx'.rand())

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