On est d’accord que la meilleure sécurité, si on doit laisser un port SSH d’ouvert, n’est ni de le changer ni de le masquer mais tout simplement d’utiliser une clé.
Car le changer ne fait que se prémunir contre pas mal de scripts/scanners qui par défaut ciblent le port 22. Le cacher, ce qu’on va voir ici, ne protège pas contre l’analyse du trafic de la machine (qui fera ressortir les commandes d’accès au « vrai » port SSH). Mais c’est mieux que rien et permet de se prémunir des brute forces basiques à partir de scripts.
Le port knocking consiste donc à masquer son port SSH et à y accéder par un enchainement de requêtes sur des ports précis (par exemple 1000 puis 124 puis 312 et enfin on tombe sur le port SSH). C’est le même principe que dans les vieux films d’espionnage avec une séquence particulière lorsqu’on frappe sur une porte, pour que l’autre comprenne le message et nous ouvre :)
Bref. C’est pas une révolution, c’est pas magique, mais plutôt simple à mettre en place et relativement efficace et ça se nomme Knock.
Précisons que cette méthode nécessite d’avoir de quoi faire ces commandes successives lors de la connexion SSH depuis le client vers le serveur. Je ne sais pas faire sous Windows aussi ce tutoriel ne concerne que les personnes sous Linux (et OSX je suppose). Le tutoriel est effectué sur un serveur Debian et un client Archlinux.
EDIT : bonne nouvelle pour les Windowsiens :)
Configuration du serveur
Knock va être chargé d’ouvrir les ports. Il convient donc de les fermer via IPtables. Cette manipulation comporte un risque majeur : celui de vous retrouver à la porte de votre machine si vous n’autorisez pas déjà les connexions établies.
En effet, fermer tous les ports entrants via IPtables revient à fermer aussi le port SSH et donc votre accès actuel. Il faut donc commencer par autoriser les accès en cours avant de fermer les ports.
On va s’assurer que le serveur n’aura pas de souci à se parler à lui-même (services internes) :
sudo iptables -A INPUT -i lo -j ACCEPT
On autorise ensuite les connexions entrantes déjà établies (dont le SSH en cours) :
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
ATTENTION, sans cette règle vous n’aurez plus accès à votre machine !!! (Sauf via un Rescue Mod où vous pourrez virer les règles IPtables)
On ajoute ensuite une règle par service entrant qui doit rester visible. Pas le SSH évidemment, puisque lui on veut le cacher, mais par exemple le serveur Web (ports 80 et/ou 443), le serveur FTP (port 21) etc.
La règle est la même pour tous, il faut juste changer le port (PORT) et éventuellement le protocole TCP par UDP, selon vos configurations (souvent pour OpenVPN par exemple) :
sudo iptables -A INPUT -p tcp --dport PORT -j ACCEPT
Exemple avec un serveur Web HTTP classique, donc port 80
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
Exemple pour SickRage qui tournerait sur le port 8081
sudo iptables -A INPUT -p tcp --dport 8081 -j ACCEPT
Exemple pour OpenVPN Server qui tournerait sur le port 913, en UDP
sudo iptables -A INPUT -p udp --dport 913 -j ACCEPT
Et pour terminer on ferme tous les ports (pour les connexions entrantes), sereinement, maintenant qu’on a sécurisé notre accès SSH en cours.
sudo iptables -A INPUT -j DROP
Et pour sauvegarder ces règles, on peut le faire à la main ou :
sudo apt-get install iptables-persistent
Installation et configuration de knock
Knock, enfin son daemon knockd précisément, va se charger d’ouvrir et fermer les ports « intéressants » et le SSH selon votre configuration.
On installe donc knock
sudo apt-get install knockd
Et on le configure. Ce qui se fera via le fichier /etc/knockd.conf
sudo nano /etc/knockd.conf
Ce qui nous donne ce fichier, que nous allons remplir :
[options] UseSyslog [openSSH] sequence = 7000,8000,9000 seq_timeout = 5 command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT tcpflags = syn [closeSSH] sequence = 9000,8000,7000 seq_timeout = 5 command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT tcpflags = syn
- sequence : l’ordre des ports à « frapper » avant d’arriver au port SSH
- seq_timeout : durée d’ouverture des ports, qui sont ensuite refermés par knockd
- commande : autorisation de l’accès au port SSH pour notre IP dans IPtables
- tcpflags : SYN = demande de synchronisation ou établissement de connexion
Et bien entendu démarche effectuée une 1ère fois en entrée puis en sens inverse en sortie. Comme quand on ouvre et ferme une porte. Ainsi depuis la machine cliente vous devrez lancer la commande knock 2 fois : la 1ère pour ouvrir les accès et la seconde pour les fermer. Chronophage mais aussi un tantinet risqué si vous oubliez de les refermer.
Nous allons par conséquent modifier légèrement la configuration de knockd sur le serveur afin qu’il referme tout lui-même automatiquement.
[SSH] sequence = 7000,8000,9000 seq_timeout = 5 tcpflags = syn start_command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT cmd_timeout = 5 stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
- start_command : autorisation de l’accès au port SSH pour notre IP dans IPtables
- cmd_timeout : délai de fermeture des ports par knock
- stop_command : annulation de l’autorisation de l’accès au port SSH pour notre IP dans IPtables
Pour l’exemple je vais utiliser le port SSH 2016 et les ports 1978, 2000 et 2015 pour y accéder. Je vous recommande de mettre un timeout un peu plus long que 5 secondes pour parer à d’éventuels souci de latence entre le serveur et vous. Disons que 20 secondes est plutôt sécurisant.
Mon fichier de configuration ressemble de fait à ceci :
[SSH] sequence = 1978,2000,2015 seq_timeout = 20 tcpflags = syn start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 2016 -j ACCEPT cmd_timeout = 20 stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 2016 -j ACCEPT
Et pour tester nous lançons ensuite knock
sudo knockd
Ne fermez pas, ne faites pas ctrl + C. Ce n’est pas lancé en fond mais directement, juste pour tester. Si vous fermez, ça l’arrête.
Configuration côté client
Pour se connecter en SSH nous avons maintenant besoin de knock sur la machine cliente. Et ça se trouve normalement dans les paquets de chaque distribution. Dans mon cas Archlinux.
Une fois installé, nous pouvons alors l’utiliser pour nous connecter en SSH, en précisant la combinaison de ports paramétrée sur le serveur. Donc sous la forme suivante :
knock IP -v PORT1 PORT2 PORT3 & SSH -p PORT_SSH [email protected]
Ce qui donne
knock IP -v 1978 2000 2015 & SSH -p 2016 [email protected]
Cette commande remplace donc la commande SSH classique qui aurait été ssh [email protected] -p PORT_SSH
.
Et nous pouvons alors voir que knock va bien « frapper » aux différentes portes, dans le bon ordre, afin d’autoriser ensuite SSH à établir une connexion avec le serveur.
┬─[[email protected]:~]─[19:29:13] ╰─>$ knock xxx.xxx.xxx.xxx -v 1978 2000 2015 & ssh -p 2016 [email protected] hitting tcp xxx.xxx.xxx.xxx:1978 hitting tcp xxx.xxx.xxx.xxx:2000 hitting tcp xxx.xxx.xxx.xxx:2015 [email protected]'s password: The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Sat Mar 5 19:28:11 2016 from xxx.xxx.xxx.xxx [email protected]:~$
Et voilou :)
Bien entendu ça fonctionne tout aussi bien avec une clé SSH en lieu et place d’un mot de passe.
Lancement du service côté serveur
sudo knockd -d