# SSH Security > A full write-up on OpenSSH usage with security in mind. --- ## Table of Contents * [Generating An SSH Key Pair](#generating-an-ssh-key-pair) - [Linux](#linux) - [Windows](#windows) * [Getting Your Client To Use Your SSH Key](#getting-your-client-to-use-your-ssh-key) - [Linux](#linux) - [Windows](#windows) * [Setup Server](#setup-server) - [Harden OpenSSH Daemon](#harden-openssh-daemon) - [Create A New User On The Server](#create-a-new-user-on-the-server) - [Copy Your Public Key To Your Shell](#copy-your-public-key-to-your-shell) * [Extra Security](#extra-security) - [Allow Incoming SSH Connections Through IPTables](#allow-incoming-ssh-connections-through-iptables) - [Lock Users In A Chroot Jail Environment](#lock-users-in-a-chroot-jail-environment) - [Port Knocking](#port-knocking) - [Setup Server](#setup-server-1) - [Using IPTables](#using-iptables) - [Using Knockd](#using-knockd) - [Knocking Your Server](#knocking-your-server) - [Using Nmap](#using-nmap) - [Using knockd](#using-knockd-1) - [Jump Hosts](#jump-hosts) **Note:** The port *65150* is used in this write-up as an example of how to use a non-standard ports. --- ### Generating An SSH Key Pair #### Linux Generate a key using the **Ed25519** algorithm with 500 KDF rounds: * `ssh-keygen -t ed25519 -a 500 -C "$(whoami)@$(hostname)-$(date -I)"` This will generate 2 files in your `~/.ssh` directory. A public key *(.pub)* and a private key. You only need to backup your private key. Public keys can be regenerated from the private key: * `ssh-keygen -y -f ~/.ssh/acidvegas@pi-2017-01-01` Copy your public key to clipboard: * `cat ~/.ssh/acidvegas@pi-2017-01-01.pub` #### Windows Download & run [puttygen](https://the.earth.li/~sgtatham/putty/latest/w32/puttygen.exe). Once opened, change the key type to **ED25519** under the *Parameters* box, and then click the *Generate* button. Click the *Save private key* button to save your key. You only need to backup your private key. Public keys can be regenerated by clicking `File -> Load private key`. Copy the data in the box labeled *Public key for pasting into OpenSSH authorized_keys file*. ### Getting Your Client To Use Your SSH Key #### Linux * `ssh -p 65150 -i ~/.ssh/acidvegas@pi-2017-01-01 acidvegas@192.168.1.10` or... * `nano ~/.ssh/config` ``` Host acidbox HostName 192.168.1.10 Port 65150 User acidvegas IdentityFile ~/.ssh/acidvegas@pi-2017-01-01 IdentitiesOnly yes ``` * `chmod 600 ~/.ssh/config` * Usage: `ssh acidbox` #### Windows Download & run the [putty](https://the.earth.li/~sgtatham/putty/latest/w32/putty.exe) client. Once opened, select `Connection -> SSH -> Auth` from the *Category* box. Click the *Browse* button and select your private key. Select *Session* from the *Category* box. Change the *Host Name (or IP address)* and *Port* to your server. Name the session in *Saved Sessions* box and click the *Save* button. SSH into your server by clicking your saved session from the *Saved Sessions* box, and clicking the *Open* button. --- ### Setup Server #### Harden OpenSSH Daemon * `nano /etc/ssh/sshd_config` ``` AddressFamily any AllowAgentForwarding no AllowGroups ssh AllowTcpForwarding no AuthorizedKeysFile /etc/ssh/authorized_keys/%u #Banner /etc/issue ChallengeResponseAuthentication no Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr ClientAliveInterval 0 #ClientAliveCountMax 0 HostKey /etc/ssh/ssh_host_ed25519_key KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 LoginGraceTime 30 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 MaxAuthTries 2 MaxSessions 1 MaxStartups 3:50:10 PasswordAuthentication no PermitRootLogin no Port 65150 PrintLastLog no PrintMotd no Protocol 2 ``` * `mkdir /etc/ssh/authorized_keys` * `rm /etc/ssh/ssh_host_*_key` * `ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key` **Options**: * The `AddressFamily` option can be: - **inet** for IPv4 only. - **inet6** for IPv6 only. - **any** for both. * The `AuthorizedKeysFile` option can be commented out to use the standard `~/.ssh/authorized_keys` file instead. * The `Banner` option can be un-commented if the `/etc/issue` file exists. This is shown before the user authenticates. * The `ClientAliveCountMax` option can be un-commented & the `ClientAliveInterval` option can be changed to **1800** to enforce a 15 minute idle timeout. * The `MaxSessions` option can be increased if there are additional users on the server. * The `Port` option should be set to a non-standard port *(High-value port number recommended)*. * The `PrintMotd` option can be changed to **yes** if the file `/etc/motd` exists. This is shown after the user authenticates. #### Create A New User On The Server Create a new user on the server with a password: * `useradd -m -s /bin/bash acidvegas` * `passwd acidvegas` Create an **ssh** group and add your user to the group. * `groupadd ssh` * `gpasswd -a acidvegas ssh` #### Copy Your Public Key To Your Shell * `nano /etc/ssh/authorized_keys/acidvegas` *(Paste your public key data in this file)* **Note:** This is only required if you are using the `AuthorizedKeysFile /etc/ssh/authorized_keys/%u` line in your `sshd_config` file. For using the standard `~/.ssh/authorized_keys` file, do the follow: * `mkdir ~/.ssh` * `chmod 700 ~/.ssh` * `chown -R $USER ~/.ssh` * `nano ~/.ssh/authorized_keys` *(Paste the copied public key data into this file)* * `chmod 400 ~/.ssh/authorized_keys` * Optionally, you can pass the immutable flag to prevent changes: - `chattr +i ~/.ssh` - `chattr +i ~/.ssh/authorized_keys` --- ### Extra Security #### Allow Incoming SSH Connections Through IPTables ``` iptables -A INPUT -i eth0 -p tcp --dport 65150 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 65150 -m conntrack --ctstate ESTABLISHED -j ACCEPT ``` You can also allow only incomming connection from a specific IP address instead by changing the first line above to: ``` iptables -A INPUT -i eth0 -p tcp -s 192.168.1.99 --dport 65150 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT ``` #### Lock Users In A Chroot Jail Environment See [mkchroot](https://github.com/acidvegas/mkchroot) repository for details. #### Port Knocking The following is an example which uses the port knocking sequence `8881 -> 7777 -> 9991` to open port 65150 for 30 seconds. ##### Server ###### Using IPTables * `nano /etc/iptables/iptables.rules` ``` *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] :TRAFFIC - [0:0] :SSH-INPUT - [0:0] :SSH-INPUTTWO - [0:0] # TRAFFIC chain for Port Knocking. The correct port sequence in this example is 8881 -> 7777 -> 9991; any other sequence will drop the traffic -A INPUT -j TRAFFIC -A TRAFFIC -p icmp --icmp-type any -j ACCEPT -A TRAFFIC -m state --state ESTABLISHED,RELATED -j ACCEPT -A TRAFFIC -m state --state NEW -m tcp -p tcp --dport 65150 -m recent --rcheck --seconds 30 --name SSH2 -j ACCEPT -A TRAFFIC -m state --state NEW -m tcp -p tcp -m recent --name SSH2 --remove -j DROP -A TRAFFIC -m state --state NEW -m tcp -p tcp --dport 9991 -m recent --rcheck --name SSH1 -j SSH-INPUTTWO -A TRAFFIC -m state --state NEW -m tcp -p tcp -m recent --name SSH1 --remove -j DROP -A TRAFFIC -m state --state NEW -m tcp -p tcp --dport 7777 -m recent --rcheck --name SSH0 -j SSH-INPUT -A TRAFFIC -m state --state NEW -m tcp -p tcp -m recent --name SSH0 --remove -j DROP -A TRAFFIC -m state --state NEW -m tcp -p tcp --dport 8881 -m recent --name SSH0 --set -j DROP -A SSH-INPUT -m recent --name SSH1 --set -j DROP -A SSH-INPUTTWO -m recent --name SSH2 --set -j DROP -A TRAFFIC -j DROP COMMIT ``` * `systemctl daemon-reload ` * `systemctl restart iptables` ###### Using Knockd Download & install the [knockd](http://www.zeroflux.org/projects/knock) package. * `nano /etc/knockd.conf` ``` [options] logfile = /var/log/knockd.log [opencloseSSH] sequence = 8881:tcp,7777:tcp,9991:tcp seq_timeout = 5 tcpflags = syn,ack start_command = /usr/bin/iptables -A TCP -s %IP% -p tcp --dport 65150 -j ACCEPT cmd_timeout = 10 stop_command = /usr/bin/iptables -D TCP -s %IP% -p tcp --dport 65150 -j ACCEPT ``` #### Knocking Your Server ##### Using Nmap Download & install the [nmap](https://nmap.org/) package. * `nano knock.sh` ```bash #!/bin/bash HOST=$1 shift for ARG in "$@" do nmap -Pn --host_timeout 100 --max-retries 0 -p $ARG $HOST done ``` * Usage: `sh knock.sh example.server.com 8881 7777 9991` ##### Using Knockd Download & install the [knockd](http://www.zeroflux.org/projects/knock) package. * `knock -v example.server.com 8881:tcp 7777:tcp 9991:tcp` #### Jump Hosts * `ssh -J ` The `` option can be `user@host`, `user@host:port` or an host setup in your `~/.ssh/config`. Multiple jump hosts can be used in a comma *(no spaces)* separated list. The same applies for the `` option, except to change the port, either use the `-p ` option at the end or use a host setup in your `~/.ssh/config`. or... * nano `~/.ssh/config`: ``` Host jumpbox HostName jump.server.com Host targetbox ... ProxyJump jumpbox1 ... ``` Multiple jump hosts can be used in the `ProxyJump` option in a comma *(no spaces)* separated list. Connect to your target host with `ssh targetbox` --- ### Sources * https://wiki.archlinux.org/index.php/Port_knocking * https://wiki.archlinux.org/index.php/SSH_keys * https://wiki.mozilla.org/Security/Guidelines/OpenSSH * https://www.openssh.com/manual.html * https://stribika.github.io/2015/01/04/secure-secure-shell.html