SSH

Guides for hardening and configuring Secure Shell (SSH) servers and clients.

Many systems automatically install OpenSSH. However, you should check the version (using ssh -V) and update if necessary (using sudo apt update && sudo apt upgrade openssh-server), as well as harden the default installation to avoid known vulnerabilities in the server’s implementation itself. You should also consider further restricting certain users, groups, and especially (possibly automated) clients who need access to a login shell, in accordance with the principle of least privilege.

Hardening SSH

In order to use SSH most securely, you should consider performing the following procedures, derived from this "Secure Secure Shell" article, among other sources, such as the sshd manual page. In a nutshell, these instructions provide the following:

  • Network-based hardening through careful selection of permissible key exchange algorithms, ciphers, and other cryptographic implementations.
  • Host-based hardening through Operating System-level and application-level configuration options.
  • Deactivation of undocumented and risky features (i.e., security vulnerability CVE-2016-0777).

Harden SSH server

Do this to harden your OpenSSH installation:

  1. In the server’s /etc/ssh/sshd_config file, prepend the following lines, which will preempt the application of any similar configuration directives that appear later in the file. (See the sshd_config(5) manual page for more details and configuration options.)
    # Network security considerations.
    # Consider moving off a default port.
    #Port 22
    # Consider listening only on the local interface and setting up a Tor Onion service instead; this blocks LAN access.
    #ListenAddress 127.0.0.1
    # Cryptographic selections.
    KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
    Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
    MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-ripemd160-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160,umac-128@openssh.com
    # Server authentication.
    Protocol 2
    HostKey /etc/ssh/ssh_host_ed25519_key
    HostKey /etc/ssh/ssh_host_rsa_key
    # Client authentication.
    PasswordAuthentication no
    ChallengeResponseAuthentication no
    PubkeyAuthentication yes
    # Host-based security considerations.
    UsePrivilegeSeparation sandbox
    AllowGroups ssh-users
    # Don't tell clients our operating system, they don't care.
    DebianBanner no
    
    • If you chose to include the diffie-hellman-group-exchange-sha256 key exchange algorithm (in the list of acceptable KexAlgorithms), edit the /etc/ssh/moduli file (see moduli(5) for details) to remove small (i.e., weak) primes:
      awk '$5 > 2000' /etc/ssh/moduli > "${HOME}/moduli" # print lines where the fifth column is greater than 2000
      wc -l "${HOME}/moduli" # make sure there is something left in the file; we should see a positive integer
      sudo mv "${HOME}/moduli" /etc/ssh/moduli # replace the original moduli file with the filtered one
      rm "${HOME}/moduli" # remove the temporary moduli file
      
    • If the /etc/ssh/moduli file doesn’t exist, then create it:
      sudo ssh-keygen -G /etc/ssh/moduli.all -b 4096
      sudo ssh-keygen -T /etc/ssh/moduli.safe -f /etc/ssh/moduli.all
      sudo mv /etc/ssh/moduli.safe /etc/ssh/moduli
      sudo rm /etc/ssh/moduli.all
      
  2. Remove any existing but unused SSH keys, and regenerate the remaining recommended ones with stronger parameters (longer key sizes):
    cd /etc/ssh
    sudo rm ssh_host_*key*
    sudo ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" < /dev/null
    sudo ssh-keygen -t rsa -b 4096 -f ssh_host_rsa_key -N "" < /dev/null
    
  3. Create the special-purpose ssh-users group:
    sudo groupadd ssh-users
    
  4. Before a user will be permitted to login over SSH, they must be added to the ssh-users group with sudo usermod -a -G ssh-users $THE_USERNAME (where $THE_USERNAME is the username of the user to be added to the group; you will probably want to add your own user account, at a minimum).
  5. Finally, test the configuration with sshd -t or sshd -T for an extended check. No errors indicates a reasonable configuration file.

Test and apply the new configuration

Once configured as above, you can apply the new sshd_config on the server:

sudo sshd -t # test the configuration again, just in case
# Find the SSH server's main process and send it a hangup signal, to reload its configuration file.
sudo kill -SIGHUP $(ps -u root | grep sshd | sort -n | head -n 1 | awk '{print $1}')

Note that this might kill your connection, so be certain you can still access the server through some other means if the configuration does not take.

Harden SSH client

Do this to harden your SSH client:

  1. On your personal computer, in your user’s ~/.ssh/config file, prepend the following lines, which will preempt the application of any similar configuration directives that appear later in the file. (See the ssh_config(5) manual page for more details and configuration options.)
    # Make it easier to use Tor Onion services.
    Host *.onion
        ProxyCommand nc -x 127.0.0.1:9050 %h %p
        # If you prefer to use socat(1) instead of nc(1), use the following line instead:
        #ProxyCommand socat - SOCKS4A:localhost:%h:%p,socksport=9050
    # If you use GitHub, you will need a special KexAlgorithms line.
    Host github.com
        KexAlgorithms diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1
    Host *
        # Don't send extraneous identity keys (which leaks metadata about who you are during the SSH connection).
        IdentitiesOnly yes
        ChallengeResponseAuthentication no
        PasswordAuthentication no
        PubkeyAuthentication yes
        KexAlgorithms diffie-hellman-group-exchange-sha256
        HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ssh-rsa
        # macOS clients only support a strict subset of the above HostKeyAlgorithms.
        # If you are using a macOS client, you may need to comment the above line and uncomment this one:
        #HostKeyAlgorithms ssh-rsa-cert-v01@openssh.com,ssh-rsa
        Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
        # macOS clients only support a strict subset of the above Ciphers.
        # If you are using a macOS client, you may need to comment the above line and uncomment this one:
        #Ciphers aes256-ctr,aes192-ctr,aes128-ctr
        MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-ripemd160-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160,umac-128@openssh.com
        # macOS clients only support a strict subset of the above MACs.
        # If you are using a macOS client, you may need to comment the above line and uncomment this one:
        #MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
        # Protect against CVE-2016-0777.
        UseRoaming no
        # macOS users may want to store public key passphrases in their macOS Keychain facility:
        #UseKeychain yes
        # Clients may also wish to automatically load public keys into `ssh-agent(1)` upon use:
        #AddKeysToAgent confirm
    
  2. Generate (or re-generate) your client’s identity keys with strong values:
    ssh-keygen -t ed25519 -o -a 100
    ssh-keygen -t rsa -b 4096 -o -a 100
    
  3. Copy your newly generated SSH public key to your user’s ~/.ssh/authorized_keys file on the server, possibly using ssh-copy-id(1) (or any file transfer mechanism).

Apply application-level restrictions

Before you apply application-level restrictions, consider whether or not your use case requires access to a shell in the first place. If you can avoid creating an Operating System user account and providing a login shell entirely, you may be able to position yourself with a stronger security posture since you will never have exposed the possibility of gaining direct shell access to potential attackers in the first place. The rest of this section assumes you have already come to the conclusion that a shell provided by SSH is required.

Restrict allowed commands based on authorized SSH keys

TK-TODO: Use the command="…" option in the authorized_keys file to restrict logins made with specific public keys to a specific command invocation.