Одноразовый пароль на основе времени: объяснение TOTP

Пользователям Интернета регулярно приходится вводить пароли — например, при входе в социальные сети, при совершении покупок в Интернете или при использовании интернет-банкинга. Пароли предотвращают доступ третьих лиц к конфиденциальным данным. Однако многие пользователи недостаточно тщательно следят за безопасностью в Интернете: профессионалы могут взломать простые пароли за считанные секунды. Другие люди создают хорошие пароли, но не хранят их надежно, оставляя тем самым дверь открытой для преступников. Кроме того, слабые места в сервисах, на которые подписаны пользователи, также не являются мелочью. Если такие сервисы не обеспечивают надлежащую защиту паролей, данные тысяч пользователей могут оказаться под угрозой.

Одним из способов минимизации риска является использование двухфакторной или многофакторной аутентификации. Вместо использования только пароля требуется еще как минимум одно средство аутентификации. Пользователи данной технологии получают этот дополнительный фактор аутентификации через смартфон или специальное аппаратное устройство (так называемый «токен»). Общим моментом между большинством этих дополнительных факторов является то, что они уникальны и действуют только в течение короткого времени — другими словами, генерируется одноразовый пароль, основанный на времени. Давайте рассмотрим, как это работает.

Зачем нам нужен TOTP?

Обычные пароли — какими бы сложными пользователь их ни делал — имеют недостаток: если кто-то другой знает строку символов, безопасность уже не гарантирована. Одним из решений является регулярная смена паролей, но даже самые образцовые пользователи не делают этого каждый час. Решением является TOTP: пароль, который действителен только в течение короткого времени, после чего срок его действия истекает. Рабочая группа по разработке Интернета (IETF) опубликовала алгоритм одноразового пароля в 2011 году в RFC 6238 для повышения безопасности в Интернете.

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

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

Как работает алгоритм одноразового пароля на основе времени?

В основе TOTP лежит хэш-функция — криптографическая процедура, при которой секретный ключ и метка времени объединяются в зашифрованную символьную строку. И пользователь, и сервер знают секретный ключ. Временная метка указывается в Unix-времени.

Факт

Время Unix — это значение, соответствующее количеству секунд, прошедших с 1 января 1970 года.

TOTP фактически является дальнейшим развитием HOTP, что расшифровывается как одноразовый пароль на основе HMAC. Как и HOTP, TOTP основан на процедуре HMAC — операции хэширования в фоновом режиме. И устройство пользователя, и сервер генерируют хэш-значение, комбинируя секретный ключ со счетчиком. Эти два значения идентичны, так работает аутентификация.

Сама хэш-функция не определена; на практике часто используется SHA-1 (в том числе, например, в Google Authenticator). SHA-1 генерирует 160-битное хэш-значение. Для удобства это значение усекается с помощью функции сжатия. В итоге получается короткое число (например, шесть цифр), которое пользователь может легко использовать для входа в веб-службу.

Примечание

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

Для второй части функции HOTP использует счетчик, который совместно используется сервером и пользователем. Проблема заключается в том, что сгенерированный код остается действительным до тех пор, пока его не используют. TOTP ограничивает это: сгенерированный код может быть использован только в течение определенного периода времени. Как это работает?

Для алгоритма одноразового пароля, основанного на времени, есть три важные формулы:

TOTP = HOTP(SecretKey,CurrentTime).

Эта основная формула просто определяет, что TOTP — это процедура HOTP с двумя параметрами — SecretKey и CurrentTime:

  • SecretKey: Случайно сгенерированный пароль, известный как серверу, так и клиенту.
  • CurrentTime: текущее время в Unix.

Однако это значение времени меняется каждую секунду, что не оставляет пользователю достаточно времени для ввода сгенерированного кода. Другими словами, через секунду TOTP уже недействителен, поскольку сервер уже сгенерировал новое хэш-значение. Поэтому требуется дополнительная формула:

CurrentTime = floor((unixtime(now) — unixtime(T0))/T1).

Параметр CurrentTime определяется следующим образом:

  • unixtime(now): Текущее время в Unix-времени
  • unixtime(T0): Время Unix в T0, точке, от которой отсчитываются шаги времени — в большинстве случаев полночь 1 января 1970 года (=0).
  • T1: Период, в течение которого будет действовать TOTP (обычно 30 секунд).
  • floor: Функция округления для округления вычисленного значения до целого числа.
Примечание

Теоретически, T0 может принимать любое значение, не обязательно 0. Главное, чтобы клиент и сервер выбрали одно и то же значение.

Эффект деления и округления заключается в том, что результат меняется через определенные промежутки времени.

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

Результат = TOTPmod10d

Операция модуло генерирует контрольную сумму:

  • mod 10: Модуло с делителем = 10
  • d: Желаемое количество цифр TOTP

Другими словами, основание (10) увеличивается до желаемого количества цифр, затем TOTP делится на это значение и извлекается остаток.

Пример расчета TOTP

Предположим, что мы хотим сгенерировать TOTP, действительный в течение 30 секунд. Мы можем начать с вычисления CurrentTime и определить, на какое время будет гарантирована действительность. Для значения unixtime(now) возьмем 1548322860, то есть 10:41 утра 24 января 2019 года. Если мы разделим это значение на 30, то получим ровно 51610762. Поскольку это уже целое число, округление даст тот же результат. Однако если мы установим CurrentTime на 15 секунд позже (т.е. 1548322875), то после деления получим 51610762,5. После округления значение, как и раньше, равно 51610762. Таким образом, CurrentTime остается неизменным. Следующая таблица показывает, что новое значение генерируется только каждые 30 секунд.

unixtime(now) unixtime(now)/30 floor(unixtime(now)/30)
1548322857 51610761.9000 51610761
1548322858 51610761.9333 51610761
1548322859 51610761.9667 51610761
1548322860 51610762.0000 51610762
1548322861 51610762.0333 51610762
1548322862 51610762.0667 51610762
1548322863 51610762.1000 51610762
1548322864 51610762.1333 51610762
1548322865 51610762.1667 51610762
1548322866 51610762.2000 51610762
1548322867 51610762.2333 51610762
1548322868 51610762.2667 51610762
1548322869 51610762.3000 51610762
1548322870 51610762.3333 51610762
1548322871 51610762.3667 51610762
1548322872 51610762.4000 51610762
1548322873 51610762.4333 51610762
1548322874 51610762.4667 51610762
1548322875 51610762.5000 51610762
1548322876 51610762.5333 51610762
1548322877 51610762.5667 51610762
1548322878 51610762.6000 51610762
1548322879 51610762.6333 51610762
1548322880 51610762.6667 51610762
1548322881 51610762.7000 51610762
1548322882 51610762.7333 51610762
1548322883 51610762.7667 51610762
1548322884 51610762.8000 51610762
1548322885 51610762.8333 51610762
1548322886 51610762.8667 51610762
1548322887 51610762.9000 51610762
1548322888 51610762.9333 51610762
1548322889 51610762.9667 51610762
1548322890 51610763.0000 51610763
1548322891 51610763.0333 51610763

Таким образом, наше текущее время установлено (51610762). Теперь мы используем генератор паролей для получения SecretKey: >cHSB_UQ#O5m;~b

HMAC (с SHA-1) объединяет секретный ключ и текущее время для получения хэш-значения (в шестнадцатеричном формате): c0 62 37 94 dd 37 7a 3a f0 91 22 08 1f 21 6f 9b 17 4b 17 45. Это 160-битное (20 байт) значение усекается до 31 бита с помощью так называемого динамического усечения. При этом выполняются следующие шаги: Сначала рассматриваются последние 4 бита. В нашем примере это число 0x5, которое также можно записать как 5 в десятичной системе счисления. Это дает значение смещения, которое будет использоваться для динамического усечения, и означает, что, начиная с байта с индексом 5, мы должны извлечь четыре байта (читать слева, начиная с 0): 0x377a3af0. В этом примере наше значение уже начинается с бита, равного 0. Если это не так, то его нужно соответствующим образом изменить. Таким образом, 31-битное значение имеет вид: 0x377a3af0, или 930757360.

Чтобы сократить эту 9-значную строку до 6 цифр, мы используем операцию модуляции, при необходимости дополняя результат ведущими нулями: 930757360 mod (106) = 757360. Теперь это TOTP, который действителен в течение 30 секунд. В сочетании с другим фактором это делает процедуру входа в систему достаточно безопасной.

Оцените статью
cdelat.ru
Добавить комментарий