Для аутентификации пользователей в большинстве случаев требуется лишь логин и пароль, но некоторые системы – такие, как банк-клиенты, или сервисы, использующие персональные данные пользователей, требуют повышенной безопасности при их аутентификации.
Многофакторная аутентификация (МФА, англ. 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 на телефон пользователя — для этого можно использовать приведенный в данной статье исходный код с вашими доработками.