It works similarly to SSL which you use all the time to do most of your web browsing.
When using encryption it becomes **very** hard to sniff the data traveling between the client and the server.
There are two versions of SSH, version 1 and version 2, and you should only use version 2 as the former is not considered [secure]() anymore.
The recommended encryption used by most SSH servers is [AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard).
If you're interested in understanding the mathematics behind AES, [this](https://www.youtube.com/channel/UC1usFRN4LCMcfIV7UjHNuQg) class is exceptionally good but not for the faint of heart.
The main takeaway would be the number of **bit's used** where **higher** is **better**.
By default ssh uses a very secure cipher but you can specify which one you want with the `-c` flag to `ssh`.
Do keep in mind that the server needs to support the cipher you're requesting.
## SSH keys
SSH encryption and SSH keys are not the same thing.
**Keys** are used for **authentication** with a server.
Once the client is authenticated and granted access to the server, the encryption is set to **encrypt** the **traffic** from client to server and visa versa.
SSH keys are [asymmetric](https://en.wikipedia.org/wiki/Public-key_cryptography) key pairs where you have two simple text files.
One with the **private** part, which is used for **decrypting**, and one **public** part which is used for **encrypting**.
Both parts together form one **key pair**.
If you're interested in the maths behind key pairs, have a look at this 15min [video](https://www.youtube.com/watch?v=4zahvcJ9glg&t=1s), it's a lot easier than you expect!
Keys are by default stored in `~/.ssh/` and named `id_rsa` for the **private** part, and `id_rsa.pud` for the **public** part.
**Important**, each generated key is **unique** so if you overwrite a key you made previously that old key is **gone!**.
There is **no way** to recover that old key anymore, gone is gone.
I highly advise you to keep backup's of your important keys, preferably in multiple locations.
GNOME [Seahorse](https://wiki.gnome.org/Apps/Seahorse/) or [keepass2](https://keepass.info/) are good password managers you can use to store both passwords and key pairs.
An ssh key can be generated by running the `ssh-keygen` command.
You'll be prompted with a dialog that will ask to name and where to save the key pair, plus whether you want a password for that key or not.
For automated logins you should not set a password as it would defeat the purpose but you **must** realise that everyone that has access to the **private** key will be able to log in to each server the key is deployed to.
Keeping this file safe becomes very important.
**Remember the bandit SSH key level?**
```
➜ ~ git:(master) ✗ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/waldek/.ssh/id_rsa): my_ssh_key
The connection will try any form of authentication allowed by the server in order of most secure to least secure.
Publickeys are considered more secure than passwords so it will try that first.
You can see this at the following line `debug1: Will attempt key: /home/waldek/.ssh/id_rsa RSA SHA256:tOuvE+Qq1B/eXyGcyIfs0MVXaaSI/GNYjLqO3D+Tz+k`.
The `student` account does not have the matching public key as an authorized key so the client tries a password login next `debug1: Next authentication method: password`.
On the server side the sshd process will look for a matching **public** key in the users home directory.
By default it will try every line in the `~/.ssh/authorized_keys` file for authentication.
If a match is found, you'll be granted access, if not it will try an other authentication method until every method allowed by the server is exhausted and you'll be denied access.
The verbose output of a successful login with a key pair can be seen below.
So, how did I add my public key to the `student`'s account authorized keys?
There is a program called `ssh-copy-id` that can do it for you, but I personally always just copy and paste it to the users `~/.ssh/authorized_keys` file.
This is an example of a server I use with the public keys that are allowed to log in.
As you can see there are **four** key's that are allowed to log in.
It's a **two part** process that I'll let you figure it out by yourself but if you're stuck have a look at [this](https://gitea.86thumbs.net/user/settings/keys) and [this](https://pandammonium.org/how-to-change-a-git-repository-from-https-to-ssh/).
We've done quite a bit of SFTP before so we won't go into detail here but if you forgot, go have a look at the networking exercises in the resources directory.
I'm mentioning it because it's crucial to remember it's existence in order to understand the next topic, sshfs.
Some clever guy's used it to build [sshfs](https://wiki.archlinux.org/title/SSHFS) which mounts a remote folder into our system so we can use it like a network share.
Again, this is very handy additional program to install on your ssh **client** which requires no modifications to the ssh **server** you're connecting to.
You install it with trusty old `apt`, `sudo apt install sshuttle`.
Now, what does it do?
It creates a connection to a **remote** ssh server and adds **local** iptable rules to send all (or some) traffic via that remote server onto the internet.
I highly recommend to read through the `man sshd_config` pages for a detailed explanation of all possible settings.
The Debian configuration is quite secure but we can improve it a bit.
Below are some standard security improvements you'll find on lot's of servers.
**A word of caution.**
You can lock yourself out of your server!
Try out some options now on your virtual machines so you get a firm understanding of what they all do.
If you lock yourself out of a remote server you'll have to either gain physical access or reboot the VPS in rescue mode.
For OVH, the VPS provider I tend to use, the rescue mode is detailed [here](https://support.us.ovhcloud.com/hc/en-us/articles/360010553920-How-to-Recover-Your-VPS-in-Rescue-Mode).
With other providers it will be different but similar.
Specifies the protocol versions sshd(8) supports. The possible values are ‘1’ and
‘2’. Multiple versions must be comma-separated. The default is ‘2’. Protocol 1
suffers from a number of cryptographic weaknesses and should not be used. It is
only offered to support legacy devices.
Note that the order of the protocol list does not indicate preference, because the
client selects among multiple protocol versions offered by the server. Specifying
“2,1” is identical to “1,2”.
```
#### Root login
Most systems we install, and the ones you'll deploy later, perform system management via `sudo` so there is no point in even allowing the `root` user to log in.
We can deny any attempt to log in as root with the following option.
If this option is set to prohibit-password (or its deprecated alias, without-password), password and key‐
board-interactive authentication are disabled for root.
If this option is set to forced-commands-only, root login with public key authentication will be allowed,
but only if the command option has been specified (which may be useful for taking remote backups even if
root login is normally not allowed). All other authentication methods are disabled for root.
If this option is set to no, root is not allowed to log in.
```
#### Key only login
Once you properly understand how to do key based login it's wise to disable password login all together for internet facing servers.
This protects you for [bruteforce](https://en.wikipedia.org/wiki/Brute-force_attack) attacks and script kiddies.
On a LAN you can get away with leaving them but I would still advise to keep it key only as we'll later see how an attacker can forward your ssh server to an off-site remote server.
Here I would put no to override the default.
```
PasswordAuthentication
Specifies whether password authentication is allowed. The default is yes.
```
#### Allow only specific users and groups
On systems with lot's of users and groups it might be wise to only permit certain groups and/or users.
Messing with this setting is a common way of locking oneself out of a server so think before you restart sshd.
It's worth noting that upon a restart of your sshd service, your active connection is **not** interrupted so keep it open and try a login from a different terminal.
The optional rdomain qualifier requests sshd(8) listen in an explicit routing domain. If port is not
specified, sshd will listen on the address and all Port options specified. The default is to listen on
all local addresses on the current default routing domain. Multiple ListenAddress options are permitted.
For more information on routing domains, see rdomain(4).
```
#### Maximum of authentication tries
You can limit the amount of tries a user has before the connection is canceled by the server but **watch out with this one**.
It acts differently from how you think it does!
When a user presents himself to the server, every key in their `~/.ssh/` is presented one by one to the server and each key is a try.
So if you set this value too low you might lock yourself out in the future without realizing why.
Imagine you only have one key, then everything is fine with a low value but if later down the line you create more keys this could become a problem and I guarantee you it will take you a while to figure it out.
```
MaxAuthTries
Specifies the maximum number of authentication attempts permitted per connection. Once the number of
failures reaches half this value, additional failures are logged. The default is 6.
```
Have a look at [this](https://unix.stackexchange.com/questions/418582/in-sshd-config-maxauthtries-limits-the-number-of-auth-failures-per-connection) for a more detailed explanation of **what** counts as a **try**.
### Some *fun* stuff
You can set banner and motd (message of the day) files that will be shown to the user upon login.
This is what bandit uses to draw their ASCII banner when you log in.
```
Banner
The contents of the specified file are sent to the remote user before authentication is allowed. If the
argument is none then no banner is displayed. By default, no banner is displayed.
PrintMotd
Specifies whether sshd(8) should print /etc/motd when a user logs in interactively. (On some systems it
is also printed by the shell, /etc/profile, or equivalent.) The default is yes.
The above example is not *that* bad but we can do the same with **every** server or service on an internal network!
We can expose internal ssh servers to the outside world like this.
It must be noted that in the logs of the **internal** server or service, all incoming connections will originate from the **bad client** in the internal network.
This is both good and bad, you'll be able to pinpoint who is responsible inside your network, but you'll have to dig deeper to find out *where* the data is going to.
**Let's expose an internal ssh server to the web!**
The remote server issue is a bit more problematic but there is an easy fix.
The way I resolve it is by adding a dedicated reverse ssh user account on the remote server with a dedicated ssh key pair.
Let's call this one `bridgy`.
In the `~/.ssh/authorized_keys` I add the dedicated public key
I copy the **private** key to the `bridgy` account to all the clients I want initiate tunnels from.
Up until now nothing is different compared to our starting point, it's even worse from a security point of view, but the solution is both magical and simple.
Every client that has the private key to the `bridgy` account can now connect to the server and get's a shell but we have control over *which* shell they get serverside.
If we change the default shell of `bridgy` to `/bin/false` they will never get a shell but the tunnel will still work!
So in short:
1. add a dedicated user account on the server
2. deploy ssh keys
3. set the user's login shell to `/bin/false`
You can further control this one specific user with `Match` blocks in the `sshd_config` file of the server in case you want to.