Ticketing
Документация

Аутентификационный хендшейк

Общий участок, где клиентский порт и Raft-порт кластера используют совершенно одну и ту же спецификацию. После установления соединения (после завершения TLS, если он используется) сервер первым отправляет challenge. Это обмен двумя текстовыми строками, разделёнными переводом строки (\n), выполняемый один раз на соединение.

От порта зависит только набор токенов, используемых для проверки — клиентский порт проверяет по client_tokens, Raft-порт — по cluster_tokens. Правила токенов для Raft-порта (какой токен отправляется, замена без простоя) смотрите в Установление соединения · аутентификация.

Поток

Подключающийся (клиент · пир)
Сервер
TCP-подключение · (TLS-хендшейк)
challenge: SHA-256 ␣ nonce
digest = SHA-256(token ∥ nonce) · 43 символа
сравнение с константным временем по всему списку токенов
успех → без ответа, сразу начинается основной протокол
немедленная отправка первого запроса (например, A · acquire)
если неудача
E · auth_failed → соединение закрыто
запросответ

1. Challenge (сервер → подключающийся)

Структураrefresh
<hash> <nonce>\n            например: SHA-256 aB3dEf_g\n
ПолеСодержимое
hashназвание алгоритма дайджеста. Сейчас всегда SHA-256, сервер принимает только его
nonceслучайная строка из 8 символов алфавита base64url. Из-за фрейминга по переводу строки длина в будущем может увеличиться — подключающийся должен считать nonce всем, что идёт после первого пробела

2. Response (подключающийся → сервер)

Структураrefresh
<digest>\n

digest = base64url_nopad( SHA-256( token_bytes ∥ nonce_bytes ) )

( — конкатенация байтов: к исходным байтам токена напрямую присоединяются ASCII-байты строки nonce)

  • base64url — это url-safe алфавит без паддинга (A–Z a–z 0–9 - _). Дайджест SHA-256 всегда занимает 43 символа.
  • Сервер проверяет по всему списку настроенных токенов сравнением с константным временем — по времени отклика нельзя понять, какой токен подошёл и до какого места совпадение дошло.
  • Сервер без настроенных токенов допускает один пустой токен "". В этом случае проверку пройдёт digest = base64url(SHA-256(nonce)). Саму процедуру хендшейка пропустить нельзя.
  • Верхняя граница читаемой сервером строки ответа — 256 байт.

3. Результат

  • Успех: сервер ничего не отправляет и сразу переключается на основной протокол — клиентский порт переходит к бинарному протоколу блокировок на основе кадров, Raft-порт — к RPC с префиксом длины. Первый запрос можно отправлять сразу.
  • Неудача: сервер отправляет E auth_failed и закрывает соединение. Если соединение обрывается во время хендшейка или строка некорректна, оно может закрыться молча, без фрейма ошибки.

Термины

  • Challenge-response — способ аутентификации, при котором вместо передачи самого секрета (токена) сервер отправляет одноразовую задачу (challenge), а секрет используется только для вычисления ответа на неё.
  • Nonce — случайное число, используемое один раз (number used once). Меняется при каждом подключении, поэтому повторное использование перехваченного ответа (replay-атака) не срабатывает.
  • Сравнение с константным временем (constant-time compare) — сравнение, всегда занимающее одинаковое время независимо от того, до какого места совпали данные. Защищает от атак по времени отклика (timing attack), способных выдать секрет.
  • base64url — вариант base64, использующий только алфавит, безопасный для URL (A–Z a–z 0–9 - _). Здесь используется без паддинга (=).