SSH в деталях или разгребаем кучи ключей
Решил я недавно разобраться в подробностях работы SSH. Использовал его для удалённого запуска команд давно, но, будучи не слишком опытным в системном администрировании, очень размыто представлял, зачем админы просят им отправить какой-то ключ, что с этим ключом происходит при подключении, зачем при запуске ssh
периодически орёт на меня какими-то предупреждениями, и прочие прелести. К своему удивлению, не смог найти ресурсов с описанием протокола, после которых у меня не осталось бы только больше вопросов. Поэтому, после прочтения спецификаций и разборок с OpenSSH, хочу разложить всё по полочкам здесь.
Статья рассчитана на поверхностно знакомых с SSH, либо совсем не знакомых. Попытаюсь описать основные аспекты безопасности протокола: какие ключи и алгоритмы используются, в какой момент и зачем. Статья призвана дать базу в работе с самим протоколом SSH и OpenSSH (одной из программ, реализующих протокол), зная которую можно разбираться в его более продвинутых возможностях.
Что нужно знать
Единственное требование: знать о симметричном и об ассиметричном шифровании. Что такое криптографический ключ, что такое открытый и закрытый ключи, зачем они нужны, что умеют, как работает шифрование и цифровая подпись — на эти и связанные вопросы здесь ответа нет. Кому надо, тот загуглит про (а)симметричное шифрование, об этом есть множество доступных ресурсов.
Терминология
Далее везде
Пользователь — системный пользователь, то есть который создаётся на линуксе через
adduser
или на винде в настройках.Клиент — программа, реализующая клиентскую часть протокола SSH: отправляющая запросы к SSH-серверу, пишущая вам в консоль гневные тирады из-за смены ключей, и прочее.
Сервер — соответственно программа, реализующая серверную часть SSH.
Стороны — клиент и сервер.
Вы — вы, то есть человек, использующий клиент.
Админ (истратор) — человек, ответственный за сервер. Возможно совпадает с «вами». Также это может быть некоторая автоматическая система, например, если вы используете облачные сервисы. В этом случае взаимодействие с сервером происходит через панель управления облаком.
Что такое SSH?
SSH — это сетевой протокол для защищённого управления удалёнными устройствами по незащищённому сетевому соединению. Самый примечательный сценарий использования: удалённый вход в систему и выполнение команд.
Это вольный перевод первого абзаца статьи про SSH на английской википедии. Думаю, каждый, кто открывал хоть одну ссылку про SSH в гугле, знает об этом.
Чуть менее тривиально (написано во втором абзаце) то, что на самом деле SSH состоит из трёх более или менее независимых протоколов: протокол транспортного уровня, протокол аутентификации, и протокол соединения. Возможно, называть их прямо отдельными протоколами — слишком громкие слова, и можно было бы считать, что это просто три стадии налаживания соединения, но так их обзывают в спецификации, а чем я хуже. Кстати, спецификация у каждого из них своя: RFC 4253, RFC 4252 и RFC 4254 соответственно, за подробностями можно и нужно обращаться к этим ссылкам.
Обычно на практике разделение на три протокола не часто упоминается, но чтобы понять, когда и зачем какой ключ используется, это довольно важно. Поэтому далее каждый из этих протоколов разберём отдельно.
Акт 1. Протокол транспортного уровня
Сцена 1. Установка защищённого соединения
Первый этап в работе SSH — наладить защищённый канал связи. Внимание, спойлер: позднее, например если используется аутентификация по паролю, мы будем отправлять по сети пароль голым текстом (а как иначе сервер сможет сравнить пароль с хешем, который хранит у себя?), либо не пароль так ещё кучу всякой конфиденциальной информации. Поэтому нужно осуществить некоторые танцы с бубном, чтобы кто попало эти данные не прочитал. Это, я считаю, самый сложный из трёх протоколов, так как содержит множество хитрых фикусов и рассуждений о безопасности.
Итак, первое, что делают стороны (клиент и сервер) после того, как TCP соединение установлено (а SSH обычно работает поверх TCP) — отправляют друг другу версию своего ПО и самого протокола SSH, которую хотят использовать (на момент написания статьи актуальна версия 2.0). Далее они обмениваются списками поддерживаемых алгоритмов шифрования (и не только).
Разработчики SSH предусмотрели, что, с одной стороны, алгоритмы шифрования, как и всё в жизни, со временем выходят из моды (точнее в них находят уязвимости), а с другой, не все разработчики клиентов/серверов SSH способны поддерживать все существующие алгоритмы. Поэтому и нужен шаг, на котором стороны договариваются об используемых алгоритмах. Сколько же алгоритмов и для каких конкретных целей нам понадобится? Не один и даже не два.
В SSH слова «соединение защищено» значат, что все отправляемые сообщения подвергаются симметричному шифрованию. То есть и у сервера, и у клиента есть (обычно) одинаковый ключ симметричного шифрования, который может и зашифровать, и расшифровать любое сообщение. Симметричные шифры бывают разные, поэтому первый алгоритм, о котором договариваются стороны: алгоритм симметричного шифрования (encryption algorithm).
Уточнение 1
На самом деле стороны договариваются одновременно обо всех алгоритмах, а «первым» я его назвал для удобства. Кроме того, алгоритмов симметричного шифрования может быть выбрано два: для сообщений от сервера к клиенту один, а от клиента к серверу другой. Но спецификация рекомендует использовать один в обе стороны, и для простоты далее я буду считать, что он один.
Вопрос: как так сделать, чтобы клиент и сервер, изначально общаясь по незащищённому соединению, смогли договориться о ключе симметричного шифрования, и при этом никто кроме клиента и сервера не узнал этот ключ? Ответ: использовать хитроумный алгоритм обмена ключами (англ. key exchange algorithm, он же kex algorithm). Это второй алгоритм, о котором договариваются стороны.
Конкретные алгоритмы для обмена ключами — это обычно вариации на тему алгоритма Диффи-Хеллмана. На английской википедии есть очень наглядная картинка (приведена ниже), где в роли ключей выступают цвета. Сначала стороны договариваются о некотором открытом ключе (обычно клиент его генерирует и отправляет серверу по незащищённому соединению, на картинке общим ключом является жёлтый цвет). Затем каждая сторона создаёт свой закрытый ключ (цвет заката и морской волны в моей интерпретации