• Reading time ~ 10 min
  • 25.03.2024

SSH is a very powerful and flexible tool, but as practice shows, not everyone understands how it works and uses it correctly. The word Secure is part of the abbreviation SSH and is one of the key aspects of the protocol, but it is often not enough attention that is paid to security. In this article, I want to talk about a few common mistakes when working with SSH, as well as some that are often overlooked.


Существует несколько способов аутентификации пользователя:

  1. По паролю — стандартный механизм, но не самый надежный, я не буду заострять на нем внимание
  2. По ключу — самый надежный способ аутентификации, но это при условии, если правильно его использовать
  3. По IP адресу — режим совместимости. Привожу просто для справки, сомневаюсь, что кто-то будет использовать его в трезвом уме.

SSH asymmetric encryption

uses asymmetric encryption, which means that there are two keys: a public key and a private key. You can encrypt a message with a public key, and you can decrypt it with a private key. The private key is kept safe, while the public key is available to everyone. In addition, you can sign a message with a private key, and verify this signature with a public key.

As you can see from the diagram, after exchanging public keys, two nodes can securely communicate with each other over an insecure Internet.

In addition, the user can be authenticated using this key pair.

The user's public key must be added to the $HOME/.ssh/authorized_keys file
There can be multiple public keys in this file, all of which will work.


Protection against MITM attacks

A MITM attack is a type of attack in cryptography where an attacker secretly relays and, if necessary, alters communication between two parties who believe they are directly communicating with each other. It is a method of compromising a communication channel, in which an attacker, having connected to a channel between counterparties, interferes with the transmission protocol, deleting or distorting information.

One of the main innovations in the second version of the protocol is the built-in protection against MITM attacks.


The essence of protection is that each party must make sure that the other side is exactly the one who is expected, and not the attacker.

The StrictHostKeyChecking parameter and the known_hosts file are responsible for client-side MITM protection (i.e. to determine that you are connecting to your server ).

The public keys of the servers are stored in the following files:
$HOME/.ssh/known_hosts is a custom file,
/etc/ssh/ssh_known_hosts is a system file.

Each record in the known_hosts is a string that contains fields and uses a space as a separator:

  1. одно или несколько имен серверов или IP-адресов, разделенных запятыми
  2. тип ключа
  3. открытый ключ
  4. любые дополнительные комментарии

This is where the "identification" of the


server takes place The values can be as follows:

  • No — the connection will happen in any case, at most we will receive a warning that the connection is not secure. It can often be found in all sorts of automated scripts such as autotests and autodeploys, and this is where the main problem lies: if the script works normally, then the user (administrator) will not notice anything wrong, and infection/compromise will occur.
  • ask — ask on a new connection (default value) if the record is not yet in the known_hosts, and if you agree to the connection, a new record is added
  • yes — always scan, the safest option, which I strongly recommend using in automated systems. The connection is made only if there is an entry in the known_hosts

What does it give us:

  1. При первом подключении мы можем определить, не представился ли сервером злоумышленник
  2. Гарантию, что при последующих подключениях к серверу не произойдет подмены добропорядочного сервера злоумышленником

If everything is clear with the second point, then what about the first?

There are at least three options here:From my experience,

  1. Довериться случаю и согласиться на добавление нового ключа сервера
  2. Добавить флаг VisualHostKey=key, при этом клиент отобразит визуальное представление открытого ключа сервера, это представление уникально и облегчит запоминание ключа
  3. Флешка или открытые источники: это вариант для параноиков, однако, если компрометация системы может стоить десятков тысяч долларов, то это не лишне.

Использование визуализации открытого ключа

Если открытый ключ изменился

Сообщение о смене ключа может происходить по нескольким причинам:

  1. Изменился адрес сервера
  2. Изменился ключ сервера, например, при переустановке системы
  3. MITM атака

options 1 and 2 in total tend to be 100%, but point 3 cannot be excluded either.

Here's an example of a life hack that combines web and ssh approaches

curl https://server.com/ssh_fingerprint | tee -a ~/.ssh/known_hosts

At first glance, this is not very secure, however, this information can be obtained using

ssh-keyscan example.com

the However, in the first option, we additionally verify the authenticity of the received key using HTTPS.

In mission-critical CI/CD, using a

ssh-keyscan example.com >> ~/.ssh/known_hosts

combination during initialization in conjunction with


MITM attacks can be reliably protected against MITM attacks.

A lot of keys

You can often see the following pattern:


Each server on the client has its own key pairs, and the $HOME/.ssh/ is a complete mess.

On the one hand, this is more secure than using a single pair of client keys—if one key is compromised, only one system is compromised, not all the ones the user has been working with.

However, as practice shows, this is the last thing users are guided by, often they just follow all the instructions step by step:


Sometimes I have observed a situation when some keys were rubbed by others without any thought in the head.


As a reminder, if you're paranoid about security, it's enough to have one pair of keys, but you need to protect it properly.

By the way, about key


protection Think of your private SSH key as the key to the apartment where the money is kept. I've never seen a more careless attitude than with SSH keys. If users are even more or less aware of the seriousness of saving passwords, then only a few think about the fact that no one should be given access to the private key.

What can be highlighted:

  1. Хранить ключ надо в безопасном месте, в идеале это шифрованное хранилище
  2. Никому не предоставлять доступ к ключу, скомпрометированный ключ компрометирует все системы где разрешен доступ по нему
  3. Шифрование приватного ключа увеличивает безопасность, т.к. при потере ключа необходимо еще получить пароль для его дешифрации, либо потратить время и вычислительные мощности на его взлом.
  4. Не забывать про установку корректных прав на файл ключа 400, кстати, это распространенная ошибка, когда клиент отказывается использовать ключ

You can change or add a password using the command

ssh-keygen -p


But there is often a situation when you need to go to the server with your key and use it there. There are three solutions to this problem:

  1. Скопировать свой приватный ключ на сервер
  2. Сгенерировать новую пару ключей и прописать ее в качестве варианта доступа
  3. Использовать ssh-agent

In my experience, users choose the first two options in 90% of cases, and as we have already said: there is nothing more scary, than the compromise of the key.

I recommend using the third method


: the SSH-agent stores the private keys and uses them when necessary. A program (e.g. ssh), when it needs to use a private key, does not do it itself, but calls the ssh-agent, which, in turn, uses the data about the private keys known only to it. In this way, the private keys are not disclosed to anyone, not even to the programs. owned by the user.

The ssh-agent command creates a socket file named /tmp/ssh-XXXXXXXX/agent.ppid, through which the agent communicates. To all child processes, the agent uses environment variables SSH_AUTH_SOCK (where the socket file name is stored) and SSH_AGENT_PID (where the agent's process ID is stored) to provide information on how to contact the agent.

The agent provides information in a form that is easy for the shell to use.

SSH_AUTH_SOCK=/tmp/ssh-XXt4pHNr/agent.5087; export SSH_AUTH_SOCK;
echo Agent pid 5088;

When the -c switch is specified, the agent uses C Shell syntax. By default (and when the -s switch is explicitly specified), the Bourne Shell syntax is used. These variables must be set in the current shell, so it is common to combine the ssh-agent call with the eval command.

$ eval `ssh-agent`
Agent pid 5088

The agent runs until it is explicitly terminated by a signal or call

$ ssh-agent -k

The list of secret keys known to the agent can be viewed with the same ssh-add command with the -l command-line switch.

$ ssh-add -l
1024 46:88:64:82:a7:f9:aa:ea:3b:21:9e:aa:75:be:35:80 /home/user/.ssh/id_rsa (RSA)

An example of working with ssh-agent can be seen below


In addition, the agent solves another problem: if you have encrypted the private key, you will not be asked for a password every time you access it. If you use an agent, you will only need to enter the password when you add the key to the agent.

Local config

If every time I watched a string of the form

ssh -p 2022 [email protected] -o StrictHostKeyChecking=yes -i ~/.ssh/server.pem

type, I was given a ruble, I would have lived in Sochi a long time ago.

On the local machine, you can find the file $HOME/.ssh/config

Host server
	User root
	IdentityFile ~/.ssh/server.pem
Host example.com
	User admin
	IdentityFile ~/.ssh/production.pem

Accordingly, you can write most of the parameters for the host in this file and not enter it every time.

Other ways you can improve security

1. When using key authentication, don't forget that you still have a password, and no matter how you protect your private key, an attacker will be able to guess your qwerty password and log in without having to steal the key

There are several solutions:

  • Set a very complex password that will be difficult to guess and store in a secure place. This will allow you to have an alternate way to sign in.
  • Delete the password completely, but then there may be problems with sudo and other things
  • Disabling password authentication on the server, in fact, as a rule, this is forbidden for the root user. The only thing left to do is to disable for all users.

PasswordAuthentication no in /etc/ssh/sshd_config

2. You can also disable the use of ssh v1
Protocol 2 in /etc/ssh/sshd_config

3. And be sure to block access to SSH for untrusted sources

on the firewall 4. In the past, I would have advised you to change the port from standard 22 to another, but observing how many attempts there are to log in to non-standard ports, I can say unequivocally: this is not protection against hacking.

5. If we are already considering password guessing, then it would not be superfluous to set up fail2ban in order to limit attempts to guess the password.

6. Problems and vulnerabilities are periodically found in the protocol and libraries, the poem here is a universal approach — keep track of software updates and try to regularly install at least security patches.

7. ssh-agent is safer than just copying files, however, it can also be hacked, for example, by a root user on a server. Therefore, it is recommended to enable forwarding only in cases where it is necessary.


Read the documentation, it says everything, no matter how vulgar it sounds.
SSH is a very secure protocol, but human error is often the main source of problems, so keep an eye on security.

Materials Used
Protection with SSH keys
Agent-based SSH key management


No comments yet
Yurij Finiv

Yurij Finiv

Full stack


Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

About author CrazyBoy49z
Ukraine, Lutsk