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). Это второй алгоритм, о котором договариваются стороны.

Конкретные алгоритмы для обмена ключами — это обычно вариации на тему алгоритма Диффи-Хеллмана. На английской википедии есть очень наглядная картинка (приведена ниже), где в роли ключей выступают цвета. Сначала стороны договариваются о некотором открытом ключе (обычно клиент его генерирует и отправляет серверу по незащищённому соединению, на картинке общим ключом является жёлтый цвет). Затем каждая сторона создаёт свой закрытый ключ (цвет заката и морской волны в моей интерпретации

© Habrahabr.ru