Темы



NTS: аутентифицированное время в Meta

Коротко сгенерировано ИИ по тексту статьи
  • Публичный сервис Meta поддерживает NTS по адресу nts.meta.com: пакеты аутентифицируются, а серверы не хранят состояние клиентов.
  • Meta открыла исходный код протокола, сервера и клиента в библиотеке времени на GitHub и призвала разработчиков добавить поддержку NTS.
  • Максимальный срок публичных TLS-сертификатов сократится до 200 дней в марте 2026 года, 100 дней в марте 2027-го и 47 дней в марте 2029-го.

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

NTS-at-Meta-Hero.png
  • Публичный сервис времени Meta теперь поддерживает NTS (Network Time Security, RFC 8915) по адресу nts.meta.com. Пакеты проходят аутентификацию, поэтому устройство может проверить, что время получено от нас и не было изменено в пути.
  • Наши серверы NTS не хранят состояние отдельных клиентов. Ключи cookie выводятся, а не хранятся и не реплицируются.
  • Мы открыли исходный код всего проекта, включая протокол, сервер и клиент, в библиотеке времени Meta на GitHub.
  • Мы также призываем всех, особенно тех, кто поддерживает клиенты NTP для Android или iOS, присоединиться к нам и добавить поддержку NTS. 

Ранее мы писали о том, как создали более точный сервис времени в масштабах Meta: перешли с ntpd на chrony, повысили точность с 10 миллисекунд до 100 микросекунд и открыли для всех time.meta.com.

Эта работа сделала время точным. Теперь мы делаем его проверяемым.

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

С 1985 года NTP не использует аутентификацию — как и многие базовые интернет-протоколы. Но именно с ним сверяют время действия каждого сертификата, токена и подписи. Клиент отправляет 48 байт, в ответ получает 48 байт и верит им. Ни подписи, ни подтверждения личности нет.

Это не единственный такой протокол. Многие базовые интернет-протоколы создавались для сети, в которой никого не считали потенциальным злоумышленником, и с тех пор отрасль пытается их дорабатывать. Но время отличается от них: это не просто ещё один протокол, который нужно защитить. Именно с ним сверяются при принятии любых других решений о безопасности.

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

  • Проверка сертификатов: notBefore и notAfter сверяются с локальными часами. Неверное время — неверный результат.
  • Срок действия токенов и учётных данных: фраза «действителен 15 минут» — это утверждение о времени.
  • Окна защиты от повторного воспроизведения: чтобы отклонить запрос старше N секунд, нужно знать текущее время.
  • Сопоставление и упорядочение записей журналов: если часы на двух хостах расходятся, получается хронология, которой никогда не было.

И сама проверка оказывается замкнутой на себе. Нельзя проверить notBefore/notAfter в X.509, не зная текущего времени. Фактически пришлось бы отключить проверку срока действия сертификата или реализовать один из предложенных обходных вариантов.

Есть два распространённых обходных решения. Оба плохи. Можно пропускать проверку, пока часы не будут настроены, — тогда устройство останется без защиты именно в самый уязвимый момент. Или можно заложить запас: сертификат, выпущенный в 12:00:00, будет отклонён клиентом, на часах которого 11:59:30, поэтому центры сертификации устанавливают для notBefore время на несколько минут раньше, а проверяющие системы незаметно расширяют допустимое окно. Обе стороны гадают, насколько часы другой стороны отстают или спешат.

Это было приемлемо, когда срок действия сертификата составлял 398 дней. Голосование CA/Browser Forum по предложению SC-081v3 изменило ситуацию. Максимальный срок действия вновь выпущенных публично доверенных TLS-сертификатов сократился до 200 дней в марте 2026 года, снизится до 100 дней в марте 2027 года и достигнет 47 дней в марте 2029 года. Одновременно срок повторного использования результатов проверки домена сократится до 10 дней.

При сроке в 47 дней ручное управление сертификатами перестаёт быть жизнеспособным в любых масштабах. Обновлять их придётся примерно раз в месяц, в автоматическом режиме — обычно через ACME. Автоматический цикл обновления на хосте с неточными часами не создаст заявку в службу поддержки. Сертификат будет перевыпущен или обновление завершится с ошибкой — по расписанию, за которым никто не следит.

Как работает NTS

NTS работает в несколько этапов, и возможность разделить их делает развёртывание практичным.

Этап 1 — согласование ключей (NTS-KE): TLS 1.3 через TCP/4460 с согласованием ALPN ntske/1. Клиент и сервер выбирают алгоритм AEAD, затем напрямую выводят из сеанса TLS два направленных ключа сеанса (C2S и S2C) с помощью экспортёра RFC 5705. Сервер выдаёт восемь cookie, сообщает клиенту, к какому NTP-серверу подключаться, используя запись согласования сервера, и закрывает соединение. Это происходит один раз, а не для каждого пакета.

Мы согласовываем три алгоритма AEAD: AES-SIV-CMAC-256 (ID 15), который RFC 8915 предписывает обязательно реализовать и который, вероятнее всего, запросит неизвестный нам клиент; AES-SIV-CMAC-512 (17); и AES-128-GCM-SIV (30). Приоритет отдаётся предпочтениям клиента.

Этап 2 — аутентифицированный NTP: стандартный NTPv4 по UDP/123 до объявленного сервера с полями расширения NTS. Запрос содержит уникальный идентификатор, cookie и аутентификатор; аутентификатор охватывает всё, что расположено перед ним, но ничего не шифрует. Сервер открывает cookie, чтобы восстановить ключи сеанса, проверяет аутентификатор и отправляет ответ с тем же уникальным идентификатором и собственным аутентификатором. Последний содержит полезную нагрузку: новые cookie, зашифрованные внутри него.

Поддельный пакет не проходит проверку и отбрасывается. Мы не отправляем NTS NAK, поэтому сбой невозможно отличить от потери пакета, и его нельзя использовать, чтобы заставить клиента начать новое согласование ключей. В повторно переданном ответе будет неверный уникальный идентификатор, который не совпадёт ни с одним ожидающим запросом. Поскольку новые cookie передаются внутри аутентификатора ответа, а не в открытом виде, наблюдатель при каждом обмене видит новую непрозрачную последовательность и не может отслеживать клиента при переходе между сетями. Клиент должен использовать каждую cookie один раз — таковы условия этой схемы. Сервер не хранит состояние и не отслеживает cookie.

Cookie без состояния

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

Мы не реплицируем ключи. Каждый сервер выводит ключ для запечатывания из общего главного секрета и текущего дня:

key = HKDF-SHA256(master, salt = BE32(day), info = «fbnts-cookie-seal-v1»)


Отсчёт day ведётся целыми 24-часовыми периодами с начала эпохи Unix, а не календарными днями. Поэтому здесь нет ни часовых поясов, ни переходов на летнее время, и каждый хост вычисляет одно и то же целое число для одного и того же момента. Это число служит идентификатором ключа cookie и передаётся в открытом виде. Если сервер получает cookie, которую раньше не видел или которая была запечатана хостом, с которым он никогда не связывался, он заново выводит ключ и открывает её. Для учёта расхождения часов на границе смены ключа мы принимаем значения за два предыдущих дня и за один последующий.

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

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

Использование NTS

Одна строка конфигурации chrony:

pool nts.meta.com nts iburst maxsources 5

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

Именно поэтому мы используем pool, а не server. Одна строка server задаёт одну ассоциацию и одного ответчика — это единственная точка отказа. А протоколу NTP нужны несколько источников, чтобы можно было отсеять ненадёжный. pool запрашивает maxsources независимых ассоциаций. Каждая устанавливает собственное соединение TLS для согласования ключей и получает отдельную пару ключей сеанса:

$ chronyc authdata
Имя/IP-адрес Режим KeyID Тип KLen Последний раз Попытки NAK Cookie CLen
time1.meta.com NTS 5 30 128 27 0 0 8 68
time2.meta.com NTS 7 30 128 142 0 0 8 68
time3.meta.com NTS 10 30 128 548 0 0 8 68
time4.meta.com NTS 1 30 128 1177 0 0 8 68
time5.meta.com NTS 2 30 128 1177 0 0 8 68

Пять строк — пять независимых аутентифицированных источников, одна строка конфигурации и одна конечная точка KE.

Посмотрим на данные слева направо. Тип 30 — согласованный алгоритм AEAD AES-128-GCM-SIV с длиной ключа сеанса KLen 128 бит; chrony указывает его первым, и приоритет отдаётся предпочтениям клиента. CLen 68 — длина cookie: 36 байт оболочки вокруг двух ключей по 16 байт внутри. Cook 8 означает, что на руках восемь cookie, а NAK 0 — что ни одна не была отклонена.

Но самое интересное в таблице не видно. Ключи сеанса в каждой строке получены в ходе отдельного рукопожатия TLS и работают только для соответствующей ассоциации. Общим является ключ, которым они запечатываются в cookie, — номер дня эпохи, вычисленный описанным выше способом. Он одинаков на всех наших ответчиках, записан в каждой cookie и не виден клиенту. Благодаря такому разделению одно согласование ключей может перенаправить клиента к пяти разным ответчикам, которые никогда не связывались друг с другом.

Когда участник пула завершает согласование ключей и переключается на согласованного ответчика, освободившийся адрес KE передаётся следующему участнику, ещё не прошедшему согласование. Это повторяется, пока не ответят maxsources ответчиков. Пять источников становятся доступны примерно за 20 минут — каждый участник по очереди завершает собственное согласование ключей.

От каких атак защищает NTS

В отличие от NTP, NTS не позволяет злоумышленнику, находящемуся между сторонами (MITM), подделать ответ. Для классической MITM-атаки не нужно взламывать криптографию — достаточно ответить клиенту раньше настоящего сервера. Если злоумышленник переведёт часы назад, он сможет снова сделать действительными просроченные сертификаты или использовать отозванные токены. Любой механизм контроля, основанный на истечении срока действия, будет обойдён. Если же злоумышленник переведёт часы вперёд, срок действия всего истечёт одновременно. Устранить последствия такого сдвига сложнее: после определённой точки сбой уже нельзя исправить удалённо.

Рассмотрим, что произойдёт с устройством, которое убедили в том, что сейчас 2037 год. NTP считает секунды в 32-битном поле, переполняющемся в феврале 2036 года. Клиент, оказавшийся за этой границей, вычислит поправку для неверной эпохи — и механизм, призванный исправить неправильные часы, отдалит их ещё сильнее. Тем временем все сертификаты на устройстве давно просрочены, поэтому TLS не работает, а значит, устройство не может связаться ни с чем, что могло бы помочь, включая собственную службу обновлений. Исправление невозможно доставить, потому что для этого нужны часы, которые уже не работают.

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

А теперь представьте атаку со сдвигом часов вперёд на хосте, который выдаёт учётные данные. Короткоживущие учётные данные считаются безопасными, потому что быстро истекают. Иными словами, их короткий срок действия выполняет ту роль, которую в противном случае играла бы процедура отзыва. Это свойство полностью зависит от часов хоста, выдающего учётные данные. Если его убедить, что наступил следующий год, он подпишет учётные данные, действительные дольше предусмотренного вами срока.

Чего NTS не исправляет

Атаки с задержкой. В RFC 8915 это сказано прямо. Злоумышленник, задерживающий ваши пакеты, может сдвинуть ваши часы на величину до половины внесённой задержки, и никакая криптография протокола этого не обнаружит, поскольку каждый байт подлинный. Аутентификация сообщает, кто сформировал пакет, но не то, сколько времени он провёл в пути. Защита — стандартная: несколько независимых источников, ограничения на допустимые значения и ограниченные шаги коррекции.

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

Первоначальная настройка. NTS-KE работает поверх TLS, а TLS нужны исправно работающие часы — это та же проблема замкнутого круга, о которой говорилось выше. Устройство с неисправными часами реального времени всё равно должно сначала получить приблизительно правильное время, чтобы установить первое соединение.

Неверные серверы. NTS аутентифицирует путь передачи данных, а не правильность ответа. Сервер, который настроен правильно, прошёл аутентификацию, но при этом показывает неверное время, передаст вам его с безупречной подписью. По-прежнему необходимы кворум, проверки на разумность значений и мониторинг.

Монотонность. Аутентифицированное время всё ещё является календарным временем, а календарные часы могут идти назад — во время високосной секунды или при применении коррекции. В конце 2016 года с этим столкнулась авторитетная DNS-система Cloudflare: длительность обмена данными с резолвером, измеренная через високосную секунду, оказалась отрицательной, это повлияло на выбор вышестоящего сервера и вызвало сбой Go rand.Int63n (). Ничего не подделали и не доставили не туда. Если ваш код измеряет прошедшее время, используйте монотонные часы.

Внедрение

RFC 8915 — «Безопасность сетевого времени для протокола сетевого времени» — был опубликован в сентябре 2020 года в треке стандартов IETF как проект стандарта. Cloudflare запустила time.cloudflare.com с поддержкой NTS за 15 месяцев до этого, в июне 2019 года, на основе актуального на тот момент проекта стандарта, и показала, что технология работает в больших масштабах.

Сегодня в публичном списке серверов NTS — несколько десятков записей. В основном это национальные метрологические институты и операторы интернет-инфраструктуры, например PTB, Netnod и time.nl. Теперь к ним добавится ещё один.

Гораздо больше пробелов на стороне клиентов. Поддержка NTS есть там, где её ожидаешь увидеть в серверном мире: её реализуют chrony и ntpsec. Но её совсем нет в стандартных клиентах времени на платформах, на которых работает большинство устройств в интернете. 

Системная синхронизация времени в Android использует обычный SNTP по UDP/123 — фиксированный 48-байтовый пакет без обработки полей расширения, наряду с NITZ и GNSS, — поэтому поддержки NTS там нет. Устройства Apple синхронизируют время с помощью timed, подключаясь к time.apple.com; насколько нам известно, NTS там тоже не поддерживается.

Эти два программных стека устанавливают время на миллиардах телефонов, часов и гарнитур, и каждое устройство полагается на неаутентифицированный UDP-пакет. Производитель может уже сегодня установить отдельный клиент с поддержкой NTS — chrony прекрасно работает на Android, —, но это лишь обходной путь для функции, которую должна обеспечивать сама платформа.

Протокол готов, серверы появляются, реализации для клиентов существуют. 

Не хватает поддержки на мобильных устройствах.

Помогите внедрить NTS

nts.meta.com уже работает и доступен бесплатно. Исходный код опубликован на github.com/facebook/time.

Если вы поддерживаете публичный сервис времени, включите NTS. Если вы разрабатываете клиент NTP, реализуйте RFC 8915. Если вы отвечаете за стек времени в мобильной ОС, именно здесь и нужно устранить пробел: на Android и iOS устанавливается время на большинстве устройств в мире, но обе платформы по-прежнему делают это с помощью неаутентифицированного пакета.

Мы годами работали над повышением точности времени. Но точность без подлинности даёт лишь очень точное значение из неизвестного источника. Теперь время может быть и точным, и достоверным.

Благодарности

Мы хотели бы поблагодарить Софию Скальцо, Пабло Мадзини, Вадима Федоренко, Патрика Каллена и Ийсинь Вэй за помощь в этом проекте.

© Engineering at Meta