Additional SSH client security
Following on from last week's post, this post is going to look at some additional steps you can take to keep your SSH connections secure.
Using ssh-agent
If you're using key based authentication, it's a good idea to encrypt your private key using a passphrase. Unfortunately one of the big downsides to doing this is having to decrypt your key before using it. If you have a complex passphrase this can quickly become annoying if you regularly make new connections.
One way round this problem is using ssh-agent to cache your
keys in memory. This makes it possible to use an encrypted private key multiple
times without having to repeatedly enter your passphrase. To start ssh-agent
run the following command:
$ eval $(ssh-agent)
Agent pid 4948
This will start an ssh-agent
process in the background and set the following
environment variables:
SSH_AUTH_SOCK
: the path to the socket file used to communicate with the agent.SSH_AGENT_PID
: the process id of thessh-agent
Once the agent is running you can use ssh-add
to cache a private key:
$ ssh-add ~/.ssh/id_rsa
Enter passphrase for /home/bob/.ssh/id_rsa:
Identity added: /home/bob/.ssh/id_rsa (/home/bob/.ssh/id_rsa)
This will decrypt the key and store it in memory. Once you've done this ssh
should be able to use your private key without you having to re-enter your
passphrase:
$ ssh remotehost
Last login: Fri Jun 15 19:41:40 2018 from somehost.example.com
$
You can verify which SSH keys you've currently got loaded using the -l
option:
$ ssh-add -l
2048 2f:c6:62:4f:f8:e4:a7:56:df:f8:93:8d:47:a1:d2:bc .ssh/id_rsa (RSA)
If you want to unload a private key, you can use the -d
option:
$ ssh-add -d .ssh/id_rsa
Identity removed: .ssh/id_rsa ( [email protected])
Alternatively you can use the -D
option to remove all identities.
Locking and unlocking
Once you've decrypted a private key, ssh-agent
will store the key in memory.
To prevent anyone using the key while it's loaded you can lock the agent using
the -x
option. This will prompt for a password, and then prevent any access
to the key:
$ ssh-add -x
Enter lock password:
Again:
Agent locked.
$ ssh remotehost
Enter passphrase for key '/home/bob/.ssh/id_rsa':
To use the keys loaded in the agent again, use the -X
option to unlock the
key:
$ ssh-add -X
Enter lock password:
Agent unlocked.
$ ssh remotehost
Last login: Fri Jun 15 21:10:15 2018 from somehost.example.com
$
Verifying remote hosts
When you first connect to a host via ssh you will get a message similar to the following:
$ ssh remotehost
The authenticity of host 'remotehost (192.168.10.10)' can't be established.
ECDSA key fingerprint is 61:13:87:c6:13:0c:b4:d4:0c:d6:86:53:b3:b7:a1:42.
Are you sure you want to continue connecting (yes/no)?
Ideally you should verify the fingerprint matches the fingerprint for the host your connecting to. The ssh-keygen command can be used to display the fingerprint for a ssh host key:
[root@remotehost ~]# ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key
256 61:13:87:c6:13:0c:b4:d4:0c:d6:86:53:b3:b7:a1:42 (ECDSA)
If you type yes
the public key of the remote host will be added to
~/.ssh/known_hosts
. ssh
will then verify the public key of the host your
connecting to matches when making subsequent connections. If the public key
doesn't match, ssh
will display a message similar to the following:
$ ssh remotehost
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
8f:c4:e1:75:a2:cc:9d:09:b2:49:d9:6f:76:f3:7d:f3.
Please contact your system administrator.
Add correct host key in /home/bob/.ssh/known_hosts to get rid of this message.
Offending RSA key in /home/bob/.ssh/known_hosts:1
RSA host key for remotehost has changed and you have requested strict checking.
Host key verification failed.
Using VisualHostKey
Verifying hex strings is fine for a computer, however spotting visual patterns
is generally easier for humans. One alternative to using a host key fingerprint
is enabling ASCII art representations of public keys. This can be done using
the VisualHostKey
option:
$ ssh -o VisualHostKey=yes remotehost
Host key fingerprint is 61:13:87:c6:13:0c:b4:d4:0c:d6:86:53:b3:b7:a1:42
+--[ECDSA 256]---+
| .*@=o. |
| oo.@= |
| E+=.o |
| . . = o |
| . S . |
| . |
| |
| |
| |
+-----------------+
ssh-keygen
can also be used to display ASCII art for a specific key:
$ ssh-keygen -lv -f /etc/ssh/ssh_host_ecdsa_key
256 61:13:87:c6:13:0c:b4:d4:0c:d6:86:53:b3:b7:a1:42 (ECDSA)
+--[ECDSA 256]---+
| .*@=o. |
| oo.@= |
| E+=.o |
| . . = o |
| . S . |
| . |
| |
| |
| |
+-----------------+
Hashing known_hosts
By default the public keys of systems you've connected to are stored in
~/.ssh/known_hosts
in the following format:
{markers (optional)} {hostnames} {keytype} {base64-encoded key} {comment}
For example:
remotehost ssh-rsa AAAAB3NzaC1yc2EAAAA1sjcQhbQbmIvDvkpeAlHjQsidHJkI6mQBJFOw==
Because known_hosts
stores the hostname of systems you've been connected to,
anyone who managed to compromise your private key could use the file to
enumerate systems which you may have configured key based authentication on.
This can be prevented by setting the HashKnownHosts
option in
~/.ssh/config
:
HashKnownHosts yes
Once this options is set all new host entries in known_hosts
will be hashed
before they are written to the known_hosts
file. The resulting lines will
look similar to the following:
|1|GSPSrSFBcYBQ8rOQxMqpnYMSGUs=|ajy4mVNhFqIfeMc0rzMunrGb2YI= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNo...
Setting HashKnownHosts
will only affect new known host entries. Existing
entries can be hashed by running ssh-keygen -H
:
$ ssh-keygen -H
/home/bob/.ssh/known_hosts updated.
Original contents retained as /home/bob/.ssh/known_hosts.old
WARNING: /home/bob/.ssh/known_hosts.old contains unhashed entries
Delete this file to ensure privacy of hostnames
It's also worth noting you can use ssh-keygen -F
to check if a host exists in
you're known_hosts
file after you've hashed it:
$ ssh-keygen -F remotehost
# Host remotehost found: line 1 type ECDSA
...