Что такое OTP и почему стоит отказаться от SMS
Одноразовые пароли (OTP) — это временные коды, которые используются для подтверждения личности пользователя при входе в систему. Традиционно OTP отправляются через SMS, но этот метод имеет ряд недостатков: задержки доставки, возможные проблемы с безопасностью из-за перехвата сообщений, а также дополнительные расходы на отправку SMS.
Вместо этого можно использовать альтернативные способы генерации и передачи OTP, например, через email, push-уведомления, приложения-генераторы токенов (Google Authenticator, Authy) или даже через специальные плагины WordPress.
В этой статье мы рассмотрим, как реализовать авторизацию по OTP без использования SMS, используя email и генерацию кода на сервере, с примерами кода и рекомендациями по безопасности.
Настройка WordPress для авторизации по OTP через email
Генерация и сохранение OTP
Для начала создадим функцию, которая будет генерировать единоразовый код и сохранять его в метаданных пользователя с ограничением по времени действия. Ключевые моменты:
- Код должен быть случайным и достаточно длинным (например, 6 цифр).
- Срок действия кода — например, 5 минут.
- Код хранится в базе, чтобы можно было проверить его при входе.
function wpauth_generate_otp_for_user($user_id) {
$otp = wp_rand(100000, 999999); // 6-значный код
$expire = time() + 300; // 5 минут
update_user_meta($user_id, 'wpauth_otp_code', $otp);
update_user_meta($user_id, 'wpauth_otp_expire', $expire);
return $otp;
}Отправка OTP по email
После генерации кода отправим его пользователю на email. Для этого используем стандартную функцию wp_mail:
function wpauth_send_otp_email($user_email, $otp) {
$subject = 'Ваш одноразовый код для входа на сайт';
$message = "Здравствуйте!\nВаш код для входа: {$otp}\nОн действителен 5 минут.";
wp_mail($user_email, $subject, $message);
}Добавление формы ввода OTP на страницу входа
Для реализации процесса авторизации создадим двухэтапную форму:
- Пользователь вводит логин и нажимает "Получить код".
- Если логин корректен, генерируется OTP и отправляется на email.
- Пользователь вводит полученный код и подтверждает вход.
Реализуем обработчики и форму с помощью хуков login_form и authenticate. Пример упрощённой формы:
add_action('login_form', 'wpauth_add_otp_field');
function wpauth_add_otp_field() {
if (isset($_POST['log']) && isset($_POST['wpauth_otp_step'])) {
echo '<p><label>Введите код из email</label><br><input type="text" name="wpauth_otp_code" size="20" /></p>';
} else {
echo '<p><input type="hidden" name="wpauth_otp_step" value="1" /></p>';
}
}Далее в функции аутентификации проверим введённый код:
add_filter('authenticate', 'wpauth_authenticate_with_otp', 30, 3);
function wpauth_authenticate_with_otp($user, $username, $password) {
if (isset($_POST['wpauth_otp_step']) && $_POST['wpauth_otp_step'] == '1') {
// Первый шаг: проверяем логин, генерируем и отправляем OTP
$user = get_user_by('login', $username);
if (!$user) {
return new WP_Error('invalid_login', 'Неверный логин');
}
$otp = wpauth_generate_otp_for_user($user->ID);
wpauth_send_otp_email($user->user_email, $otp);
// Останавливаем обычный вход, показываем форму ввода OTP
return null;
} elseif (isset($_POST['wpauth_otp_code'])) {
// Второй шаг: проверяем OTP
$user = get_user_by('login', $username);
if (!$user) {
return new WP_Error('invalid_login', 'Неверный логин');
}
$saved_otp = get_user_meta($user->ID, 'wpauth_otp_code', true);
$expire = get_user_meta($user->ID, 'wpauth_otp_expire', true);
if (time() > $expire) {
return new WP_Error('otp_expired', 'Код истёк');
}
if ($_POST['wpauth_otp_code'] != $saved_otp) {
return new WP_Error('invalid_otp', 'Неверный код');
}
// Успешная авторизация
delete_user_meta($user->ID, 'wpauth_otp_code');
delete_user_meta($user->ID, 'wpauth_otp_expire');
return $user;
}
return $user;
}Рекомендации по безопасности и UX
Важно учитывать, что при использовании OTP без пароля нужно максимально защитить процесс от злоупотреблений:
- Ограничьте количество попыток ввода OTP, чтобы избежать перебора.
- Используйте nonce и проверяйте их в формах для защиты от CSRF.
- Логируйте успешные и неуспешные попытки для анализа.
- Добавьте таймаут между запросами OTP.
Для улучшения пользовательского опыта можно интегрировать уведомления через плагины, например, использовать WPRemark для показа сообщений об ошибках и успехе.
Использование готовых плагинов для OTP без SMS
Если не хочется писать код самому, можно обратить внимание на готовые решения. Некоторые популярные плагины поддерживают OTP через email или приложения-генераторы токенов:
- WP Simple OTP Verification — бесплатный плагин с поддержкой email для OTP.
- WP 2FA — расширенный плагин с множеством способов двухфакторной аутентификации, включая OTP через приложения.
Для интеграции этих плагинов с кастомными формами авторизации можно использовать их API и хуки, что позволит гибко настроить процесс на сайте.