The FreeBSD Diary |
(TM) | Providing practical examples since 1998If you buy from Amazon USA, please support us by using this link. |
Putting sshd on a higher port
4 December 2006
|
ssh is the standard protocol used when you want to access a shell on a remote machine. By remote, I mean you are not sitting in front of the console. Remote may mean next door, the next building, or the next continent. ssh is a secure method for talking to that computer. ssh is also a common attack vector. There are many scripts that can be used to attempt to break in via ssh. As a general rule, I greatly restrict access via my packet filter rules. I allow incoming connections only from my other servers, my home, and a few trusted hosts and friends. At worst, this reduces the number of spurious log-in attempts recorded in my logs. At best, it reduces the risk. However, there are some instances when I am not at one of these trusted locations and I still need to ssh in. This is why I also run sshd, unfiltered, on a high random port. This article shows the configuration I used to achieve this. NOTE: If all you want is sshd listening on another port, the configuration below is overkill. If that case, you probabaly want something like this: # grep ListenAddress /etc/ssh/sshd_config ListenAddress 10.2.3.4:22 ListenAddress 10.2.3.4:44444 However, if you want the second sshd to have a different configuration, such as only permit public key authorization, then this article is for you. |
The startup script
|
Here is the startup script from /usr/local/etc/rc.d: #!/bin/sh # # $NetBSD: sshd,v 1.18 2002/04/29 08:23:34 lukem Exp $ # $FreeBSD: src/etc/rc.d/sshd,v 1.8 2005/01/16 03:12:03 obrien Exp $ # # PROVIDE: sshd # REQUIRE: LOGIN cleanvar . /etc/rc.subr name="sshd_higher_port" rcvar=`set_rcvar` command="/usr/sbin/sshd" keygen_cmd="sshd_keygen" start_precmd="sshd_precmd" pidfile="/var/run/${name}.pid" extra_commands="keygen reload" timeout=300 user_reseed() { ( seeded=`sysctl -n kern.random.sys.seeded 2>/dev/null` if [ "x${seeded}" != "x" ] && [ ${seeded} -eq 0 ] ; then warn "Setting entropy source to blocking mode." echo "====================================================" echo "Type a full screenful of random junk to unblock" echo "it and remember to finish with This script is based entirely upon /etc/rc.d/sshd. The diff is here: 12c12 < name="sshd" --- > name="sshd_higher_port" 14c14 < command="/usr/sbin/${name}" --- > command="/usr/sbin/sshd" |
The configuration
|
The truth is, I set up this daemon several months before I wrote this article. When it came time to write, it took me about 5 minutes to figure out where the configuration was done. Finally, I found it in /etc/rc.conf: sshd_enable="YES" sshd_higher_port_enable="YES" sshd_higher_port_flags="-p 57328 -f /usr/local/etc/sshd_config_higher_port" sshd_higher_port_program="/usr/sbin/sshd" NOTE: you probably already have sshd_enable="YES" set. It is best not to duplicate settings. NOTE: My testing shows you can omit the sshd_higher_port_program directive from /etc/rc.conf. If memory serves, it took some time to figure out how to configure this properly and get it to run at boot time. I will explain the flag items:
That second configuration file is pretty much identical to the original /etc/ssh/sshd_config. Here are the items I added to the new configuration file after copying it from the original: Port 57328 PasswordAuthentication no PidFile /var/run/sshd_higher_port.pid ChallengeResponseAuthentication no Looking at this, I see that the port number is specified in both /etc/rc.conf and in the configuration file. I've just implemented this on another server, without the /etc/rc.conf setting for the port, and it works fine. The key point to this configuration is the second line. That completely disables login by password. This means that someone must have an ssh key to login. This setting completely eliminates any dictionary attacks (e.g. password guessing). The attacker *must* have your private ssh key in order to get in. |
Firewall rules
|
Here is the new PF firewall rule I added: pass in quick proto tcp from any to $MYSELF port 57328 flags S/SA synproxy state |
Starting the daemon
|
This command started the daemon: # /usr/local/etc/rc.d/sshd_higher_port start Starting sshd_higher_port. And here is what it looks like when running: # ps auwx | grep sshd root 871 0.0 0.2 3520 1836 ?? Is 9Nov06 0:02.59 /usr/sbin/sshd root 89864 0.0 0.3 6244 2840 ?? Is 7:40AM 0:00.05 sshd: dan [priv] (sshd) dan 89870 0.0 0.3 6224 2852 ?? S 7:41AM 0:00.36 sshd: dan@ttyp0 (sshd) root 90687 0.0 0.3 3520 2584 ?? Ss 7:59AM 0:00.00 /usr/sbin/sshd -f /usr/local/etc/sshd_config_higher_port # |
Testing the theory
|
To test that passwords are not accepted, I did this: $ ssh -p 57328 myserver.example.org Enter passphrase for key '/home/dan/.ssh/id_dsa': Permission denied (publickey). At the prompt, I pressed enter. If passwords are accepted, I would have been presented with a password prompt, like this: $ ssh xeon Enter passphrase for key '/home/dan/.ssh/id_dsa': Password: |
|
Convenience versus risk
|
What I have done is a trade off between convenience and risk. It is more convenient to use the regular port (22). But it is annoying to get all the failed login attempts in my logs. The higher port is still wide open, but it is much less likely to get any login attempts. What would you prefer to do? Please leave your comments. |