Чому коди TOTP не працюють, коли годинник пристрою розходиться
Код — це хеш секрету й поточного кроку часу. Порівняйте зсуви на обох кінцях, а потім виправте годинник замість розширення вікна.
Одноразові коди можуть бути цілком правильними на вашому телефоні, і все ж сервер відхилить їх тієї ж секунди. Обидві сторони обчислюють ту саму функцію зі спільного секрету й поточного кроку часу, тому розбіжність у часі дає розбіжність у коді. Через це дрейф годинника стає не просто незручністю, а несправністю, значущою для безпеки.
Тут важливі два годинники, і виправлення видимого — це те, що люди роблять першим. Той, який зазвичай потребує уваги, — інший.
Код — це функція часу, а не пароль
TOTP бере спільний секрет і лічильник, похідний від поточного часу, пропускає обидва через хеш із ключем і обрізає результат до короткого десяткового рядка, як визначено в RFC 6238. Лічильник просувається на кожному кроці часу, зазвичай на тридцять секунд, тому той самий секрет дає нове значення, коли крок змінюється. Перевіряльник перераховує очікуване значення для поточного кроку й порівнює, що потребує того самого секрету й того самого уявлення про теперішнє. Пароль залишається придатним для повторного використання, доки його не змінять, а це значення спливає на межі, якої клієнт не бачить.
Тому один код працює, а наступний зазнає невдачі за мить. Це також пояснює, чому копіювання коду з повідомлення в чаті — така ненадійна звичка.
Два годинники мають збігатися, а не один
Матеріал реєстрації — це перше спільне, а час — друге. Якщо секрет правильний, а годинники розходяться більше за дозволене вікно, кожне згенероване значення потрапляє в неправильний крок і відхиляється. Якщо годинники збігаються, а секрет неправильний, кожне значення також відхиляється, і обидві невдачі виглядають однаково на екрані входу. Розділити їх означає перевірити запис облікового запису й час окремо, саме в такому порядку.
Годинник перевіряльника заслуговує такої ж перевірки, як і годинник пристрою. Сервер із несправним джерелом часу відхиляє правильні коди всіх користувачів одразу, і звіти описуватимуть раптову аварію, а не дрейф. Цей зразок варто розпізнавати, бо його виправлення належить серверу, а не сотні телефонів.
Скільки коштує розширення вікна
Реалізації можуть приймати код із сусіднього кроку, щоб поглинути невеликі відмінності, і ця терпимість — проєктне рішення, а не безкоштовне налаштування. Кожен додатковий крок множить кількість значень, чинних у будь-який момент, а саме цього й хоче атакувальник, який вгадує. Правило проти повторів важливе з тієї ж причини, адже код, прийнятий двічі, — це код, що корисно витік. Адміністратор, який розширює вікно, щоб заглушити скарги, міняє реальну властивість на косметичне поліпшення.
Виправлення годинника — це ремонт, а розширення вікна — заспокійливе. Перше усуває причину, друге її приховує.
Перевірте обидва годинники, перш ніж повторити спробу
Прочитайте час на пристрої та на сервері й порівняйте зсуви, а не показаний місцевий час. Наведені нижче команди показують стан синхронізації й необроблений момент UTC на хості або сервері Linux. Виконайте їх на обох кінцях, перш ніж змінювати будь-яке налаштування автентифікації.
timedatectl
date -u +'%Y-%m-%dT%H:%M:%SZ'
chronyc tracking
timedatectl timesync-status
Зсув, виміряний у секундах, нешкідливий, виміряний у хвилинах пояснює відмову, а система, яка не повідомляє жодного джерела синхронізації, є кандидатом на обидва. Порівняйте дві позначки часу UTC безпосередньо, оскільки місцевий час містить часовий пояс, якого алгоритм ніколи не бачить. Якщо зсуви малі, а коди все ще не працюють, припиніть налаштовувати годинники й натомість огляньте запис реєстрації. Повторні спроби проти заблокованого облікового запису ускладнюють спостереження початкової несправності.
Запишіть час відмови, зсув і текст помилки, а спільний секрет залиште поза цим. Підтримка може працювати з першими трьома й ніколи не повинна бачити четверте.