С ростом числа угроз кибербезопасности, для разработчиков становится все более и более необходимым обновлять стандарты безопасности веб-приложений и быть при этом уверенными в том, что аккаунты пользователей в безопасности. Для этого в настоящее время многие онлайн-приложения просят пользователей добавить дополнительный уровень безопасности для своей учетной записи. Они делают это за счет включения двухфакторной аутентификации. Существуют различные методы реализации двухфакторной аутентификации, и аутентификация TOTP (алгоритм одноразового пароля на основе времени) является одним из них.
Чтобы понять, что из себя представляет TOTP и как он используется, необходимо сначала кратко рассмотреть более базовые понятия. Первое из них – двухфакторная аутентификация. Двухфакторная аутентификация (или многофакторная аутентификация) — это метод идентификации пользователя в каком-либо сервисе (как правило, в Интернете) при помощи запроса аутентификационных данных двух разных типов, что обеспечивает двухслойную, а значит, более эффективную защиту аккаунта от несанкционированного проникновения. Это означает, что после включения двухфакторной аутентификации пользователь должен пройти еще один шаг для успешного входа в систему. Стандартные шаги для входа в учетную запись – это ввод логина и ввод пароля (рис.1).
Включение двухфакторной аутентификации добавляет в порядок входа дополнительный шаг (рис.2). Этот метод более безопасен, поскольку преступник не может получить доступ к учетной записи пользователя, если у него нет доступа как к обычному паролю пользователя, так и к одноразовому паролю.
В настоящее время существует два широко используемых метода получения одноразового пароля:
На основе SMS. Каждый раз, когда пользователь входит в систему, он получает на указанный в учетной записи номер мобильного телефона текстовое сообщение, которое содержит одноразовый пароль.
На основе TOTP. При включении двухфакторной аутентификации пользователю предлагается отсканировать QR-код с помощью специального приложения для смартфона, которое в дальнейшем постоянно генерирует одноразовый пароль для пользователя.
Метод на основе SMS не требует пояснений. Несмотря на свою простоту, он имеет ряд проблем. Например, ожидание SMS при каждой попытке входа в систему, проблемы с безопасностью и т. д. Вследствие чего NIST еще в 2016 году рекомендовала не использовать его в новых системах аутентификации. В связи с минусами метода на основе SMS, метод на основе TOTP становится популярным из-за его преимуществ.
Также, стоит отметить, что в настоящий момент есть некоторые разногласия о том, что именно считать шагами, а что факторами аутентификации. Общепризнанным является существование трех факторов:
Знание, например, пароль
Обладание (в физическом смысле), например, смартфон
То, чем вы являетесь, например, биометрические данные
При этом шаги аутентификации являются субъединицами факторов, так, если для входа в систему необходимо введение двух паролей, то по сути мы используем только фактор знания. Если говорить о рассматриваемых нами методах, то метод на основе SMS принято относить к двухшаговой, но однофакторной аутентификации, т. к. пароль для SMS генерируется на сервере, а TOTP к двухфакторной, поскольку для генерации пароля необходимо наличие определенного приложения на смартфоне, что усложняет задачу доступа злоумышленников к этой информации.
Итак, используя для двухфакторной аутентификации метод на основе TOTP, мы создаем одноразовый пароль на стороне пользователя (а не на стороне сервера) через приложение для смартфона. Это означает, что у пользователя всегда есть доступ к своему одноразовому паролю. А также предотвращает отправку текстового сообщения сервером при каждой попытке войти в систему. Кроме того, сгенерированный пароль изменяется через определенный промежуток времени, что делает его, по сути, одноразовым.
Для реализации двухфакторной аутентификации с использованием TOTP необходимо учитывать основное требование – пароль должен создаваться на стороне пользователя, а также постоянно меняться.
Решение данной задачи может выглядеть следующим образом:
Когда пользователь включает двухфакторную аутентификацию, происходит следующее
Внутренний сервер создает секретный ключ для этого конкретного пользователя
Затем сервер передает этот секретный ключ телефонному приложению пользователя
Телефонное приложение инициализирует счетчик
Телефонное приложение генерирует одноразовый пароль, используя этот секретный ключ и счетчик
Телефонное приложение изменяет счетчик через определенный интервал и восстанавливает одноразовый пароль, делая его динамическим
Однако, у данной последовательности действий есть несколько проблем. Первая из них заключается в том, как приложение будет генерировать одноразовый пароль. С этой проблемой справляется предшественник TOTP метода – алгоритм HOTP.
HOTP переводится как «Одноразовый пароль на основе HMAC». Этот алгоритм был опубликован инженерной группой Интернета (IETF) как RFC4226. HOTP определяет алгоритм создания одноразового пароля из секретного ключа и счетчика.
Этот алгоритм включает в себя два этапа:
Создать хеш HMAC (используя алгоритм хеширования SHA-1) из секретного ключа и счетчика
hmacHash = HMAC-SHA-1 (секретный ключ, счетчик)
В этом коде на выходе будет строка длиной 20 байт. Эта длинная строка не подходит в качестве одноразового пароля. Итак, нам нужен способ обрезать эту строку. HOTP определяет способ обрезать эту строку до желаемой длины
hmacHash[19] means 19th byte of the string.offset = hmacHash[19] & 0xf;
truncatedHash = (hmacHash[offset++] & 0x7f) << 24 | (hmacHash[offset++] & 0xff) << 16 | (hmacHash[offset++] & 0xff) << 8 | (hmacHashh[offset++] & 0xff);
finalOTP = (truncatedHash % (10 ^ numberOfDigitsRequiredInOTP));
В этом алгоритме мы сначала получаем смещение, которое является последними 4 битами hmacHash [19]
. После этого мы объединяем байты из hmacHash [offset]
в hmacHash [offset + 3]
и сохраняем последний 31 бит в truncatedHash
. Наконец, используя простую операцию по модулю, мы получаем одноразовый пароль разумной длины.
Это в значительной степени определяет алгоритм HOTP. Документ RFA4226 объясняет, почему это наиболее безопасный способ получить одноразовый пароль из этих двух значений.
Итак, мы нашли способ получить одноразовый пароль с помощью секретного ключа и счетчика. А как следить за счетчиком? Ответ на этот вопрос находится в TOTP. TOTP переводится как «Одноразовый пароль на основе времени». Он был опубликован IETF как RFC6238. TOTP использует алгоритм HOTP для получения одноразового пароля. Единственная разница в том, что здесь вместо «счетчика» используется «время», и это дает решение нашей проблемы. Это означает, что вместо инициализации счетчика и его отслеживания мы можем использовать время в качестве счетчика в алгоритме HOTP для получения OTP. Поскольку и сервер, и телефон имеют доступ ко времени, ни один из них не должен отслеживать счетчик. Кроме того, чтобы избежать проблемы с разными часовыми поясами сервера и телефона, мы можем использовать временную метку Unix, которая не зависит от часовых поясов. Однако время Unix определяется в секундах, поэтому оно меняется каждую секунду. Это означает, что сгенерированный пароль будет меняться каждую секунду, что не очень хорошо. Вместо этого нам нужно добавить значительный интервал перед изменением пароля. Например, приложение Google Authenticator меняет код каждые 30 секунд.
counter = currentUnixTime / 30
Итак, мы решили проблему счетчика. Теперь нам нужно решить нашу третью проблему: поделиться секретным ключом с приложением телефона. Здесь нам может помочь QR-код. Хотя есть возможность попросить пользователей вводить секретный ключ напрямую в приложение телефона, безопасность ключа зависит от его длины, и пользователю будет неудобно вводить такую длинную строку. Поскольку большинство смартфонов оснащено камерой, пользователь может использовать ее для того, чтобы отсканировать QR-код, и получить от него секретный ключ. Все, что для этого нужно – преобразовать секретный ключ в QR-код и показать его пользователю. В настоящее время есть несколько бесплатных телефонных приложений (например, Google Authenticator App, Authy и т.д.), которые могут генерировать одноразовый пароль для пользователя. Поэтому в большинстве случаев создавать собственное телефонное приложение не нужно. Следующие псевдокоды объясняют способ реализации двухфакторной аутентификации на основе TOTP в веб-приложении.
When user request to enable 2-factor authentication
// Generate a secret key of length 20.secretKey = generateSecretKey (20);
// Save that secret key in database for this particular user. SaveUserSecretKey (userId, secretKey);
// convert that secret key into qr image.qrCode = convertToQrCode (secretKey);
// send the qr image as responseresponse (qrCode);
Пользователя просят отсканировать этот QR-код. Когда приложение телефона сканирует QR-код, оно получает секретный ключ пользователя. Используя этот секретный ключ, текущее время Unix и алгоритм HOTP, приложение телефона сгенерирует и отобразит пароль. Затем система просит пользователя ввести сгенерированный код после сканирования QR-кода. Это необходимо, чтобы убедиться, что пользователь успешно отсканировал изображение и приложение для телефона успешно сгенерировало код.
User types the code displayed in the application.
// Fetch secret key from database.secretKey = getSecretKeyOfUser (userId);
if (codeTypedByUser == getHOTP (secretKey, currentUnixTime / 30)) {enableTwoFactorAuthentication (userId);}
Здесь используется алгоритм HOTP на стороне сервера, чтобы получить аутентификацию на основе OTP по секретному ключу и текущему времени Unix. Если этот OTP совпадает с введенным пользователем, то появляется возможность включить двухфакторную аутентификацию для этого пользователя. Теперь, после каждой операции входа в систему, проверяется, включена ли для этого конкретного пользователя двухфакторная аутентификация. Если да, то запрашивается одноразовый пароль, отображаемый в приложении телефона. И если этот набранный код правильный, только тогда пользователь аутентифицируется.
User types the code displayed in the phone application to login
// Fetch secret key from database.secretKey = getSecretKeyOfUser (userId);
if (codeTypedByUser == getHOTP (secretKey, currentUnixTime)) {signIn (userId);}
Если пользователь потеряет код, есть несколько способов помочь пользователю восстановить его. Обычно, когда они включают двухфакторную аутентификацию, есть возможность показать секретный ключ вместе с QR-кодом и попросить их сохранить этот код в безопасном месте. Такие приложения, как Google Authenticator App, позволяют сгенерировать пароль путем прямого ввода секретного ключа. Если пользователь потеряет код, он может ввести этот надежно сохраненный секретный ключ в приложение телефона, чтобы снова сгенерировать одноразовый пароль. При наличии номера телефона пользователя возможно использовать метод на основе SMS, чтобы отправить пользователю одноразовый пароль, чтобы помочь ему восстановить код.
Двухфакторная аутентификация набирает популярность. Многие веб-приложения реализуют его для дополнительной безопасности. В отличие от метода на основе SMS, метод TOTP также не требует особых усилий. Так что эту функцию стоит реализовать для любого приложения.
sokolov_pavel
Мне кажется, что фактор владения по сути сводится к фактору знания т.к. секретный ключ, записанный на телефоне, информация об используемом алгоритме хэширования и т.д. не являются принципиально неотчуждаемыми от телефона или иного устройства. Более того, в реальной жизни секретный ключ для TOTP, и сопутствующая информация, будут скорей всего храниться на том же устройстве или даже в той же самой базе, где и сам пароль.
Может быть модель двух-шаговой аутентификации не так уж и плоха в виду того, что на конечно устройстве пользователя ничего не хранится, а как следствие это невозможно украсть? Если высылать код не через СМС, а, например, через пуш для уже аутентифицированного клиента, ряд проблем сразу уходит.
shuron
Есло на одном устройстве то смылс в этом действительно мало.
Но обычно вы логинитесь таки с рабоичей станции/куда-то а TOTP у вас на мобильном телефоне...