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

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

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

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

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

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

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

codePK (int, a-I), userID (int), type (int), code (varchar 32), date (timestamp)

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

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

Спасибо!
Мала

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

4b9b3361

Ответ 1

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

  • В качестве ключа, используемого для проверки писем электронной почты, отправленных пользователю
  • В качестве ключа, используемого для ссылок reset

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

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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