58

Самый недооцененный механизм безопасности SSH или почему known_hosts - это не кэш⁠⁠

Самый недооцененный механизм безопасности SSH или почему known_hosts - это не кэш

Каждый, кто хоть раз подключался к новому серверу по SSH, знаком с этим интерактивным ритуалом:

The authenticity of host example. com can't be established. ED25519 key fingerprint is SHA256:... Are you sure you want to continue connecting (yes/no)?

И почти все бездумно вводят одинаковый ответ:

yes

Эта модель называется TOFU или Trust On First Use — доверие при первом использовании.

Через несколько месяцев или даже лет по тому же адресу может прилететь уже совсем другое сообщение:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

И тут сценарий в большинстве случаев тоже простой и бестолковый:

ssh-keygen -R example. com
ssh example. com
yes

Вот и все, можно снова не беспокоиться, проблема решена.

Или нет?



До недавнего времени я относился к файлу known_hosts примерно так же. Ну какой-то там служебный кэш SSH. Если что-то пошло не так - удалил запись, подключился заново, живем дальше.

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

known_hosts - это вообще не кэш.

Это база доверенных идентичностей серверов.

Когда SSH спрашивает:

Вы уверены, что хотите доверять этому серверу?


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

Получается интересная ситуация.

Один из важнейших механизмов безопасности SSH хранится в обычном текстовом файле.

При этом вокруг него почти нет инструментов.

Где заканчивается OpenSSH

Давайте посмотрим, что OpenSSH умеет делать со своей собственной базой доверия.

  • автоматически добавить новую запись при первом подключении

  • удалить запись (ssh-keygen -R)

  • найти запись (ssh-keygen -F)

  • захэшировать файл (ssh-keygen -H)

И, по большому счёту, на этом его полномочия всё.

Если вы работаете с десятками или сотнями серверов, через несколько лет в known_hosts накапливаются сотни записей.

И неожиданно оказывается, что OpenSSH почти не помогает ответить на самые обычные вопросы.

  • Какие серверы уже давно не существуют?

  • Какие ключи изменились?

  • Есть ли дубликаты?

  • Какие записи используют устаревшие алгоритмы?

  • Кому я доверяю прямо сейчас?

И начинается дурдом с grep, awk, sed.

А мой коллега американец достает припасенную пачкау shell-скриптов и с умным видом делает вид, что (его цитата) shoveling shit)

Меня это искренне удивило.

SSH существует уже больше тридцати лет. Это один из самых распространённых сетевых протоколов в мире.

Но его модель доверия практически заканчивается сразу после первого yes.

Создать доверие - пожалуйста. Поддерживать его - уже без меня.

А как вообще SSH получает host key?

Стало интересно, как именно клиент получает публичный ключ сервера.

Мне всегда казалось, что для этого нужно установить полноценную SSH-сессию, договориться о шифровании, пройти аутентификацию и только потом получить нужную информацию.

Оказалось, все гораздо прозаичнее.

Во время подключения происходит примерно такая последовательность:

Сначала стороны просто обмениваются строками версии вроде

SSH-2.0-OpenSSH_10.0

Затем договариваются о поддерживаемых алгоритмах.

И наконец клиент отправляет `SSH_MSG_KEX_ECDH_INIT`.

Самое интересное происходит в ответном сообщении.

`SSH_MSG_KEX_ECDH_REPLY` содержит:

  • host key сервера

  • временный публичный ключ сервера

  • криптографическую подпись

Именно здесь клиент вычисляет фингерпринт, сравнивает его с known_hosts и принимает решение - продолжать соединение или нет.

Что меня удивило больше всего - все это происходит ещё до аутентификации пользователя.

Никаких паролей. Никаких приватных ключей. Никакого shell. Никакой открытой SSH-сессии.

И это абсолютно логично.

Host key существует именно для того, чтобы клиент убедился, с кем он разговаривает, прежде чем отправлять хоть какие-либо секреты.

Получается, что если цель - просто проверить идентичность сервера, то после получения `SSH_MSG_KEX_ECDH_REPLY` соединение можно сразу закрывать.

Все необходимое уже получено.

От исследования к инструменту

Когда я это понял, стало очевидно еще кое-что.

Чтобы проверить host key сервера, как я уже упомянул выше, не нужен полноценный SSH-клиент. Ни шелл, ни аут. Не нужна большая часть SSH вообще.

Нужен лишь небольшой кусок протокола.

Именно из этого наблюдения постепенно вырос небольшой CLI проект, который я назвал khm (known hosts manager).

Изначально он вообще писался для себя.

Мне хотелось иметь возможность быстро ответить на вопросы, на которые OpenSSH почему-то не отвечает.

  • изменились ли ключи у уже известных серверов

  • есть ли мусор и дубликаты в known_hosts

  • чем отличаются два файла после миграции инфраструктуры или ротации ключей

  • что вообще я имею на сегодняшний день

Постепенно стало понятно, что проблема гораздо шире, чем казалось сначала.

На удивление много людей воспринимают known_hosts как временный файл, который можно удалить при первой ошибке.

Хотя на самом деле именно он определяет, каким серверам ваш компьютер доверяет прямо сейчас.

Например, именно такого вывода мне всегда не хватало в OpenSSH:

$ khm verify --all

OK  github. com

OK  gitlab. com

CHANGED  old. example. com

UNREACHABLE  backup. example. com

4 hosts • 2 OK • 1 changed • 1 unreachable

Не список ключей. Не тупой, подверженный человеческому фактору, вывод grep, а простой ответ на простой вопрос:

Все ли ещё соответствует тому, чему я доверял раньше?

Вместо заключения

Пока я работал над этим проектом, самым неожиданным открытием оказался вовсе не SSH-протокол.

Меня удивило отношение к known_hosts. Мое в том числе.

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

Но если посмотреть внимательнее, это единственная локальная база доверенных идентичностей серверов, которой пользуется OpenSSH.

И как только начинаешь воспринимать ее именно так, становится удивительно, насколько мало вокруг нее существует инструментов.

Именно поэтому появился khm.

Не как ещё один SSH-клиент. И не как замена OpenSSH.

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

Исходный код проекта, бинарные сборки и документация доступны в репо:

Смотреть

Устанавливайте, чекайте, ищите изъяны, ставьте звезды, открывайте пулл-реквесты, наводите порядок на своих хостах. Увидимся!

Лига Сисадминов

2.8K поста19.2K подписчиков

Правила сообщества

Мы здесь рады любым постам связанным с рабочими буднями специалистов нашей сферы деятельности.

10
Автор поста оценил этот комментарий

Проблема "Неуловимого Джо"

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества

Недвижимость и ремонт

Теги

Популярные авторы

Сообщества