Перейти к содержимому
New

DeepSeek V4.1 Flash free for 7 days: 10M tokens a day after a top-up of $10 or more. Until Nov 30.

How it works

Ключи SSH: как они работают и как пользоваться ими безопасно

Как работают ключи хоста и пользователя в SSH, почему по умолчанию стоит брать Ed25519 с парольной фразой и как настроить и защитить вход по ключу на своей лабораторной VM.

Начальный9 мин чтенияАвтор: NotHoly

Что защищает SSH

SSH (Secure Shell) — протокол, через который большинство людей заходит на серверы Linux, лабораторные виртуальные машины и Git-хостинги. Он открывает shell по зашифрованному каналу, и по тому же каналу можно копировать файлы или пробрасывать порты. Задач у него три. Он шифрует трафик, чтобы никто на сетевом пути не мог его прочитать. Он доказывает серверу, кто вы. Он доказывает вам, кто этот сервер.

Вторую задачу ключи решают без отправки пароля по сети. Пароль можно подобрать или выманить фишингом. Пара ключей работает иначе. Сервер хранит только публичную половину. При входе клиент подписывает запрос (challenge) приватной половиной, а сервер проверяет подпись. Приватный ключ никогда не покидает вашу машину.

В некоторых случаях SSH вас не защищает, и знать их нужно не меньше, чем сам протокол. Если скомпрометирован ваш компьютер, вредоносное ПО, запущенное от вашего пользователя, может прочитать файл приватного ключа или попросить агент что-нибудь подписать. Если приватный ключ украден, а парольная фраза слабая, злоумышленник может подбирать её офлайн. Если вы принимаете личность сервера без проверки, вы, возможно, разговариваете вовсе не с сервером.

Два вида ключей

В SSH есть два разных вида ключей, и их часто путают.

Ключи хоста идентифицируют сервер. У каждого SSH-сервера их один или несколько, обычно они лежат в /etc/ssh/ssh_host_*_key. Приватная часть остаётся на сервере. Публичная предъявляется каждому подключающемуся клиенту. Увидев её впервые, клиент сохраняет её в known_hosts. При последующих подключениях изменившийся ключ хоста вызывает предупреждение.

Пользовательские ключи идентифицируют вас. Пару вы создаёте на своей машине. Приватный ключ остаётся у вас. Публичный отправляется на сервер, в ~/.ssh/authorized_keys нужного аккаунта.

У этого различия есть практические последствия. Скопировав приватный ключ на сервер, вы даёте этому серверу и всем, кто может его прочитать, всё необходимое, чтобы действовать от вашего имени везде, где ключу доверяют. Игнорируя предупреждение о ключе хоста, вы рискуете отправить пароль или команды самозванцу.

Почему Ed25519 с парольной фразой

OpenSSH поддерживает несколько типов ключей. RSA всё ещё работает, но новые ключи RSA должны быть длиной не меньше 3072 бит, и строки публичных ключей получаются длинными. Ключи Ed25519 короткие, быстро проверяются и стандартизованы для SSH в RFC 8709. Начиная с OpenSSH 9.5, Ed25519 используется в ssh-keygen по умолчанию. Для лабораторного ключа Ed25519 подходит по умолчанию, если только нужная вам система не принимает лишь более старый тип.

Парольная фраза шифрует файл приватного ключа на диске. Без неё файлом сможет воспользоваться любой, кто его скопировал. С ней понадобятся и файл, и фраза. Это защищает от самых частых случайностей: резервная копия ушла не туда, ключ остался в общей папке, файл по ошибке синхронизировался в облачное хранилище. Когда ключ загружен в агент и от вашего имени работает вредоносное ПО, парольная фраза уже не поможет. Делайте её длинной, храните в менеджере паролей и держите резервную копию файла ключа в надёжном месте.

Как проходит подключение

Транспортный уровень описан в RFC 4253. В общих чертах подключение проходит такие шаги:

  1. Клиент открывает TCP-соединение с сервером, обычно на порт 22.
  2. Обе стороны отправляют поддерживаемые алгоритмы и договариваются об обмене ключами. Обмен даёт общие секреты, и с этого момента весь трафик шифруется.
  3. Сервер отправляет свой ключ хоста и подпись данных обмена. Клиент сверяет ключ хоста с known_hosts. Если хост новый, клиент показывает отпечаток и просит подтвердить его.
  4. Вы проходите аутентификацию. Клиент предлагает публичный ключ. Если сервер находит его в authorized_keys, он отправляет запрос. Клиент подписывает запрос приватным ключом, а сервер проверяет подпись.

Обратите внимание, откуда берётся доверие. Шаг 3 касается сервера. Шаг 4 касается вас. Если на шаге 3 пропустить проверку отпечатка, остаток рукопожатия будет работать на того, кто ответил на соединение.

Отпечатки

Отпечаток — это короткий хеш публичного ключа. OpenSSH по умолчанию показывает отпечатки SHA256. Два человека могут сравнить отпечаток и убедиться, что у них один и тот же публичный ключ, не зачитывая ключ целиком.

Команды ниже запускались на машине с Windows 11 и OpenSSH 9.9p2 (ssh -V), в Git Bash. Ключ был одноразовой копией, созданной для этого наблюдения, с пустой парольной фразой, чтобы вывод можно было здесь показать. У вашего настоящего ключа будет другой отпечаток.

bash
ssh-keygen -t ed25519 -C 'lab-key' -f ./lab_ed25519 -N ''
ssh-keygen -lf ./lab_ed25519.pub

Наблюдаемый вывод:

text
256 SHA256:2BAyZTrHADdiG1FNwfCwb/fC5vSVZPwfGnZjRaaExc4 lab-key (ED25519)

ssh-keygen -lvf печатает тот же отпечаток с картинкой random-art. На картинке проще заметить изменения, но сравнивать нужно текст отпечатка.

Практика

Понадобится виртуальная машина или облачный инстанс, которым вы владеете и который контролируете, с запущенным сервером OpenSSH и аккаунтом, которому доступен sudo. Подойдёт локальная VM в VirtualBox или Hyper-V. Подойдёт и небольшой облачный инстанс, за который вы платите и который можете удалить. Не выполняйте эти шаги на чужой машине.

Шаг 1: создайте ключ

bash
ssh-keygen -t ed25519 -C 'lab-key' -f ~/.ssh/lab_ed25519

Когда появится запрос, введите длинную парольную фразу. Команда создаёт два файла: lab_ed25519 (приватный) и lab_ed25519.pub (публичный). Покидать вашу машину должен только файл .pub.

Шаг 2: проверьте отпечаток

bash
ssh-keygen -lf ~/.ssh/lab_ed25519.pub

Запишите этот отпечаток или хотя бы первые несколько символов. Позже вы сравните его ещё раз.

Шаг 3: закройте доступ к файлу приватного ключа

bash
chmod 600 ~/.ssh/lab_ed25519

В Linux и macOS ssh отказывается работать с приватным ключом, который могут читать другие пользователи. В Windows OpenSSH проверяет ACL файла, биты режима Unix ему безразличны. На этой машине с Windows chmod 600 отработал без ошибки, но ls -l после этого всё ещё показывал -rw-r--r--. Не рассчитывайте, что биты режима там изменились. Если ssh в Windows жалуется на права, проверьте файл через icacls и уберите доступ для других аккаунтов.

Шаг 4: установите публичный ключ на VM

bash
ssh-copy-id -i ~/.ssh/lab_ed25519.pub youruser@your-lab-vm

Это единственный раз, когда вы намеренно вводите пароль аккаунта. Команда дописывает публичный ключ в ~/.ssh/authorized_keys на VM.

При первом подключении к VM вы также увидите отпечаток ключа хоста. Сравните его с настоящим. На VM выполните:

bash
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

Если отпечатки совпадают, введите yes. Если нет, остановитесь и выясните причину, прежде чем продолжать. Несовпадение может означать, что вы переустановили VM или что между вами и ней кто-то сидит.

Этот шаг здесь не выполнялся, потому что VM на этой машине не было. По той же причине команды на шагах с 4 по 6 показаны без вывода. Каждую из них можно проверить на своей VM.

Шаг 5: войдите по ключу

bash
ssh -i ~/.ssh/lab_ed25519 youruser@your-lab-vm

Клиент спросит парольную фразу ключа, пароль аккаунта ему не нужен. Если вы получили shell, ключ работает. Оставьте эту сессию открытой для следующего шага.

Шаг 6: отключите вход по паролю

На VM:

bash
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sshd -t && sudo systemctl restart ssh

Строка sed заменяет строку PasswordAuthentication независимо от того, закомментирована она или нет. sshd -t проверяет синтаксис конфигурации и прерывает цепочку при ошибке. systemctl restart ssh применяет изменение. В Fedora и других системах семейства RHEL служба называется sshd, используйте это имя.

Здесь часто случаются три проблемы:

  • Строка переопределена. Во многих системах Debian и Ubuntu /etc/ssh/sshd_config включает файлы из /etc/ssh/sshd_config.d/, и действует первое прочитанное значение ключевого слова. Проверьте значение, которое sshd реально использует:
bash
sudo sshd -T | grep -i '^passwordauthentication'

После изменения вывод должен быть passwordauthentication no. Если там всё ещё yes, найдите файл, который это задаёт, и исправьте его.

  • Строки нет. sed редактирует только существующую строку. Если строки PasswordAuthentication нет, действует значение по умолчанию, и по man-странице sshd_config(5) это yes. Добавьте строку сами:
bash
echo 'PasswordAuthentication no' | sudo tee -a /etc/ssh/sshd_config
  • Вы заблокировали себе доступ. Прежде чем закрывать сессию из шага 5, откройте второй терминал и войдите по ключу. Закрывайте первый терминал только после того, как заработал второй. Если доступ потерян, почините конфигурацию через консоль VM в гипервизоре или облачной панели.

Затем проверьте со своей машины, что вход по паролю отклоняется:

bash
ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password youruser@your-lab-vm

Подключение должно завершиться сообщением об отказе в доступе. Выполните эту проверку сами на своей VM. На этой машине она не выполнялась.

Агент и known_hosts

ssh-agent

Вводить парольную фразу при каждом подключении утомительно. ssh-agent держит расшифрованный ключ в памяти на время сессии, так что фразу вы вводите один раз.

bash
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/lab_ed25519
ssh-add -l

ssh-add -l показывает отпечатки, которые хранит агент. На этой машине с Windows ssh-add -l запустился без работающего агента, напечатал Could not open a connection to your authentication agent. и завершился с кодом 2. В Windows для этого есть служба OpenSSH Authentication Agent. Запустите её из консоли Services или из PowerShell с правами администратора. Это изменение вашей системы, поэтому делайте его сами и только если агент вам нужен.

Агент удобен, но он ещё и цель. Любой, кто может обратиться к сокету агента, пока вы в системе, способен попросить его что-нибудь подписать. Поэтому не используйте проброс агента (ssh -A) на хосты, которым не доверяете полностью. Пользователь root на удалённом хосте может воспользоваться вашим проброшенным агентом. Если нужно попасть на закрытый хост через бастион, используйте jump-хост:

bash
ssh -J youruser@bastion youruser@private-vm

known_hosts

Клиент хранит ключи хостов в ~/.ssh/known_hosts, по одной строке на хост и тип ключа. Если задать HashKnownHosts yes, строки хешируются, и тот, кто прочитает файл, не увидит имён хостов.

Чтобы найти хост:

bash
ssh-keygen -F your-lab-vm

Чтобы удалить запись после пересборки VM и получения нового ключа хоста:

bash
ssh-keygen -R your-lab-vm

Делайте это, только когда знаете, почему ключ изменился. Изменившийся ключ хоста — это предупреждение, и отмахиваться от него нельзя. Если удалить старую запись без проверки нового отпечатка, вы приучите себя игнорировать следующее предупреждение, а оно может оказаться настоящим.

Главное

  • Никому не передавайте приватный ключ. На серверы, Git-хостинги и другим людям уходит только файл .pub.
  • Защищайте приватный ключ парольной фразой и держите резервную копию файла.
  • Проверяйте отпечаток хоста при первом подключении и разбирайтесь с любым его изменением в дальнейшем.

Частые ошибки

  • Вставлять приватный ключ в чат, issue, тикет или на скриншот. Относитесь к нему как к паролю, который нельзя сбросить. Если он утёк, создайте новый ключ, установите его и удалите старый публичный ключ из authorized_keys.
  • Устанавливать на сервер приватный ключ вместо публичного. Серверу нужна только строка .pub в authorized_keys.
  • Права на сервере. В Linux у ~/.ssh должен быть режим 700, а у authorized_keys режим 600. При более свободных правах sshd может проигнорировать ключ. Если вход по ключу не работает, смотрите журналы sshd.
  • Отключать пароли до того, как заработал вход по ключу. Это самая частая причина блокировки. Соблюдайте порядок из шага 6.
  • Один ключ на всё. Если один ключ используется на лабораторных VM, Git-хостингах и в продакшене, одна утечка открывает всё. Заведите отдельные ключи по назначению, например lab_ed25519 для лаборатории и другой ключ для GitHub.
  • Принимать неизвестный ключ хоста без проверки. Первое подключение — самый вероятный момент для появления самозванца. Сравните отпечаток, прежде чем вводить yes.
  • Потерять парольную фразу. Восстановить её нельзя. Храните её в менеджере паролей.
  • Дублирующиеся строки в authorized_keys. Двойной запуск ssh-copy-id безвреден, но если вручную дописывать ключ несколько раз, файл становится сложнее проверять. Удаляйте ключи, которыми больше не пользуетесь.

Что делать дальше

Когда лаборатория заработает, несколько шагов сделают повседневную работу безопаснее и аккуратнее.

  • Настройки для отдельных хостов в ~/.ssh/config. Задайте каждому хосту алиас, укажите IdentityFile и добавьте IdentitiesOnly yes, чтобы клиент предлагал только выбранный ключ. Тогда он не будет пробовать на сервере все ключи из агента.
  • Аппаратные ключи. OpenSSH может создавать ключи, хранящиеся на аппаратном ключе безопасности, командой ssh-keygen -t ed25519-sk. Приватную часть тогда нельзя скопировать с устройства. Прежде чем на это полагаться, проверьте версию OpenSSH и поддержку на своём ключе.
  • Сертификаты SSH. Организации с большим числом серверов часто используют центр сертификации, чтобы не раздавать ключи на каждый хост. Концепцию стоит изучить, даже если пока она вам не нужна.
  • Первоисточники. Man-страницы ssh-keygen и sshd_config описывают все опции, которые вам встретятся. RFC 4253 объясняет транспортный уровень, а RFC 8709 посвящён Ed25519 в SSH.

Если режимы файлов и владельцы для вас пока в новинку, сначала прочитайте предыдущую статью о файлах и правах в Linux. Следующая статья рассказывает об изолированных сетях Docker для лабораторий, с их помощью трафик лаборатории можно держать подальше от повседневной сети.

Источники

Источники

  1. OpenBSD manual: ssh-keygen(1)
  2. OpenBSD manual: sshd_config(5)
  3. OpenSSH 9.5 release notes
  4. RFC 4253: The Secure Shell (SSH) Transport Layer Protocol
  5. RFC 8709: Ed25519 and Ed448 Public Key Algorithms for SSH

Ещё по теме: Linux и инструменты разработчика

Linux и инструменты разработчика

Основы Bash для работы в безопасности

Пайпы, перенаправление, переменные, циклы, коды завершения и set -euo pipefail, а затем подсчёт неудачных входов и хеширование папки на этой основе.

Начальный11 мин чтения

Linux и инструменты разработчика

Права в Linux: пользователи, группы, chmod и umask

Владельцы и группы в Linux, биты rwx, chmod, umask и setuid, а также лабораторная, где доступ проверяется от имени второго пользователя и ищутся опасные режимы файлов.

Начальный11 мин чтения