Update October 2015:
A recently-released paper discusses the some vulnerabilities involved with using primes less than 1024 bits. The short version, as it applies to this post, is that the prime numbers used to generate encryption keys are not necessarily unique among all users. Therefore, if an attacker with sufficient resources (like the NSA) could break a single 1024-bit group, they could then read a certain percentage of encrypted network traffic. Researchers figure this is about a quarter of all SSH traffic using the standard configurations. Happily, this doesn’t affect the recommendations here. Using a 2048 or 4096-bit key and specifying acceptable ciphers to prevent the daemon from dropping to a lower security level is enough to prevent a Logjam attack on your SSH session.
The Internet is all about communication with remote machines. Back in the days of telnet
, when users needed to work with a remote system, their usernames and passwords were often passed to the server in plaintext; anyone monitoring the network traffic could capture that information and use it for spying and other nefarious purposes. SSH enables users to connect to remote systems securely, over an encrypted data channel and thereby preventing a casual observer from listening in on a data stream. For that reason, it is now the most common means of transmitting data online.
However, “security” isn’t a destination – it’s a mindset. Security measures need to be constantly reassesed and updated by those who put them in place. Malicious actors are already doing exactly that, and true security is a matter of always staying one step ahead of them.
That said, now is as good a time as any to review your SSH settings. Generally the defaults are good enough for most users, and the default ciphers will protect against most attempts at decryption by anyone other than a government entity or a very motivated, well-funded organization.
Even if you aren’t the target of government surveillance, we want to maintain that secure mindset, and that means hardening our systems as much as possible. Basically, the goal is this: make your encryption and configurations so tight that the only way to hack them is to hit you over the head with a wrench until you spill your secrets.
The SSH daemon
SSH is based on the client-server model. The server is typically a daemon running on a remote machine that we would like to access. This daemon is also the point of greatest interest; it is the thing accepting connections from clients over the Internet and also stands between those clients and your systems.
So, obviously it needs to be secure.
Let’s look at a couple of config settings that you should have:
Protocol
The SSH daemon supports two protocols: 1 and 2. Protocol v1 is older, has a number of weaknesses and should be considered deprecated. Not only does it not perform integrity checks of the connection, but it lacks strong mechanisms for ensuring confidential data transfer.
Version 1 supports a wider variety of user authentication methods (Rhosts, TIS and Kerberos), so some situations may require protocol 1 in order for systems to communicate. If that’s the case for you, please consider upgrading your systems.
Recommended setting:
Protocol 2
HostKey
This specifies the cipher that generated the server’s private key. These private keys are used by the server to prove its identity to the client during key exchange. Protocol 2 offers several options here:
-
ssh_host_dsa_key DSA key with SHA1. DSA keys are required by the specs to be exactly 1024 bits, which is arguably insecure at this point. Additionally, DSA requires a per-message signature value that is extremely sensitive to randomness, secrecy and uniqueness. Any violation of those parameters is enough to reveal the entire key. Best to avoid this one.
-
ssh_host_ecdsa_key Elliptic Curve DSA. ECDSA keys can have varying key lengths and SHA functions. ECDSA is just as sensitive to random signature values; Sony’s private key for PS3 software was cracked in 2010 by exploiting this fact. In fact, the ECDSA algorithm has been broken a few times now. Avoid it.
-
ssh_host_ed25519_key Edwards-curve Digital Signature Algorithm is a scheme designed for high performance while avoiding security problems in DSA/ECDSA. It’s also designed to avoid side channel and timing attacks. Has not yet been broken. According to a BlackHat 2013 presentation, elliptic curve cryptography is preferred for its resilience against mathematical breaks.
-
ssh_host_rsa_key RSA is an encryption scheme which works on the principal of the factoring problem. Essentially, the encryption key is public and can be used by anyone to encrypt data, but the only feasible way to decrypt the data is with the private decryption key. There aren’t currently any known methods for breaking RSA encryption. It can accept very large key lengths, and uses a reasonably secure hash to verify message integrity.
The current consensus is that Ed25519 is probably the most secure scheme at the moment, followed by RSA. Do not use DSA/ECDSA.
Recommended settings:
HostKey /etc/ssh/ssh_host_ed25519_key HostKey /etc/ssh/ssh_host_rsa_key
LogLevel
Logs are always good, not only for debugging purposes, but also for forensic analysis. The daemon should support a number of debug levels, DEBUG
, DEBUG1
, DEBUG2
, and DEBUG3
, but these can leak sensitive information from legitimate users. You don’t want this information sitting around on the system where it could be accessed by others.
Recommended setting:
LogLevel INFO
AllowUsers
This setting allows you to specify which users are allowed to access to the system over SSH. By default, all users are given access. Any given *nix system will have a number of users, including system users like “root,” “ftp,” “mail,” and so on. If you allow any arbitrary user to log in to the system, then you’re opening yourself up to a breach.
For example, if your FTP user is set up without a password, then in theory someone running a scan of your network services could simply run ssh [email protected]
and be logged into your system. What they can do from there depends both on their skill level and luck. Let’s not test that.
Recommended setting:
AllowUsers <USER1> <USER2> <USER3>...
PermitRootLogin
This determines whether the root user is allowed to log into the system. This is never okay! Anyone who can log in as root can do anything to the system. Anyone who needs access to the system should be added to the AllowUsers list, and administrative actions should be controlled through sudo.
That is, if you need root access on a remote system, you should log in as yourself, then sudo -i
to do whatever you need to do.
Recommended setting:
PermitRootLogin no
PubkeyAuthentication
Public key authentication is one of the means of user authentication supported by SSH. This is how you should be logging in! Passwords can be stolen much easier than private keys, and they are easier to guess. One nice thing about using keys is that you can actually password-protect a private key, so that even if it’s stolen it can’t be used fraudulently.
A good public-private keypair would use a secure key length (2048 or 4096) and algorithm (RSA or Ed25519), with a strong passphrase. That would allow a user to authenticate with a password locally and a public key remotely, which is about a secure as one can get. There’s no evidence that organizations like the NSA can steal or break reasonably-secure keys like this, so we can be reasonably certain that it’s safe from malicious actors.
Recommended setting:
PubkeyAuthentication yes
HostbasedAuthentication
With SSH, you can authenticate a user based on where the request is coming from. You can also specify which users and groups are allowed access based on their host. Personally I don’t like this setup. In principal, someone who gains access to a host can then get access to your remote system, unencumbered by needing public keys or passwords. Even if you only open this up to users with no sudo privileges, you still run the risk of a malicious person using some kind of privilege escalation exploit. Unless you have a really good reason, leave this alone.
Recommened setting:
HostbasedAuthentication no
PasswordAuthentication
With SSH you can authenticate with a username and password. This should be avoided for reasons mentioned above. Usernames and passwords can be guessed. Passwords can be cracked much faster than public keys. Don’t even give clients the option of doing this.
Recommended settings:
PasswordAuthentication no
PermitEmptyPasswords
If you are using passwords to authenticate for some reason, then make sure this setting is off. Otherwise, it will allow users without passwords to authenticate. So for example, if your ftp user doesn’t have a password, this would allow someone to log in as ftp just by submitting a blank password. Once they’re in the remote system, who knows what kind of damage they could do. Avoid this!
Recommended setting:
PermitEmptyPasswords no
ChallengeResponseAuthentication
This is one of the more annoying settings in the SSH daemon. If this is set to “yes,” then passwords will still be allowed, even if PasswordAuthentication
is set to “no.” However, setting ChallengeResponseAuthentication
to “no” will still allow public keys and host based authentication to work.
Recommended setting:
ChallengeResponseAuthentication no
UsePAM
The Linux Pluggable Authentication Modules (PAM) framework provides an extra layer of security. We can actually define the authorized users at a lower level than the daemon. Thus, even if the daemon is exploited somehow, we can still (hopefully) use PAM as a backup to validate authentication.
If you’re going to use PAM, then you have some additional configuration to do. This article won’t deal with how PAM works, so feel free to read the docs, or the Wikipedia article for brevity. Basically, you need to edit some files.
First up is your /etc/security/access.conf
, where you can specify which users can log in.
# Allow anyone to log in from the local network (optional)
+ : ALL : 192.168.1.
# Give users alice and bob remote access to the system
+ : alice : ALL
+ : bob : ALL
# Catch-all; anyone not specifically granted access is denied
- : ALL : ALL
Next, you’ll want to instruct the daemon’s PAM file to use the new access rules by modifying /etc/pam.d/sshd
:
account required pam_access.so
You’ll probably see a number of rules in here. You’ll mostly want to keep them in place and simply add the above line.
Finally, you’ll want to edit /etc/ssh/sshd_config
and make sure that you have UsePAM yes
. Restart the daemon for the changes to take effect.
Recommended setting:
UsePAM yes
UsePrivilegeSeparation
This one is a bit more subtle. When a client connects to the server, the server initiates a process for the connection. If the process is privileged, then in theory those privileges can be exploited by a bug to compromise the system.
Privilege separation uses two processes, a parent and a child. The design allows the parent process to handle authentication and the child process to handle the network data, thereby placing a barrier between the system and incoming network data.
You definitely want to use privilege separation. Most installations use “yes” as a default, but this is actually an older model. Per the docs: “If UsePrivilegeSeparation is set to ‘sandbox’ then the pre-authentication unprivileged process is subject to additional restrictions.” So for the tightest restrictions, use “sandbox”
Recommended setting:
UsePrivilegeSeparation sandbox
Port (optional)
Some people like to suggest changing the port to something non-standard. Security by obscurity; it’s unlikely that automated scans of public IP addresses will bother to waste time and compute cycles on iterating over every possible port on a given device. The cost-benefit ratio just isn’t there. So, yes, changing the port will basically eliminate automated scans.
However, it won’t hinder a targeted attack either. Some simple commands in nmap
against a host will tell an attacker exactly which ports are open. He or she can then simply attempt an SSH connection to each open port until they find a receptive one. Discovering your secret port would only take a few minutes.
It may not really be necessary either. If your remote system is behind a firewall of some kind, then you really only need to close port 22 on the firewall and open up a non-standard port there. Data to the new port can be routed internally to port 22 on the remote system.
Recommended setting: something non-standard if the system is directly connected to the Internet, otherwise leave it alone and obfuscate the port at the firewall.
The SSH client
While the server is the most commonly-targeted for attack, you can also change your client settings to ensure that you never negotiate an insecure connection with a remote host. I recommend something along the lines of this in your ~/.ssh/config
file:
Host *
Ciphers [email protected],[email protected],[email protected],aes256-ctr,aes192-ctr,aes128-ctr
HostbasedAuthentication no
KexAlgorithms [email protected],diffie-hellman-group-exchange-sha256
MACs [email protected],[email protected],[email protected],[email protected],hmac-sha2-512,hmac-sha2-256,hmac-ripemd160,[email protected]
PasswordAuthentication no
Protocol 2
PubkeyAuthentication yes
Most of these have already been discussed above. Let’s spend a few minutes on Ciphers
, KexAlgorithms
, and MACs
.
Ciphers
This line specifies the ciphers we’re allowing the client to use in order of preference. Note that this parameter only applies when Protocol 2 is invoked, which is fine because that’s the only protocol we’re going to support.
chacha20-poly1305 is a newer cipher for secure communications. It doesn’t suffer from some of the same vulnerabilities found in AES-GCM. It also prevents traffic analysis, which can be performed even if the stream’s encryption isn’t broken. Hence, it is the preferred option.
AES-GCM ciphers with at least 128 bits are next, followed by AES-CTR with at least 128 bits. GCM is a newer mode of symmetric key block encryption noted for its efficiency and performance. CTR is a similar mode, but with a few drawbacks. For one, it can’t be completely parallelized, so speed can drop. When implemented correctly, security is not really an issue; it’s included in the list for compatibility with a broader array of systems.
KexAlgorithms
This is the preferred list of algorithms for key exchange. [email protected] is Elliptic Curve Diffie Hellman key exchange over Curve25519 with SHA2 data integrity verification. Curve25519 is preferred over NIST curves, as the former were backed by the NSA and there is some concern over backdoors. diffie-hellman-group-exchange-sha256 is an implementation of Diffie-Hellman key exchange with SHA2 data integrity checking. This is included as the strongest alternative that is still generally supported.
MACs
Message Authentication Codes (MACs) provide data integrity checks. These allow us to ensure that the data has not been tampered with during transmission. There are a few ways to ensure the integrity of a message sent, but the strongest is Encrypt then Mac (ETM). With ETM, messages that fail validation are simply ignored. Not only is this an easier approach, but it mitigates the most common attacks. The hashing algorithms presented here all use ETM with secure hashing functions (ie, no MD5/SHA1) and key sizes of at least 128 bits.
Results
Based on this discussion, the following configurations are recommended for foiling the attmempts of a third party to eavesdrop on your data communications:
/etc/ssh/sshd_config
:
AllowUsers <USER1> <USER2> <USER3>...
ChallengeResponseAuthentication no
HostbasedAuthentication no
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
LogLevel INFO
PasswordAuthentication no
PermitEmptyPasswords no
PermitRootLogin no
Protocol 2
PubkeyAuthentication yes
UsePAM yes
UsePrivilegeSeparation sandbox
/etc/ssh/ssh_config
:
Host *
Ciphers [email protected],[email protected],[email protected],aes256-ctr,aes192-ctr,aes128-ctr
HostbasedAuthentication no
KexAlgorithms [email protected],diffie-hellman-group-exchange-sha256
MACs [email protected],[email protected],[email protected],[email protected],hmac-sha2-512,hmac-sha2-256,hmac-ripemd160,[email protected]
PasswordAuthentication no
Protocol 2
PubkeyAuthentication yes
Conclusion
Hopefully you found this helpful. If you have anything you’d like to contribute, please let me know!