Open SSH port a bad idea on a Raspberry Pi?

In terms of security, three additional methods come to my mind.

A: use public key authentication

To add to security, you can set up your SSH server to use public key authentication. That is, either additionally to or instead of a strong password, the connection will be opened only if the SSH client provides the private key which matches the public key on the server. Even if an attacker could gain the public key somehow, he could not recover the private key from that. However, this will not hide your port from port scanners.

B: use a different port

Furthermore, I made good experience in terms of less port scans with configuring the SSH server to listen to a different port than 22. The corresponding, default configuration option in /etc/ssh/sshd_config is

Port 22

You could change that to, say 54322:

Port 54322

Remember to re-start the SSH server afterwards; depending on the Linux on your Raspberry, it might be one of

# service sshd restart
# systemctl restart sshd

(The # sign, if not in a file, shall denote a root prompt here in my examples.)

Don't worry, your current SSH session will stay active. It might be worth a try to open a second SSH session to port 54322 to see if login still works. Remember to

  • set your SSH client to the new port
  • if applicable, forward the new port in your internet router to the Raspberry Pi

C: close the port and open it only upon your request

If you really do not want to show "the internet" that you have this port open, have a look at port knocking daemons, e. g. knockd. Those programs listen to (closed) ports defined by you, and upon a knocking sequence, also defined by you, open a different port, e. g. your SSH port. From a mobile phone or a laptop, you initiate the knocking sequence, and the knock daemon on your Raspberry Pi opens your SSH port, which was not visible at all.

In more detail, port knocking will add a line to your iptables configuration. This line will open up the port on your Raspberry. This also means, that the SSH port must be closed by iptables before. And this means you cannot login via SSH.

An example knockd.conf could look like that:

[openclosessh]
    sequence    = 1000,2020,3015,65432
    seq_timeout = 15
    tcpflags    = syn
    start_command   = /usr/local/bin/knockd-open.sh %IP%
    cmd_timeout = 30
    stop_command    = /usr/local/bin/knockd-close.sh %IP%

Also, remember to forward the to-be-knocked ports from your internet router to your Raspberry.

The corresponding open/close scripts could look like that:

#!/bin/bash
# /usr/local/bin/knockd-open.sh
# adds two lines at the top of iptables which allow all incoming and outgoing traffic on tcp port 54322
iptables -I INPUT -s $1 -p tcp --dport 54322 -j ACCEPT
iptables -I OUTPUT -d $1 -p tcp --sport 54322 -j ACCEPT

and

#!/bin/bash
# /usr/local/bin/knockd-close.sh
# deletes those two lines again
iptables -D INPUT -s $1 -p tcp --dport 54322 -j ACCEPT
iptables -D OUTPUT -d $1 -p tcp --sport 54322 -j ACCEPT

Remember to make both scripts executable with chmod +x /usr/local/bin/knockd*. Also, you should start and enable the knockd service with one of

# service knockd start && update-rc.d knockd enable
# systemctl start knockd && systemctl enable knockd

Especially if you employ knocking on a remote computer to which you do not have console access, you might want to use atd to automatically revoke any changes and/or reboot the Raspberry in case of configuration mistakes.

Because iptables will not be stored across reboots automatically, in an example, you could be root (via su) and

# at now + 5 minutes
> reboot
> (hit ctrl-d)
# ./script-which-closes-iptables.sh

An example ./script-which-closes-iptables.sh could look like that (remember to make it executable with chmod +x)

#!/bin/bash
# allow everything on the loopback interface
iptables -A INPUT -i lo -j ACCEPT
# allow only related or established incoming ssh sessions
iptables -A INPUT -p tcp -m state --state RELATED,ESTABLISHED -m tcp --dport 54322 -j ACCEPT
# allow outgoing related or established ssh sessions
iptables -A OUTPUT -p tcp -m state --state RELATED,ESTABLISHED -m tcp --sport 54322 -j ACCEPT
# allow everything on the loopback interface
iptables -A OUTPUT -o lo -j ACCEPT
# drop everything else in and out
iptables -P INPUT DROP
iptables -P OUTPUT DROP

If your SSH session is dying now, the Raspberry will reboot in 5 minutes. If your SSH session is still active, then revoke the pending reboot with

# atq
15 reboot
# atrm 15

If your SSH session is still active, try to login via a second SSH session. That should not work. Then use your mobile phone and knock the ports you configured in /etc/knockd.conf. After that, try again to login via a second SSH session. This time, it should work.

Then you can make your iptables persist a reboot. On your system, you might have to install a package via

# apt-get install iptables-persistent

Save your iptables with

# iptables-save > /etc/iptables/iptables-rules

and enable the iptables service with

# systemctl enable iptables

If your Raspberry Pi has a strong password and strong SSH security, you're fine; attackers can't do anything with SSH if they can't log into it or exploit it. They will find the port for sure, though.

Historical note: In the past, there has been a problem with the SSH configuration; the auto-generated key was predictable. That's been fixed.

If attackers do manage to gain SSH access, they effectively own the device. Then they can use it to do bad things like ARP Poisoning, which allows them to capture and change unencrypted data crossing your network. They could also use the Pi as a launching point for attacks on your other hosts. The Pi is a computer like any other, and you need to be careful to secure it.