SSH must be configured on both the client and server. It is important to configure it correctly on both sides to prevent the use of SSH-1 and to only allow strong encryption algorithms.
On the server side, the configuration files are usually located in /etc/ssh. On Mac OS X, the files are just in /etc, such as /etc/ssshd_config. The configuration file for the server is /etc/ssh/sshd_config. A typical configuration looks like this:
#Port 22 #Protocol 2,1 Protocol 2 #AddressFamily any #ListenAddress 0.0.0.0 #ListenAddress :: # HostKeys for protocol version 2 HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_dsa_key # Lifetime and size of ephemeral version 1 server key #KeyRegenerationInterval 1h #ServerKeyBits 768 # Logging # obsoletes QuietMode and FascistLogging #SyslogFacility AUTH #LogLevel INFO # Authentication: #LoginGraceTime 2m PermitRootLogin no #StrictModes yes #MaxAuthTries 6 #RSAAuthentication yes #PubkeyAuthentication yes #AuthorizedKeysFile .ssh/authorized_keys # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts #RhostsRSAAuthentication no # similar for protocol version 2
The lines starting with #
are comments. The main configuration options with their default values are displayed as comments. The most important options are:
Port 22
This is the default port for SSH.
Protocol 2
It is very important to allow only SSH-2. If you allow SSH to revert back to version 1 for cases when some of your legitimate clients support only version 1, be assured that attackers will exploit it. They will pretend they support only version 1 and will exploit all known weaknesses of SSH-1.
HostKey
The path to the private DSA and RSA keys. These keys are created automatically when SSH is started for the first time following initial installation on the server
KeyRegenerationInterval 1h
A new session key is created every hour (see The SSH-2 Protocol). This interval is commonly used.
LogLevel
The level of debug messages that are logged. You can change this value to DEBUG
to get more information.
With the logging level DEBUG
, login and password are logged. You should not allow this value to sit idle for a long time, and logs should be cleaned to remove this sensitive information.
LoginGraceTime 2m
Maximum delay allowed for a user to enter a login and password. Keep this value low. If it is too high, an attacker could initiate thousands or millions of connections to the server without typing any login or password, thus causing a denial of service (DoS). The server would have too many open connections, and legitimate users might not be able to create additional connections to the server.
It is possible to restrict the number of unauthenticated connections, which is the number of connections where the client has not yet authenticated to the server. MaxStartups 10
allows a maximum of 10 simultaneous unauthenticated connections. This prevents attackers from leaving too many open connections, but can increase the likelihood of denial of service: if the attacker opens 10 connections, no other user can login. Other options can mitigate this risk.
PermitRootLogin no
It is good practice not to allow the root account direct access through the SSH server. If you need remote root access to the server, you should connect as a normal user and then escalade to root with su or sudo (Limiting Access). This way, you reduce the possible number of vulnerabilities. If only a few users are allowed to use the sudo command, you have a few accounts that allow compromising your system with just one password. Other user accounts require knowing two passwords instead of one. Also, if there is a vulnerability in the SSH server, an attacker would only be able to access your system as an unprivileged user and would not have root access.
StrictMode yes
By default, the server does not accept connections if file permissions or ownerships are wrong. See SSH Troubleshooting for more details. This can give beginners headaches before they have a well-configured system, but this should be left as yes
.
MaxAuthTries 6
The maximum login attempts per connection is usually set to 3. The default value is 6.
PublicKeyAuthentication yes
Allow users to authenticate with their public keys. You can set this option to no if you think your users cannot be trusted to keep their private key secured on their system.
PasswordAuthentication yes
Allow users to authenticate with a login and password.
PermitEmptyPasswords no
Users must not be able to use an empty password to connect to the server.
UsePAM no
You could use Pluggable Authentication Modules (PAM) to authenticate users with a login and password. PAM is currently used by most Linux distributions to authenticate users. Several services can use the same PAM configuration. If this option is set to yes
, expect the options PermitRootLogin
and PermitEmptyPasswords
to be ignored.
TCPKeepAlive yes
The server can send heartbeat packets to the client to make sure it is still reachable while the connection is idle for a couple minutes. This ensures that no dead connection (due to a network issue, for example) is left open on the server. I prefer to set this option to no
to leave the connection open when there is a temporary failure. It is not unusual to be able to resume an SSH connection after losing network connectivity for several minutes.
TCPKeepAlive
packets do not go through the encrypted channel; they can be spoofed.
UsePrivilegeSeparation yes
The SSH daemon is usually started as root. With this option set, an unprivileged separate process is created for each user connection. This is a good way to prevent privilege escalation in case of exploitation of a potential vulnerability on the SSH server.
Any change made to the server's configuration will take effect after the SSH service is restarted or reloaded.
If you connect through SSH to change the SSH configuration on the server, always keep your current connection open. Type service ssh
restart or /etc/init.d/sshd restart
. This loads the new configuration for the next SSH connections. It does not modify your current connection's parameters. You can then open a new connection to make sure it still works.
If instead you type service ssh stop
and then service ssh start
, your current connection might be closed. If you made an error in your server configuration file, you would then be locked out.
It is possible to restrict access to certain user names or certain groups. Whitelists and blacklists can be added to /etc/ssh/sshd_config:
AllowUsers
user1 user-*
Allows only users with the login name user1
or user2
to login. It is possible to use the wildcard *
to match 0 or more characters, and ?
to match any character.
AllowGroups
ssh-group
Allows only users who belong to ssh-group
. Wildcards can be used.
DenyUsers
user1
Forbids user1
from logging in through SSH. The syntax of this option is the same as AllowUsers
.
DenyGroups
group1
Forbids users who belong to group1
from logging in through SSH. The syntax of this option is the same as AllowGroups
.
You can now connect to an SSH server with the default configuration:
$ssh
julien@
192.168.0.102 The authenticity of host '192.168.0.102 (192.168.0.102)' can't be established. RSA key fingerprint is 98:d5:a3:ce:a7:74:b9:e4:02:bd:b4:20:b8:e6:60:f4. Are you sure you want to continue connecting (yes/no)?yes
Warning: Permanently added '192.168.0.102' (RSA) to the list of known hosts. julien@192.168.0.102's password: Last login: Fri Sep 1 15:00:28 2006 from 192.168.0.103 [julien@asus ˜]$
This logged me into the SSH server at the address 192.168.0.102 as user julien (I have a local account on this server). Since it is the first time I connected to this machine, SSH displays the host RSA public key fingerprint. The first connection to an SSH server is not secured.
SSH does not use a Public Key Infrastructure (PKI) where a trusted third party can verify the legitimacy of the server's public key. In its default configuration, you should verify, out of band, each server's public key by checking its key fingerprints. This is to make sure an attacker is not doing a man-in-the-middle attack (see SSH Shortcomings) and that the address of the SSH server was not spoofed. In practice, people rarely do this verification and just accept the server's key hoping for the best.
If you do not specify a username on the command line and no user is specified in the SSH configuration files (see the next section), SSH uses the currently logged-on username.
After you accept the fingerprints, the host address and host public key are added to the list of known hosts in $HOME/.ssh/known_hosts:
192.168.0.102 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAx8uJ7Yve1ArQ3iynu5ishSWc9a/f4q quu7Hz5SmzquPnC3b2CKahZNwSM4Uw3fsu+HJ9hnVaCAAVyNpBwT9OaBCNPaO8/KlywVyANuqSBWHZjM gL0AY+Dcf/9BkPSLGNQqV/iqHLCA7TmotCzukhCxFeL5ZogGrol6tSUOL/BS0=
If you connect to the same SSH server using a different format of addresses such as a fully qualified domain name (FQDN), IP address, or subdomain name only, the client considers them as different known hosts. The fingerprint is shown each time and all the different addresses are added to the known_hosts file.
Next time you connect to the same host, SSH automatically compares the public key sent by the host with the value recorded the very first time. If they do not match, the SSH connection is interrupted.
A public key mismatch does not always indicate an attack. If the operating system was reinstalled or replaced, the public key may be different. You should first call the server administrator to find out why the public key changed.
On the client side, the SSH connection can be configured through:
Command-line options
$HOME/.ssh/config
/etc/ssh/ssh_config
The parameters are considered in this order: if an option is set on the command line, the values mentioned in the two configuration files are ignored.
The two client configuration files have the same format as the server configuration files and have several options in common. Unfortunately, the same option can be set with different option names on the client and server sides. Table 15-1 shows the option name on the server configuration file, on the client, and on the command line.
Table 15-1. Parameter comparison table
Option description | Server | Client | Command line |
---|---|---|---|
Use SSH-2 only | Protocol 2 | Protocol 2 | −2 |
Data compression | Compression delayed | Compression yes | -C |
Compression level | CompressionLevel 9 | -o CompressionLevel 9 | |
Number of login attempts allowed per connection | MaxAuthTries 3 | NumberOfPasswordPrompts 3 | -o NumberOfPasswordPrompts 3 |
Change the debug level | LogLevel DEBUG | LogLevel DEBUG | -vvv |
Connect on a non-standard port | Port 2200 | Port 2200 | -p 2200 |
port |
There are a couple of interesting options specific to the client:
CheckHostIP yes
SSH can check the IP address of the SSH server in addition to its domain name. This prevents DNS spoofing attacks.
HashKnownHosts yes
Instead of storing the domain name, SSH can store a hash of the SSH server host names in known_hosts to avoid storing such sensitive information in clear text when sharing the file.
RekeyLimit 1G
Renegotiate the session key after one gigabyte of data is exchanged.
User user
If you always log in as the same username to the SSH server, you can add it once and for all in your configuration files.
ServerAliveCountMax 3
If the server does not reply to three consecutive server alive messages, the connection is considered dead and is dropped. This option should be used in place of TCPKeepAlive yes
because the server alive messages are sent through the encrypted channel and cannot be spoofed.