SSH
SSH
SSH (Secure Shell) — сетевой протокол прикладного уровня, который даёт зашифрованный двусторонний канал между двумя машинами поверх обычного TCP. Через этот канал можно выполнять команды, копировать файлы, прокидывать порты — и всё это так, чтобы посторонний посередине не смог ни прочитать, ни подменить трафик.
История
SSH придумал финн Тату Юлёнен (Tatu Ylönen) в 1995 году в Хельсинкском технологическом университете (Helsinki University of Technology, ныне Aalto University). Прямой повод был очень житейский: летом 1995 года в университетской сети случилась атака с перехватом паролей (sniffer-атака), которая утащила сотни логинов и паролей у пользователей telnet и rlogin — а они тогда передавали пароль открытым текстом, как обычное письмо.
До SSH мир выглядел так:
- Telnet (RFC 854, 1983) — текстовая консоль на удалённой машине, всё в открытом виде.
- rlogin / rsh / rcp из Berkeley (~1981) — «доверительные» команды между машинами, основанные на IP-адресах и файле
.rhosts. Сегодня бы это назвали «security by trust me bro». - FTP (1971!) — передача файлов, пароль тоже в открытом виде.
Юлёнен в июле 1995 выложил SSH-1 как условно-бесплатное ПО. Через полгода — десятки тысяч пользователей. В 1996 он основал компанию SSH Communications Security и переключился на коммерческую версию.
Дальше — два больших шага:
- 1996 — SSH-2. Полностью переделанная версия с лучшей криптографией: Diffie-Hellman вместо старого RSA-only обмена ключами, отдельная аутентификация пользователя и хоста, мультиплексирование каналов. Старый протокол SSH-1 сегодня небезопасен (уязвимости в CRC32, в обмене ключами), и большинство серверов его выключили лет десять как.
- 1999 — OpenSSH. Когда коммерческие условия SSH-1 стали жёстче, команда OpenBSD во главе с Тео де Раадтом (Theo de Raadt) сделала свободный форк из последней свободной версии OSSH. Сегодня OpenSSH — это де-факто стандарт: он стоит на macOS, на всех основных Linux-дистрибутивах, в Windows 10/11 (с 2018), на роутерах, на embedded-устройствах.
- 2006 — стандартизация в IETF. RFC 4250–4254 описывают SSH-2 как открытый стандарт.
Главная веха последних лет — переход с RSA-2048 и DSA на Ed25519 (это «эллиптическая криптография» — об этом ниже). Это умолчание в OpenSSH с 2014 года, ключ Ed25519 короче, быстрее и считается более стойким.
Что это такое
SSH — это не одна программа, а протокол (как HTTP — это протокол, а Chrome и curl — программы, которые его говорят). У него есть две стороны:
- SSH-клиент (то, что ты набираешь в терминале:
ssh user@server). - SSH-сервер (демон
sshdна удалённой машине, слушает порт 22 по умолчанию).
Что протокол даёт:
- Конфиденциальность — весь трафик шифруется симметричным ключом, согласованным на этапе handshake.
- Целостность — каждый пакет подписан MAC-кодом (Message Authentication Code), подмена байтов в пути ломает подпись.
- Аутентификацию сервера — клиент проверяет, что попал именно на тот сервер, который имел в виду (через
known_hosts). - Аутентификацию клиента — сервер проверяет, что подключающийся — это тот, за кого он себя выдаёт (пароль, ключ, Kerberos, hardware token).
И вот тут важное отличие: SSH — это не просто «защищённый telnet». Поверх одного SSH-соединения можно открыть несколько независимых каналов (channels):
- shell-канал — интерактивная консоль,
- exec-канал — выполнить одну команду и закрыть,
- direct-tcpip — пробросить порт (туннель),
- session с SFTP — копировать файлы,
- agent-forwarding — пробросить локальный ssh-agent на сервер,
- X11-forwarding — графика с сервера к тебе.
Это близкий родственник того, что в HTTP/2 называется «мультиплексированием»: одно соединение, много логических потоков.
SSH vs TLS. Часто путают. TLS (бывший SSL) — это «защитная плёнка» поверх любого приложения (HTTPS = HTTP + TLS); сертификат подтверждает доменное имя; модель доверия — иерархия Центров сертификации (CA). SSH — самостоятельный протокол; «сертификат» хоста — это просто его публичный ключ; модель доверия — TOFU, «trust on first use»: первый раз ты ему веришь, дальше клиент кричит, если ключ сменился. Поэтому SSH незаменим для серверов без публичных DNS-имён (домашние, временные, внутренние).
Аналогии из жизни
1. Курьер с опечатанной коробкой. Telnet — это открытка: всё, что написано, видит любой почтальон. SSH — это курьер, который везёт коробку в опломбированном ящике, и пломбу может срезать только адресат своим ключом. Адресат, в свою очередь, показывает курьеру свой паспорт (известное лицо).
Где ломается: у курьера один маршрут, у SSH — много каналов одновременно по тому же «маршруту». И SSH сам генерирует одноразовый ключ на каждый сеанс, а не использует один «универсальный замок» — это называется forward secrecy (если ключ потом утечёт, прошлые сеансы всё равно не расшифровать).
2. Защищённая телефонная линия в посольстве. Когда дипломаты звонят в столицу, у них стоит «крипто-телефон»: оба аппарата делают рукопожатие (обмен ключами), и дальше голос шифруется. Если кто-то «врежется» в провод — услышит только шум.
Где ломается: у дипломатов аппарат знает «свой» центр заранее. У SSH в первый коннект нет способа узнать, какой ключ у сервера «настоящий» — приходится спрашивать у пользователя «доверяешь?». Это слабое место — атака MITM возможна именно в первый раз. Поэтому в серьёзных конторах ключи хостов разносят заранее или подписывают через SSH CA (есть и такая опция, мало кто пользуется).
3. Замок с двумя ключами (асимметричная криптография). Представь почтовый ящик: каждый может бросить туда письмо (публичный ключ), но открыть и прочитать может только владелец (приватный ключ). При аутентификации по SSH-ключу сервер бросает в ящик «загадку», и только владелец приватного ключа может её решить.
Где ломается: настоящий почтовый ящик нельзя «подделать», а файл id_ed25519 можно скопировать. Поэтому ключ обычно ещё и парольной фразой защищают, и/или держат в хардварном токене (YubiKey, Secure Enclave на Mac).
Как это работает
Соединение SSH идёт в три фазы. Цифры приблизительные — на современном железе и проводе всё это занимает 50–150 мс.
Фаза 1: транспортный слой (transport layer)
Клиент → TCP SYN → Сервер
← SYN-ACK ←
→ ACK → // обычный TCP-handshake
Клиент → "SSH-2.0-OpenSSH_9.6" → // строка-баннер, версия
← "SSH-2.0-OpenSSH_9.0" ← // сервер отвечает версией
Дальше — обмен ключами (KEX, Key Exchange):
- Стороны договариваются, какой алгоритм обмена использовать (сейчас почти всегда
curve25519-sha256— это Diffie-Hellman на эллиптической кривой). - Каждый генерирует разовую пару (эпhemeralр) — поэтому ключ сеанса нельзя восстановить, даже зная долгосрочные ключи. Это и есть forward secrecy.
- Сервер шлёт свой долгосрочный публичный ключ (host key) и подпись поверх обмена — клиент проверяет подпись и сравнивает ключ со своим
~/.ssh/known_hosts. - Если ключ незнаком — клиент задаёт знаменитый вопрос «The authenticity of host 'X' can't be established. Are you sure you want to continue connecting?». Это и есть TOFU-момент.
- Если ключ знаком, но изменился — клиент ругается REMOTE HOST IDENTIFICATION HAS CHANGED! и отказывается подключаться, пока ты не разберёшься (может быть атака, а может — переустановка сервера).
После KEX оба знают общий сеансовый ключ, и весь дальнейший трафик шифруется симметричным алгоритмом (обычно chacha20-poly1305 или aes256-gcm).
Фаза 2: аутентификация пользователя
Сервер спрашивает «кто ты?», клиент перебирает методы в порядке PreferredAuthentications:
- publickey — самый частый. Клиент шлёт «у меня есть ключ для пользователя
pavel», сервер ищет соответствие в~/pavel/.ssh/authorized_keys. Если найден — посылает challenge, клиент подписывает его приватным ключом, сервер проверяет подпись публичным. - password — клиент шлёт пароль (внутри уже шифрованного канала). Безопасно от прослушки, но уязвимо к брутфорсу и плохим паролям. На современных серверах обычно отключают для root и для прода.
- keyboard-interactive — обёртка для PAM, через неё работают TOTP/2FA.
- gssapi-with-mic — Kerberos. В корпоративных Linux-сетях.
Фаза 3: соединение (connection layer)
Аутентифицировались — теперь можно открывать каналы. Клиент шлёт channel-open с типом канала. Сервер либо принимает, либо отвергает.
Самое полезное:
- Local port forwarding (
ssh -L 8080:localhost:5432 server): открывает у тебя порт 8080, всё, что туда придёт, прилетит на сервер и пойдёт оттуда наlocalhost:5432. Удобно достучаться до базы данных, которая снаружи не открыта. - Remote port forwarding (
-R): обратное. На сервере открывается порт, всё что туда придёт — отправится к тебе. Так работают «reverse tunnels», когда нужно достучаться до машины за NAT. - Dynamic forwarding (
-D): поднимает SOCKS5-прокси у тебя локально, весь трафик пускается через SSH-сервер. Бедняцкий VPN.
Forced-command — про вчерашнее
В authorized_keys рядом с публичным ключом можно прописать ограничения:
command="/usr/local/bin/mcp-clients-server",no-pty,no-port-forwarding ssh-ed25519 AAAAC3...
Эта строка значит: «когда зайдут с этим ключом — не давай шелл, не давай туннели, запусти ровно вот эту команду и закрой соединение, когда она завершится». Это forced-command — стандартный приём для безопасной «выдачи» одного конкретного сервиса по SSH без полного доступа.
Именно так был устроен вчерашний MCP-сервер clients: SSH-ключ только запускает на сервере MCP-демон, а попытка ssh server 'whoami' возвращает пустой ответ — потому что вместо whoami всё равно запускается MCP. Защищает от ситуации «ключ утёк → у злоумышленника шелл».
Один протокол, две модели доверия
TLS говорит: «верь сертификату, который подписал известный тебе центр». SSH говорит: «верь ключу, который ты увидел в первый раз». Эти модели — не «лучше/хуже», а под разные задачи: TLS для миллиардов незнакомых клиентов (веб), SSH для пары десятков серверов, которые ты сам и поставил.
Где встречается в обычной жизни
- Git push/pull через
git@github.com:.... Когда ты пушишь в GitHub по ssh-протоколу — внутри ровно тот же SSH. GitHub слушает порт 22 наgithub.com, проверяет твой ключ из~/.ssh/id_ed25519противauthorized_keysсвоего пользователяgit, дальше запускаетgit-upload-pack/git-receive-pack. - Раздача файлов на VPS.
scp file.txt server:/var/www/илиrsync -avz ./built/ server:/var/www/blog/— оба идут поверх SSH. - Raspberry Pi и домашний сервер. Включил Pi в розетку, плюнул на HDMI-кабель — зашёл по
ssh pi@raspberrypi.local. - CI/CD пайплайн. В 90% случаев деплой на сервер из GitHub Actions/GitLab CI устроен так: «возьми приватный ключ из секретов →
ssh deployer@server→ выполни команды». Никакого специального «деплой-протокола» обычно нет. - Открытие туннеля до закрытого ресурса. Хочется поработать с базой, которая открыта только из локалки —
ssh -L 5432:db.internal:5432 jump.company.comи подключаешься кlocalhost:5432.
Где встречается в IT и бизнесе
- Управление парком серверов. Ansible, Salt, Chef — почти все «безагентные» системы конфигурации просто заходят по SSH и выполняют команды. Один master, тысячи targets, ноль установленных агентов.
- Bastion-хосты. Когда продовые серверы не торчат в интернет, в DMZ ставят одну машину, на которую можно зайти по SSH, а оттуда — внутрь.
ssh -J bastion.company.com prod-db.internal(опция-J— ProxyJump) делает это одной командой. - Безопасное получение метрик и логов. Reverse-tunnels позволяют машинам за NAT (например, оборудование заказчика) самим прозвонить «домой» и держать обратный канал. Так работают многие SaaS-системы для мониторинга embedded-устройств.
- Выдача доступа подрядчику. Дать только
forced-commandна конкретную утилиту — это «делегирование одной операции», не «дать шелл и доверять». - SFTP для обмена файлами между организациями. Банки до сих пор гоняют выписки через SFTP — потому что протокол простой, проверенный, легко аудируется.
Кто пользуется
- Все, у кого есть Linux- или BSD-серверы. AWS, GCP, Azure, DigitalOcean, Hetzner, Fornex — на любой свежесозданной виртуалке открыт порт 22.
- GitHub — десятки миллионов уникальных SSH-ключей в системе, точное число я не знаю, но порядок такой.
- OpenSSH — установлен на подавляющем большинстве серверов в мире. Конкретных цифр не приведу, но если хочется — ищи отчёты Shodan по баннеру
SSH-2.0-OpenSSH. - Embedded-устройства — роутеры на OpenWRT, NAS, IP-камеры, промышленные контроллеры. Часто это и есть тот самый «лёгкий» Dropbear SSH (не OpenSSH, но тот же протокол).
Альтернативы и конкуренты
- Mosh (Mobile Shell). Сделан в MIT в 2012. Работает поверх UDP, переживает потерю сети, переключение Wi-Fi → 3G, мгновенно реагирует на нажатия клавиш. Минус: только интерактивный shell, нет port forwarding и SFTP.
- WireGuard / VPN. Решает другую задачу — соединяет сети целиком, а не «выполни команду». Часто комбинируется: WireGuard поднимает туннель, SSH идёт уже внутри. Плюс: прозрачно для приложений. Минус: не заменяет SSH, дополняет.
- RDP / VNC. Графический удалённый доступ для Windows и Linux-десктопов. Совсем другая ниша — там не CLI, а картинка. Плюс: GUI. Минус: больше трафика, сложнее автоматизация.
- Tailscale SSH. Современная штука: SSH-аутентификация через identity provider (Google, Okta), без управления ключами вручную, с автоматическим audit-логом. Плюс: не нужно возиться с
authorized_keysдля команд из 50 человек. Минус: vendor lock-in, нужен интернет для verify. - AWS Systems Manager Session Manager. Заход на EC2-инстанс без SSH вообще — через IAM и агент. Плюс: не нужны открытые 22-е порты. Минус: только для AWS.
Когда НЕ стоит использовать
- Когда нужен только один файл туда-сюда. Поднимать SSH-сессию ради одного
scp— излишне. Если у тебя CI и куча мелких трансферов — лучше HTTP/S3, у него меньше overhead на handshake. - Для UDP-нагрузок и real-time видео. SSH идёт поверх TCP, имеет переотправки и rebuffering — никакого WebRTC через SSH-туннель сделать нормально не выйдет. Используй WireGuard.
- Если у тебя 10 000 пользователей и каждому нужно дать ssh-доступ. Управлять
authorized_keysруками в таком масштабе — ад. Либо SSH CA + центральная подпись ключей, либо системы вроде Teleport, либо вообще другие подходы (Session Manager, веб-консоли).
Связанные понятия
- Ed25519 — современный алгоритм цифровой подписи на эллиптической кривой Curve25519. Сегодняшний дефолт для SSH-ключей.
- Diffie-Hellman / ECDH — алгоритм обмена ключами; делает так, что общий ключ есть у обеих сторон, но никто посередине не может его подсмотреть.
- known_hosts — файл у клиента (
~/.ssh/known_hosts), куда записываются публичные ключи серверов, к которым ты уже ходил. - ssh-agent — фоновый процесс, который держит расшифрованный приватный ключ в памяти; не надо вводить парольную фразу при каждом коннекте.
- ProxyJump (
-J) — заход через промежуточный хост одной командой. - TOFU (Trust On First Use) — модель доверия SSH: первый раз верим, дальше — кричим при изменении.
- Forced-command — ограничение в
authorized_keys, заставляющее серверный SSH запускать заранее заданную команду вместо шелла.
Литература и источники
- «SSH, The Secure Shell: The Definitive Guide» — Daniel J. Barrett, Richard E. Silverman, Robert G. Byrnes. O'Reilly, 2-е издание 2005 года. Базовый справочник, чуть устарел в деталях, но фундамент описан хорошо. (en)
man ssh,man sshd_config,man ssh_config— на любой Linux-машине. Самый точный источник по конкретной версии OpenSSH.- RFC 4251–4254 (2006) — IETF-стандарты на архитектуру, транспортный слой, аутентификацию и соединение SSH-2. https://www.rfc-editor.org/rfc/rfc4251 (en)
- OpenSSH Release Notes — https://www.openssh.com/releasenotes.html — что меняется от версии к версии (отказ от устаревших алгоритмов, новые фичи).
- Wikipedia: Secure Shell — https://ru.wikipedia.org/wiki/SSH — обзорная статья с историей и ссылками.
- «Crypto 101» Лоуренса Ольстро — бесплатная книга, объясняет криптографию (Diffie-Hellman, MAC, эллиптические кривые), на которой стоит SSH. Искать в Google: «crypto 101 book pdf».
Где встретилось у меня
Вчера всплыло, когда проверял доступ к MCP-серверу clients: подключение к нему сделано через SSH с forced-command в authorized_keys — ключ запускает только сам MCP-демон, попытка любой другой команды (ssh server 'whoami') возвращает пустой ответ. Это та самая модель «делегировать одно действие, а не дать шелл», о которой говорится выше. Параллельно вспомнил про деплой блога на VPS — это тоже SSH, только без forced-command, и rsync built/ server:/var/www/ едет поверх него же.
Краткое резюме
- SSH — это шифрованный канал между двумя машинами поверх TCP, придуман в 1995 после реальной атаки с перехватом паролей. Открытый стандарт с 2006 (RFC 4251–4254), де-факто реализация — OpenSSH.
- Внутри одного SSH-соединения может идти несколько каналов: шелл, команды, перенаправление портов, SFTP, X11. Это не «защищённый telnet», а полноценная мультиплексная транспортная штука.
- Модель доверия — TOFU: первый раз веришь, дальше клиент кричит, если ключ хоста сменился. В этом главное отличие от TLS, где доверие выстроено через иерархию центров сертификации.
- Аутентификация по ключу (асимметричная криптография, сейчас обычно Ed25519) безопаснее пароля; парольная фраза +
ssh-agentснимают неудобство. - Forced-command в
authorized_keys— простой способ выдать по SSH доступ к одному конкретному сервису без полного шелла. Именно так устроен MCP-серверclientsи многие production-сервисы.