Here are some good SSH defaults:
/etc/ssh/ssh_config: (example with OpenSSH 7.9 Debian Buster)
ForwardAgent yes (depends on local environment circumstances)
SendEnv LANG LC_*
Most secure MACs:
Secure Kex algos:
#ProxyCommand ssh -q -W %h:%p gateway.example.com
End of file
Now the server part /etc/ssh/sshd_config:
Protocol 2 (Protocol 1 is dangerously outdated!)
Port 22 (22 is standard, you can make it anything. On commandline, when connecting as client, use the “-p” option if not port 22)
AddressFamily inet (means only ipv4, no v6 allowed)
ListenAddress 0.0.0.0 -> this is okay because of strict firewall/ AppArmor. For an onion-only server, you listen on 127.0.0.1
#ListenAddress :: (comment out if ipv6 is disabled via sysctl or iptables or both)
Most secure MACs:
Secure Kex algos:
Logging (Optional- okay to leave commented out)
#LogLevel INFO (unless you need logging, leave commented out)
LoginGraceTime 2m (how long does the prompt stay if you have a passphrase to enter)
PermitRootLogin prohibit-password | no (safer to deny root obviously)
PasswordAuthentication no (use public keys ed25519 so no password authentication. A passphrase is optional for the key, but that is not part of this option. This option refers to old style password-only authentication (not secure))
MaxAuthTries 3 (number of allowed login attempts, if there is a passphrase associated with the key)
MaxSessions 4 (number of allowed sessions)
PubkeyAuthentication yes (always use public keys, not passwords)
#AllowAgentForwarding yes (circumstance specific. This refers to the ssh-agent. Useful when running a local instance and client/server exist on same machine)
#AllowTcpForwarding (be careful with this. Avoid forwarding if you can. If you do not forward tcp, leave this commented out)
TCPKeepAlive yes (dependent on connection and network. Sometimes useful, sometimes not. An okay default is to say “no” and if it turns out you need it, then do “yes.”)
ClientAliveInterval (second amount to keep connection alive)
AcceptEnv LANG LC_*
#Subsystem sftp /usr/lib/openssh/sftp-server
End of File
There are more entries that you could add depending on your needs. The one above are the most important and will establish a functioning, and well guarded setup. Use ed25519 keys only. rsa, and ecdsa are outdated. Use the ssh-keygen command to generate the keys
ssh-keygen -o -a -t ed25519
Remember like this: OATmeal is good for Ed
the -o makes the key support openssh’s own keytype not .pem
the -a determines the rounds of kdf. More=better but don’t go crazy. Generally 75-100 is good. The more rounds, the longer authentication and login will take to finish.
the -t is “type of key”
You will be asked if ~/.ssh is okay for storing the keys. Say yes.
On permissions, sometimes it gets set on its own. If not, do this:
sudo chmod 0600 ~/.ssh/id_ed25519 && sudo chmod 0644 ~/.ssh/id_ed25519.pub
Set the permission for the whole ~/.ssh folder to 0700
Create a file in ~/.ssh called authorized_keys and another one called known_hosts. Set permissions for both to 0644.
Sometimes you need to manually add your newly created private key to the ssh-agent.
The VisualHostKey yes entry in the ssh_config file makes it so when you login, openssh shows you a ascii generated picture of what the key looks like. In addition to all the other verifications, this is one last line of defense to alert you to a changed or wrong key.
Generally the newer OpenSSH’s will choose the strongest cipher, but the config files establish in what order they are parsed. Both sides need to have the same or compatible openssh versions.
Make specific firewall rules for your ssh activity too. Let’s say that you want to connect to a server at 123.45.678 and both your configs specify port 4675:
sudo iptables -A OUTPUT -p tcp -o [interface-name] -s [your client ssh ip] -d [ssh server ip] --dport 4675 --j ACCEPT
then to let them respond:
sudo iptables -A INPUT -p tcp -i [interface-name] -s [ssh server ip] -d [your client ip] --dport 4675 --j ACCEPT
This assumes a default-deny policy for INPUT and OUTPUT. If you have a default-allow for OUTPUT, then you must add this rule as the last rule in the OUTPUT chain:
sudo iptables -A OUTPUT --j DROP
This makes it so the outgoing rules you have are the only ones that allow traffic. Iptables parses in order, so when it does not see a rule matching a packet not on your list, it checks each one in the chain until it finds a match with the last rule and drops the packet.
That should set up your ssh. Some people also recommend re-generatinf the moduli file that comes in /etc/ssh. If you use the settings above, look at the kex algorithms. We are not using any diffie hellman group exchange kex algos to exchange keys, so you do not have to. The chosen kex algo is curve25519.