Port knocking is a way to secure a server by closing firewall ports—even those you know will be used. Those ports are opened on demand if—and only if—the connection request provides the secret knock.
Port Knocking Is a “Secret Knock”
Port knocking is a modern equivalent. If you want people to have access to services on your computer but don’t want to open your firewall to the internet, you can use port knocking. It allows you to close the ports on your firewall that allow incoming connections and have them open automatically when a prearranged pattern of connection attempts is made. The sequence of connection attempts acts as the secret knock. Another secret knock closes the port.
Port knocking is something of a novelty, but it’s important to know it’s an example of security through obscurity, and that concept is fundamentally flawed. The secret of how to access a system is safe because only those in a specific group know it. But once that secret is out—either because it’s revealed, observed, guessed, or worked out—your security is void. You’re better off securing your server in other, stronger ways, like requiring key-based logins for an SSH server.
The most robust approaches to cybersecurity are multilayered, so, perhaps port knocking should be one of those layers. The more layers, the better, right? However, you could argue that port knocking doesn’t add much (if anything) to a properly hardened, secure system.
Cybersecurity is a vast and complicated topic, but you shouldn’t use port knocking as your only form of defense.
To demonstrate port knocking, we’re going to use it to control port 22, which is the SSH port. We’ll use a tool called knockd. Use
apt-get to install this package onto your system if you use Ubuntu or another Debian-based distribution. On other Linux distributions, use your Linux distribution’s package management tool, instead.
Type the following:
sudo apt-get install knockd
You probably already have the iptables firewall installed on your system, but you might need to install the
iptables-persistent package. It handles the automatic loading of saved
Type the following to install it:
sudo apt-get install iptables-persistent
When the IPV4 configuration screen appears, press the space bar to accept the “Yes” option.
Press the space bar again in IPv6 configuration screen to accept the “Yes” option and move on.
The following command tells
iptables to allow established and ongoing connections to continue. We’ll now issue another command to close the SSH port.
If someone is connected by SSH when we issue this command, we don’t want them to be cut off:
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
This command adds a rule to the firewall, that says:
- -A: Append the rule to the firewall rules table. That is, add it to the bottom.
- INPUT: This is a rule about incoming connections.
- -m conntrack: Firewall rules act upon network traffic (packets) that match criteria in the rule. The
iptablesto use extra packet matching modules—in this case, the one called
conntrackworks with the network connection tracking capabilities of the kernel.
- –cstate ESTABLISHED,RELATED: This specifies the type of connection to which the rule will apply, namely ESTABLISHED and RELATED connections. An established connection is one that’s already in progress. A related connection is one that’s made due to an action from an established connection. Perhaps someone who is connected wants to download a file; that might happen over a new connection initiated by the host.
- -j ACCEPT: If the traffic matches the rule, jump to the ACCEPT target in the firewall. In other words, the traffic is accepted and allowed to pass through the firewall.
Now we can issue the command to close the port:
sudo iptables -A INPUT -p tcp --dport 22 -j REJECT
This command adds a rule to the firewall, that says:
- -A: Append the rule to the firewall rules table, i.e., add it to the bottom.
- INPUT: This rule is about incoming connections.
- -p tcp: This rule applies to traffic that uses the Transmission Control Protocol.
- –dport 22: This rule specifically applies to TCP traffic that targets port 22 (the SSH port).
- -j REJECT: If the traffic matches the rule, jump to the REJECT target in the firewall. So, if the traffic is rejected, it’s not permitted through the firewall.
We must start the
netfilter-persistent daemon. We can do so with this command:
sudo systemctl start netfilter-persistent
netfilter-persistent to go through a save and reload cycle, so it loads and controls the
Type the following commands:
sudo netfilter-persistent save
sudo netfilter-persistent reload
You’ve now installed the utilities, and the SSH port is closed (hopefully, without terminating anyone’s connection). Now, it’s time to configure the secret knock.
There are two files you edit to configure
knockd. The first is the following
knockd configuration file:
sudo gedit /etc/knockd.conf
gedit editor opens with the
knockd configuration file loaded.
We’ll edit this file to suit our needs. The sections we’re interested in are “openSSH” and “closeSSH.” The following four entries are in each section:
- sequence: The sequence of ports someone must access to open or close port 22. The default ports are 7000, 8000, and 9000 to open it, and 9000, 8000, and 7000 to close it. You can change these or add more ports to the list. For our purposes, we’ll stick with the defaults.
- seq_timeout: The time period within which someone has to access the ports to trigger it to open or close.
- command: The command sent to the
iptablesfirewall when the open or close action is triggered. These commands either add a rule to the firewall (to open the port) or take it out (to close the port).
- tcpflags: The type of packet each port must receive in the secret sequence. A SYN (synchronize) packet is the first in a TCP connection request, called a three-way handshake.
The “openSSH” section can be read as “a TCP connection request must be made to ports 7000, 8000, and 9000—in that order and within 5 seconds—for the command to open port 22 to be sent to the firewall.”
The “closeSSH” section can be read as “a TCP connection request must be made to ports 9000, 8000, and 7000—in that order and within 5 seconds—for the command to close port 22 to be sent to the firewall.”
The Firewall Rules
The “command” entries in the openSSH and closeSSH sections remain the same, except for one parameter. This is how they’re comprised:
- -A: Append the rule to the bottom of the firewall rules list (for the openSSH command).
- -D: Delete the command from the firewall rules list (for the closeSSH command).
- INPUT: This rule is concerned with incoming network traffic.
- -s %IP%: The IP address of the device requesting a connection.
- -p: Network protocol; in this case, it’s TCP.
- –dport: The destination port; in our example, it’s port 22.
- -j ACCEPT: Jump to the accept target within the firewall. In other words, let the packet drop through the rest of the rules without acting on it.
The knockd Configuration File Edits
The edits we’ll make to the file are highlighted in red below:
We extend the “seq_timeout” to 15 seconds. This is generous, but if someone’s manually firing in connection requests, he might need this much time.
In the “openSSH” section, we change the
-A (append) option in the command to
-I (insert). This command inserts a new firewall rule at the top of the firewall rule list. If you leave the
-A option, it appends the firewall rule list and puts it at the bottom.
Incoming traffic is tested against each firewall rule in the list from the top down. We already have a rule that closes port 22. So, if incoming traffic is tested against that rule before it sees the rule that allows the traffic, the connection is refused; if it sees this new rule first, the connection is allowed.
The close command removes the rule added by openSSH from the firewall rules. SSH traffic is once more handled by the pre-existing “port 22 is closed” rule.
After you make these edits, save the configuration file.
The knockd Control File Edits
knockd control file is altogether simpler. Before we dive in and edit that, though, we need to know the internal name for our network connection; to find it, type this command:
The connection this machine uses to research this article is called
enp0s3. Make a note of the name of your connection.
The following command edits the
knockd control file:
sudo gedit /etc/default/knockd
knockd file in
The few edits we need to make are highlighted in red:
We changed the “START_KNOCKD=” entry to from 0 to 1.
We also removed the hash
# from the start of the “KNOCKD_OPTS=” entry, and replaced “eth1” with the name of our network connection,
enp0s3. Of course, if your network connection is
eth1, you won’t change it.
The Proof Is in the Pudding
It’s time to see if this works. We’ll start the
knockd daemon with this command:
sudo systemctrl start knockd
Now, we’ll jump on another machine and try to connect. We installed the
knockd tool on that computer, too, not because we want to set up port knocking, but because the
knockd package provides another tool called
knock. We’ll use this machine to fire in our secret sequence and do the knocking for us.
Use the following command to send your secret sequence of connection requests to the ports on the port knocking host computer with the IP address 192.168.4.24:
knock 192.168.4.24 7000 8000 9000 -d 500
knock to target the computer at IP address 192.168.4.24 and fire a connection request to ports 7000, 8000, and 9000, in turn, with a
-d (delay) of 500 milliseconds between them.
A user called “dave” then makes an SSH request to 192.168.4.24:
His connection is accepted, he enters his password, and his remote session begins. His command prompt changes from
dave@howtogeek. To log out of the remote computer, he types:
His command prompt returns to his local computer. He uses
knock once more, and this time, it targets the ports in reverse order to close the SSH port on the remote computer.
knock 192.168.4.24 9000 8000 7000 -d 500
Admittedly, this wasn’t a particularly fruitful remote session, but it demonstrates the opening and closing of the port via port knocking and fits in a single screenshot.
So, what did this look like from the other side? The system administrator on the port knocking host uses the following command to view new entries that arrive in the system log:
tail -f /var/log/syslog
- You see three openSSH entries. These are raised as each port is targeted by the remote knock utility.
- When all three stages of the trigger sequence are met, an entry that says “OPEN SESAME,” is logged
- The command to insert the rule into the
iptablesrules list is sent. It permits access via SSH on port 22 from the specific IP address of the PC that gave the correct secret knock (192.168.4.23).
- The user “dave” connects for a few seconds only, and then disconnects.
- You see three closeSSH entries. These are raised as each port is targeted by the remote knock utility—it tells the port knocking host to close port 22.
- After all three stages are triggered, we get the “OPEN SESAME” message again. The command is sent to the firewall to remove the rule. (Why not “CLOSE SESAME” when it’s closing the port? Who knows?)
Now the only rule in the
iptables rules list regarding port 22 is the one we typed at the beginning to close that port. So, port 22 is now closed again.
Knock It on the Head
That’s port knocking’s parlor trick. Treat it as a diversion and don’t do it in the real world. Or, if you must, don’t rely on it as your only form of security.