Двухфакторная аутентификация с помощью SMS

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

Многофакторная аутентификация (МФА, англ. Multi-factor authentication, MFA) — расширенная аутентификация, метод контроля доступа к компьютеру, в котором пользователю для получения доступа к информации необходимо предъявить более одного «доказательства механизма аутентификации».

© Wikipedia

Двухфакторная аутентификация, или 2FA — это способ идентификации пользователя в системе с помощью двух типов аутентификационных данных. Всего применяются три типа таких данных:

1. То, что известно пользователю — к этому типу относятся пароли, пин-коды, ответы на секретные вопросы и другие данные, которые пользователь должен постоянно помнить и вводить в систему при каждом запросе;

2. То, что имеет пользователь — токен, устройство, которое имеется у пользователя и выполняет функцию генерации аутентификационных данных по специальному алгоритму. В качестве токена могут использоваться как отдельные устройства, подключаемые к компьютеру через USB-порт или Bluetooth, так и смартфоны со специальным программным обеспечением, таким как E-num для WebMoney Keeper или Google Authenticator, которое генерирует одноразовый пароль (OTP, One-Time Password). Также, кроме токена может использоваться электронная цифровая подпись (ЭЦП);

3. То, что присуще пользователю (биометрические данные) — устройства, сканирующие сетчатку глаза, отпечатки пальцев, геометрию лица, анализирующие голос и так далее.

2FA подразумевает использование первого типа данных и одного из двух остальных. Наиболее доверительным и удобным для пользователей является отправка SMS с кодом доступа. В данной статье мы рассмотрим пример внедрения 2FA с помощью платформы SMS-оповещений OperSMS в систему, написанную на PHP-фреймворке Yii под управлением СУБД MySQL.

Итак, предположим, что мы имеем систему, расположенную на домене example.uz, в которой при регистрации пользователей запрашиваются только стандартные данные, — такие, как имя пользователя и пароль. Для внедрения 2FA нам необходимо изменить структуру таблицы пользователей в базе данных, добавив поля «phone» и «validated».

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

<?php
// Генерируем случайное число от 100000 до 999999:
$code = random_int(100000,999999);
// Шифруем и сохраняем полученное число в сессию:
$_SESSION['vcode'] = substr(sha1($code), 0, 20);
// Получаем данные пользователя из таблицы users:
$user = Users::model()->findByPk(Yii::app()->user->id);
// Записываем номер телефона пользователя в переменную:
$phone = $user->phone;
// Формируем данные для запроса:
$data = array(
    array('phone' => $phone, 'text' => utf8_encode('Vash kod: ' . $code))
);
// Отправляем SMS с кодом на номер, указанный при регистрации
foreach ($data as $chunk) {
    // Инициализация соединения с сервером OperSMS:
    $ch = curl_init("http://185.8.212.51:8080/");
    // Включаем опцию возврата ответа:
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    // Устанавливаем ограничение на выполнение запроса 30 секунд:
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    // Собственно, сами данные:
    curl_setopt($ch, CURLOPT_POSTFIELDS, array(
        "login"    => "example",
        "password" => "P@5$w0Rd",
        // Кодируем массив в формат JSON:
        "data"     => json_encode($chunk)
    ));
    // Записываем результат выполнения запроса в переменную:
    $result = curl_exec($ch);
    // Закрываем соединение с сервером OperSMS:
    curl_close($ch);
}

Полученный код пользователь должен ввести в форму, появившуюся после отправки ему сообщения. После отправки формы, проверяем введенный код:

<?php
 
// Проверяем, введен ли валидный код:
if ($_POST['vcode'] && preg_match('/\d{6}/', $_POST['vcode']) {
 
    // Шифруем код и сравниваем его со значением переменной, хранящейся в сессии:
    if ($_SESSION['vcode'] == substr(sha1($_POST['vcode']), 0, 20)) {
        // Обновляем значение поля "validated":
        $user = Users::model()->findByPk(Yii::app()->user->id);
        $user->validated = 1;
        $user->save(false);
    }
 
}

Таким образом пользователь выполнил валидацию номера телефона. Теперь при каждом действии в системе, требующем повышенной безопасности, можно использовать двухфакторную аутентификацию посредством отправки SMS на телефон пользователя — для этого можно использовать приведенный в данной статье исходный код с вашими доработками.

[ Документация по API OperSMS ]


Комментарии (0)

Авторизуйтесь, чтобы добавлять комментарии
Отправьте нам сообщение