Все, кто использует SSH знают, что при первом подключении к серверу, появляется сообщение с подтверждением отпечатка ключа. Дальше ключ сохраняется на стороне клиента, и больше это сообщение не показывается до момента пока сохраненный ключ не изменится. Но в чем практический смысл этой процедуры?

В реальной жизни почти никто не проверяет отпечаток SSH-ключа сервера не особенно задумываясь о возможности MiTM-атаках. С появлением DNS-записи SSHFP отпечаток ключа сервера можно хранить в DNS и проверять его подлинность с помощью DNSSEC. При этом не нужно даже подтверждать ключ при первом подключении. В статье разберем, как настроить запись SSHFP для своего SSH-сервера.

Сервер для тестов


Для начала нам потребуется сервер.В панели RuVDS реквизиты для SSH-доступа находятся сразу на карточке сервера. Сохраняем IP-адрес и пароль для подключения.



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

Для настройки SSHFP на IP-адрес сервера должен быть направлен домен, именно для этого домена мы будем настраивать DNS-записи.

Как работают ключи в SSH


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

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

Файлы с ключами находятся здесь:

$ ls -la /etc/ssh/ssh_host_*_key*

/etc/ssh/ssh_host_dsa_key
/etc/ssh/ssh_host_dsa_key.pub
/etc/ssh/ssh_host_ecdsa_key
/etc/ssh/ssh_host_ecdsa_key.pub
/etc/ssh/ssh_host_ed25519_key
/etc/ssh/ssh_host_ed25519_key.pub
/etc/ssh/ssh_host_rsa_key
/etc/ssh/ssh_host_rsa_key.pub

В этом списке есть сразу несколько ключей разного типа: dsa, rsa, ecdsa, ed25519. Это сделано для совместимости с разными SSH-клиентами. На этапе подключения клиент и сервер согласовывают, какой алгоритм ключа будет использоваться. Клиент может попросить сервер использовать другой алгоритм, если предложенный не поддерживается. Сервер посылает публичную часть своего ключа клиенту и пользователю предлагается проверить его отпечаток вручную.


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

Если это первое подключение, клиенту будет показано сообщение с требованием проверить отпечаток ключа вручную:

The authenticity of host 'example.com (123.45.67.89)' can't be established.
ECDSA key fingerprint is SHA256:7Q4nIqjuo/lSXWFkt9RaJYVHrT6LUAc6KWrdQ4/DDeA.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

На этом этапе мы все обычно нажимаем Yes не задумываясь и отпечаток ключа сохраняется в файл ~/.ssh/known_hosts. Теперь если ключ на сервере изменится, клиенту будет показано сообщение о возможной MiTM-атаке. Предполагается, что в самый первый раз клиент выполнил проверку ключа самостоятельно и убедился, в его подлинности.

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

Храним отпечаток ключа в DNS. Что такое записи SSHFP


Как узнать, что предложенный сервером SSH-ключ действительно настоящий и это не MiTM-атака? Ведь для того чтобы зайти на сервер и проверить ключ нужно сперва ввести пароль. Но тогда атакующий сможет моментально взломать сервер и подменить все данные на нем, да так, что мы и не заметим подвоха. Поэтому нужен способ проверить подлинность ключа еще ДО реального подключения.

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


SSHFP позволяет проверить подлинность ключа сервера до подключения через DNS

SSHFP — тип записей DNS для хранения SSH-ключей. Отпечаток SSH-ключа помещается в DNS-сервер подобно TXT записи и подписывается ключом DNSSEC. То есть при первом подключении к серверу с использованием имени хоста, клиент сможет заранее узнать отпечаток ключа сервера через DNS, и если он совпадает с предложенным сервером, то подключаться без предупреждения.

Настройка DNSSEC


Для использования SSHFP потребуется доменное имя с настроенным DNSSEC. Есть множество публичных DNS-сервисов, которые предлагают панель управления DNS сразу с функцией DNSSEC. Самый популярный такой сервис — CloudFlare. Рассмотрим настройку на его примере. Для следующий действий домен должен быть делегирован NS-сервера Cloudflare.

?Шаг 1 — сгенерировать ключ


Заходим в панель DNS --> Enable DNSSEC

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

?Шаг 2 — добавление публичных ключей у регистратора


Далее, нужно создать DS-записи, содержащие публичный ключ, у регистратора домена.
В зависимости от вашего регистратора, интерфейс добавления ключей DNSSEC может выглядеть по-разному. Важно только не перепутать значения, так как они могут называться по-разному и отличаться от названий показанных в CloudFlare.

На примере ниже показано как соотносятся значения, показанные в панели CloudFlare со значениями в панели управления доменом у регистратора Uniregistry.



?Шаг 3 — проверка добавленных DS-записей


После добавления DS-записей на стороне регистратора можно проверить корректность настроек. На стороне CloudFlare подписание DNS-записей будет активировано, только когда будет пройдена проверка корректности добавления DS-записей на стороне регистратора.


Ожидание добавления DS-записей

Через пару минут или часов, если записи были добавлены корректно, вы увидите такое сообщение. Это значит, что DNS-ответы теперь подписываются с помощью DNSSEC.



?Шаг 4 — проверка работы DNSSEC


Теперь можно проверить работу DNSSEC на нашем домене с помощью онлайн-сервисов вроде dnssec-analyzer.verisignlabs.com. Все галочки должны быть зелеными.


Результат проверки DNSSEC

Добавление записей SSHFP


Сгенерируем SSHFP-записи на сервере. В нашем примере мы администрируем сервер с адресом myserver.com. Для этого доменного имени мы ранее настроили DNSSEC.

На сервере выполняем команду:

# Сгенерировать записи SSHFP из существующих SSH-ключей
sudo ssh-keygen -r myserver.com

myserver.com IN SSHFP 1 1 057ecce168ace29d5a0099e3b63df2850e4c8e20
myserver.com IN SSHFP 1 2 52cd6099a304b9b8f57f2cd914e96a1b7477eb2f88c98c602
myserver.com IN SSHFP 2 1 42d677482e4450ee515d3aac94d96302a99bd4ec
myserver.com IN SSHFP 2 2 edda5fa445dc0da570c772a6df0d4012037e1a102840d29c4
...

Будут сгенерированы отпечатки для всех ключей из папки /etc/ssh/. Вы можете выборочно сгенерировать отпечатки для конкретных ключей, указав путь к файлу.

Теперь все эти записи нужно добавить в панели DNS, в нашем случае Cloudflare.


Добавление записи SSHFP в панели Cloudflare

Так, нужно добавить все ключи, полученные на предыдущем шаге. Теперь можно проверить, что ключи добавлены:

dig SSHFP myserver.com

В ответе вы должны увидеть все добавленные ключи. На подписание новых записей может потребоваться время, поэтому ключи в ответе могут появиться не сразу. Обычно это не занимает дольше 10-15 минут.

Подключаемся к серверу


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

# Редактируем конфиг
vi ~/.ssh/config

VerifyHostKeyDNS yes

Теперь можно подключаться к серверу. Для чистоты эксперимента можно удалить строку с отпечатком ключа из ~/.ssh/known_hosts. Для наглядности можно добавить опцию -v

# Подключаемся к серверу
ssh -v root@myserver.com


# DNS настроен неправильно, записей SSHFP нет
debug1: kex: host key algorithm: ecdsa-sha2-nistp256
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
.....
DNS lookup error: data does not exist

# DNS настроен правильно, но системный резолвер
# не поддерживает валидацию DNSSEC
debug1: kex: host key algorithm: ecdsa-sha2-nistp256
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
....
debug1: found 8 insecure fingerprints in DNS
debug1: matching host key fingerprint found in DNS


# DNS настроен правильно, системный резолвер поддерживает DNSSEC
debug1: kex: host key algorithm: ecdsa-sha2-nistp256
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
....
debug1: found 8 secure fingerprints in DNS
debug1: matching host key fingerprint found in DNS
debug1: ssh_rsa_verify: signature correct

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

Важно помнить, что SSHFP будет работать только при подключении к серверу по доменному имени и не будет работать при подключении по IP или другому домену, на котором нет SSHFP-записей.