Public Key Authentication is Not Enough
Having public key authentication enabled is not enough for protecting a server from brute force password attacks. Password authentication also needs to be disabled.
Table of Contents 📖
SSH Passwords
Even if you have public key authentication set up for SSH on your server, if you do not have password authentication disabled, then users can still attempt to log in with a password by specifying the preferred authentication method as an option.
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no <YOUR_USER>@<YOUR_IP_ADDRESS>
user@host's password:
Right off the bat this looks insecure. It looks like an open invitation to a server that could be housing sensitive user data and server side code. A much better response to a password login would be a rejection similar to the following:
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no <YOUR_USER>@<YOUR_IP_ADDRESS>
user@host: Permission denied (publickey).
Here, password authentication is disabled. This means that the server will only accept SSH key authentication.
INFO: Both SSH keys and passwords have their pros and cons, but the cons of passwords are more severe than those of SSH keys. For example, passwords are succeptible to brute force attacks, are often repeated among different applications, and are not as long and complex as SSH keys. Some cons of SSH keys are that they don't have an expiration date and sit on disk. However, they can be password protected and rotated. Furthermore, passwords are sent to the server while the private SSH key remains on the local computer.
Server SSH Configuration
Disabling password authentication comes from the SSH server itself. Specifically, we need to configure the SSH daemon (sshd) to disable password authentication. The SSH daemon is configured with the /etc/ssh/sshd_config file. The contents of this file are below:
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
AuthorizedKeysFile .ssh/authorized_keys
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
PermitRootLogin yes
INFO: Example configuration settings are how the server listens for incoming connections, allowed authentication methods, and more.
The lines that are important to us are PasswordAuthentication and PubkeyAuthentication. These keys toggle password and public key authentication. Setting PasswordAuthentication to no disables password authentication. I would recommend that you disable PasswordAuthentication.
PasswordAuthentication no
After making changes to this file, we need to restart the SSH daemon for the changes to take effect.
sudo systemctl restart ssh
sudo systemctl status ssh
INFO: In modern Linux systems, systemctl is the preferred command for managing services, while service is mostly retained for compatibility with older scripts and systems.
Testing the Connection
Now when we attempt to log in to the server with a password, we should be denied.
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no <YOUR_USER>@<YOUR_IP_ADDRESS>
user@host: Permission denied (publickey).