Comment configurer le frappement de port en utilisant uniquement Iptables sur un VPS Ubuntu

De Get Docs
Aller à :navigation, rechercher

Statut : Obsolète

Cet article couvre une version d'Ubuntu qui n'est plus prise en charge. Si vous utilisez actuellement un serveur exécutant Ubuntu 12.04, nous vous recommandons fortement de mettre à niveau ou de migrer vers une version prise en charge d'Ubuntu :

Raison: Ubuntu 12.04 a atteint sa fin de vie (EOL) le 28 avril 2017 and no longer receives security patches or updates. This guide is no longer maintained.

Voir plutôt : Ce guide peut toujours être utile comme référence, mais peut ne pas fonctionner sur d'autres versions d'Ubuntu. S'il est disponible, nous vous recommandons fortement d'utiliser un guide écrit pour la version d'Ubuntu que vous utilisez. Vous pouvez utiliser la fonctionnalité de recherche en haut de la page pour trouver une version plus récente.


Introduction


Les serveurs connectés à Internet sont soumis à toutes sortes d'attaques et de sondages par des utilisateurs malveillants, des scripts et des robots automatisés. Il est parfois difficile de sécuriser votre serveur contre les attaques sans affecter l'accès légitime à vos services et ressources.

Certains types de services sont censés être visibles et consommables sur l'Internet public. Un exemple de ceci est un serveur Web. D'autres types de services sont généralement utilisés uniquement par l'administrateur système ou un certain nombre de personnes et ne sont pas destinés à être une ressource publique.

Un concept connu sous le nom de port knocking est un moyen de protéger les processus qui correspondent à cette dernière description. Le port knocking fonctionne en couvrant les ports associés à un processus derrière un pare-feu jusqu'à ce qu'une séquence spécifique et prédéterminée d'activité réseau se produise. À ce stade, le service de frappe de port reconfigure le pare-feu pour autoriser l'accès à l'application protégée.

Dans un article précédent, nous avons expliqué comment activer le port knocking via un service de port knocking spécialement conçu. Dans cet article, nous discuterons d'une méthode alternative de configuration du port knocking.

Cette méthode ne repose pas sur une application externe pour modifier les règles du pare-feu. Au lieu de cela, le pare-feu iptables peut tirer parti d'un module de suivi d'état appelé "récent" pour faire tout cela dans les règles de pare-feu elles-mêmes.

Nous allons le configurer sur un droplet Ubuntu 12.04, mais tout type de serveur Linux devrait fonctionner de la même manière.

Noter: Ce tutoriel couvre la sécurité IPv4. Sous Linux, la sécurité IPv6 est maintenue séparément d'IPv4. Par exemple, "iptables" ne gère que les règles de pare-feu pour les adresses IPv4, mais il a un équivalent IPv6 appelé "ip6tables", qui peut être utilisé pour maintenir les règles de pare-feu pour les adresses réseau IPv6.

Si votre VPS est configuré pour IPv6, n'oubliez pas de sécuriser vos interfaces réseau IPv4 et IPv6 avec les outils appropriés. Pour plus d'informations sur les outils IPv6, reportez-vous à ce guide : Comment configurer les outils pour utiliser IPv6 sur un VPS Linux

Présentation du frappement de port Iptables


Avant d'entrer dans la configuration proprement dite, nous décrirons comment fonctionne le module récent et comment il nous permet de créer un système de port knocking.

Iptables peut charger des modules avec le drapeau -m. Le module récent peut suivre les états de connexion. Nous pouvons l'utiliser pour canaliser nos tentatives de connexion de port à travers une séquence de chaînes en fonction du fait que l'utilisateur qui se connecte a atteint chaque port précédemment nécessaire.

Pour notre exemple, nous bloquerons notre démon SSH d'Internet, représenté par notre interface eth0. Nous allons reconfigurer dynamiquement notre pare-feu pour autoriser temporairement les connexions SSH à partir de notre ordinateur une fois qu'une séquence de ports a été "activée" en séquence.

La séquence que nous utiliserons pour ce tutoriel est :

  • 1111
  • 2222
  • 3333

Ces valeurs ne doivent pas être utilisées dans une configuration réelle.

Pour qu'un utilisateur s'authentifie correctement et qu'iptables expose le démon SSH à son adresse IP, il doit atteindre chacun de ces ports en séquence sans envoyer de trafic non séquentiel entre les deux. Si nous implémentons cela, nous aurons réussi à créer un système de frappe de port.

Stratégie de configuration d'Iptables


Afin de mettre en œuvre la conception ci-dessus, nous utiliserons quelques chaînes différentes.

Dans un premier temps, nous accepterons tout le trafic que nous ne souhaitons pas voir soumis au cognement du port. Cela inclut toutes les ressources publiques, comme un serveur Web, ainsi que les connexions établies et les connexions provenant de l'interface locale.

Directement après, nous redirigerons tout le trafic entrant non géré par les règles précédentes vers une nouvelle chaîne, où nous mettrons l'essentiel de nos règles. C'est toujours une bonne idée lors de la mise en œuvre d'un grand ensemble de règles autonome, car il fournit un moyen très simple d'activer ou de désactiver la fonctionnalité, simplement en canalisant le trafic vers ou en contournant la nouvelle chaîne.

Nous appellerons cette chaîne KNOCKING.

Nous utiliserons également d'autres chaînes. Le module récent nous permet de catégoriser différents types de trafic, puis de vérifier si une connexion correspond à une catégorie précédemment définie.

Nous utiliserons cette stratégie pour signaler les adresses IP qui ont envoyé un paquet à la première cible de frappe. Nous aurons une règle qui vérifie ce premier indicateur et vérifie si le deuxième paquet est envoyé à la deuxième cible de frappe. Si c'est le cas, il définit un autre indicateur indiquant qu'il a obtenu deux bonnes réponses jusqu'à présent. Si le deuxième paquet ne correspond pas à la deuxième cible, il est supprimé et l'indicateur est réinitialisé.

Les chaînes supplémentaires fonctionnent en utilisant cette même stratégie consistant à vérifier le drapeau approprié et à le faire passer s'il continue sur le bon chemin. Au final, une fois que le paquet final a été demandé en séquence, le démon SSH est exposé brièvement, uniquement pour l'adresse IP qui a frappé avec succès. Il est ensuite masqué à nouveau automatiquement.

Donc, fondamentalement, si nous considérons nos règles de frappe au port comme des portes différentes pour entrer dans notre service, nous aurons trois portes pour nos trois coups. Cela signifie qu'il existe quatre positions différentes dans lesquelles une adresse IP demandeuse peut se trouver :

  • état initial : il s'agit de l'état dans lequel se trouvent toutes les adresses IP jusqu'à ce qu'elles envoient avec succès un paquet à la première cible de frappe. Cela ne sera pas défini par le module récent et est simplement une façon de se référer à un client qui n'a pas défini d'indicateurs.
  • état auth1 : les adresses qui ont frappé avec succès sur la première cible de frappe sont marquées comme "auth1". À partir de là, le paquet suivant de cet hôte détermine si l'adresse sera remise à l'état initial ou déplacée vers l'état "auth2".
  • état auth2 : les adresses marquées avec cet état ont frappé avec succès sur les première et deuxième cibles dans l'ordre. Le paquet suivant de cet hôte détermine si l'hôte sera remis à l'état initial ou mis à l'état « auth3 ».
  • état auth3 : les adresses qui ont été marquées comme "auth3" ont frappé avec succès sur les trois ports, dans l'ordre, dans le temps imparti. Si une adresse marquée comme "auth3" tente d'accéder au service maintenant (dans la fenêtre qui est fournie), la connexion sera acceptée. Si tout autre trafic est reçu, l'adresse sera renvoyée à l'état initial.

En plus de ces états, qui seront des drapeaux définis par le module récent, chaque porte, ou point de décision, sera implémentée comme une chaîne. Les chaînes peuvent être résumées comme suit :

  • GATE1 : détermine si une adresse dans l'état initial doit être marquée comme "auth1".
  • GATE2 : détermine si une adresse dans l'état "auth1" doit être transformée en "auth2" ou réinitialisée à l'état "initial".
  • GATE3 : détermine si une adresse dans l'état "auth2" doit être signalée comme "auth3" pour autoriser une connexion SSH, ou réinitialisée à l'état "initial".
  • PASSED : cette chaîne est utilisée pour ouvrir brièvement le port du démon SSH pour les clients qui ont frappé avec succès. Tout trafic provenant des clients de cette chaîne qui n'est pas destiné au démon SSH est abandonné, ce qui entraîne la réinitialisation de l'état sur "initial".

Comme vous pouvez le voir, nous avons beaucoup de points de décision ici. Chaque type de trafic dans la chaîne KNOCKING et ses sous-chaînes doit être supprimé (à l'exception du trafic pour le démon SSH provenant de clients knock réussis), qu'il corresponde ou non au port correct. Le signalement interne est la seule chose qui gardera une trace des tentatives réussies et cette logique n'est pas exposée au client.

Ceci est nécessaire pour que la mise en œuvre du port knocking soit valide. Une personne tentant de se connecter ne devrait recevoir aucune rétroaction quant à l'étape du processus dans laquelle elle se trouve ou même si un tel mécanisme est en place.

Configurer le cadre de pare-feu standard


Nous commencerons par établir un cadre de base pour nos connexions. La stratégie dont nous avons parlé ci-dessus sera appliquée à la chaîne INPUT, qui gère toutes les connexions entrantes.

Nous commencerons par vider les règles de pare-feu existantes afin de pouvoir commencer avec une table rase. Avant de vider les règles, c'est toujours une bonne idée de réaffirmer que les politiques par défaut dans une table vide sont « ACCEPTER » afin de maintenir votre connexion actuelle :

sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -F

Cela garantira que nous commençons avec un pare-feu complètement ouvert, que nous pouvons commencer à restreindre.

Avant de commencer à restreindre, nous souhaitons ajouter les chaînes supplémentaires que nous utiliserons :

sudo iptables -N KNOCKING
sudo iptables -N GATE1
sudo iptables -N GATE2
sudo iptables -N GATE3
sudo iptables -N PASSED

À ce stade, nous devrions avoir huit chaînes différentes ! Nous les utiliserons tous sauf les chaînes OUTPUT et FORWARD, qui ne nous concernent pas dans ce contexte.

Tout d'abord, nous devons ajouter le trafic que nous ne voulons pas gérer avec le port knocking à la chaîne INPUT. Nous pouvons commencer par accepter toutes les connexions actuelles, ce qui permettra à notre connexion SSH actuelle de ne pas être affectée :

sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Nous devons également accepter toutes les connexions de la machine locale, car les services ont souvent besoin de communiquer entre eux :

sudo iptables -A INPUT -i lo -j ACCEPT

Si vous avez des services qui doivent rester accessibles de manière externe et publique, comme un serveur Web, ajoutez une règle pour autoriser ce type de connexion en utilisant ce format :

sudo iptables -A ENTRÉE -p protocole --dport port -j ACCEPTER

Dans notre exemple, nous supposerons que nous avons un serveur Web fonctionnant sur le port par défaut 80, et nous autoriserons ce trafic :

sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

Maintenant que nos connexions autorisées de base sont configurées, nous pouvons transférer tout le trafic qui n'a pas été géré dans les règles ci-dessus vers notre chaîne KNOCKING pour effectuer la logique de frappe réelle :

sudo iptables -A INPUT -j KNOCKING

Configurer la première porte


Lorsque nous aurons fini de configurer nos "portes", nous les connecterons toutes à la chaîne KNOCKING pour diriger le trafic à travers nos tests logiques. Avant de faire cela cependant, nous devrions développer nos unités logiques individuelles.

Nous commencerons par définir notre test de frappe initial. Lorsqu'un client se connecte, nous devons simplement voir s'il envoie un paquet à notre première cible. Si tel est le cas, nous signalons que le client a réussi le premier test et abandonnons la connexion. Si ce n'est pas le cas, nous supprimons simplement la connexion.

Nous allons d'abord définir le drapeau sur la bonne tentative de port :

sudo iptables -A GATE1 -p tcp --dport 1111 -m recent --name AUTH1 --set -j DROP

Cette ligne fait plusieurs choses. Pour commencer, il ajoute une règle à la chaîne GATE1. Cette règle correspondra lorsque le protocole utilisé est "tcp" et lorsque le port auquel il tente d'accéder est "1111", notre première cible de frappe.

Si c'est vrai, le module récent (appelé avec -m recent), marque l'adresse IP demandeuse avec le nom AUTH1 (avec la règle --name AUTH1 --set). C'est le drapeau que nous utiliserons pour voir si le deuxième coup correspond. Le paquet est supprimé une fois l'indicateur défini, de sorte que le client ne sache pas si quelque chose s'est passé.

Ensuite, nous allons simplement supprimer tous les autres paquets, car toute information envoyée à cette chaîne est uniquement recherchant le premier paquet correspondant à ce stade :

sudo iptables -A GATE1 -j DROP

Nous avons maintenant notre premier port couvert. Soit les règles correspondent et marquent l'adresse si le port correct est demandé, soit aucune action n'est entreprise et le paquet est simplement supprimé.

Configurer la deuxième porte


La deuxième porte est configurée de la même manière que la première. Il est légèrement plus complexe cependant.

Tout d'abord, la logique pour envoyer le trafic dans cette chaîne existera dans la chaîne principale KNOCKING. Cette chaîne n'a pas à vérifier si le drapeau défini par la première porte correspond, car cela se sera déjà produit.

Cependant, il doit supprimer tous les drapeaux avant de commencer le traitement. S'il ne supprime pas le drapeau, une adresse peut être marquée avec des noms différents, ce qui peut entraîner le succès de l'adresse en scannant simplement vos ports trois fois. Ce n'est certainement pas ce que nous voulons.

Nous utiliserons à nouveau le module récent dans une règle préliminaire, cette fois juste pour effacer le nom :

sudo iptables -A GATE2 -m recent --name AUTH1 --remove

Il s'agit d'une règle de traitement, nous ne prenons donc aucune décision ni aucun saut. Nous supprimons simplement le drapeau actuel (celui qui aurait autorisé le trafic dans cette chaîne) et l'envoyons à la règle suivante.

Maintenant que l'adresse a dépassé notre première règle dans cette chaîne, elle est dans un état propre sans indicateur. À ce stade, nous vérifions si cette tentative de connexion est une correspondance correcte pour la cible de port suivante :

sudo iptables -A GATE2 -p tcp --dport 2222 -m recent --name AUTH2 --set -j DROP

Ceci est géré de la même manière que la première porte. Nous définissons simplement le drapeau AUTH2, indiquant que l'adresse demandeuse a réussi le deuxième test, si le bon port a été frappé. L'indicateur est défini et le paquet est à nouveau abandonné, ne donnant au client aucune indication sur sa progression.

La règle suivante peut sembler un peu étrange au premier abord.

sudo iptables -A GATE2 -j GATE1

Vous pouvez supposer qu'il suffit de laisser tomber le paquet à ce stade est la chose logique à faire. Cependant, cela conduirait à une situation délicate dans un cas spécifique.

Si nous avions une règle « tout supprimer » ici, et que le paquet envoyé à ce stade correspond à la cible de frappe premier, il ne serait pas enregistré comme début de la séquence de frappe.

Par exemple, si notre client touche accidentellement le premier port deux fois, il ne s'enregistrera pas comme correct car le pare-feu verrait la séquence comme ceci :

  • Premier port touché. Le pare-feu marque le premier test réussi. Va vérifier le deuxième port ensuite.
  • Premier port touché. Ne correspond pas à la deuxième règle de port. La séquence est réinitialisée. Va vérifier le premier port ensuite.
  • Deuxième port touché. Ne correspond pas à la règle du premier port. La séquence est réinitialisée. Va vérifier le premier port ensuite.
  • Troisième port touché. Ne correspond pas à la règle du premier port. La séquence est réinitialisée. Va vérifier le premier port ensuite.

Comme vous pouvez le constater, la première, la deuxième et la troisième séquence sont terminées, mais le pare-feu ne sait plus quelles règles il doit vérifier. Dans ce scénario, le client devrait envoyer une requête fictive avant de commencer la séquence réelle juste pour réinitialiser la chaîne si une erreur a été commise.

Pour éviter cette situation, nous n'allons pas simplement supprimer le paquet à ce stade et en finir avec lui. Au lieu de cela, nous tirerons parti de la chaîne GATE1 que nous avons déjà configurée. Comme nous l'avons démontré ci-dessus, nous pouvons simplement renvoyer le trafic qui ne correspondait pas à la deuxième cible de frappe vers la première porte :

sudo iptables -A GATE2 -j GATE1

Cela entraînera la réinitialisation de la position du client dans la séquence de deux manières. Si la demande concerne le premier port, la séquence est redémarrée comme un premier coup réussi. S'il ne s'agit pas du premier port, il est abandonné comme d'habitude. Cela évite la situation ci-dessus.

Configurer la troisième porte


Nous pouvons utiliser ce que nous avons appris de la deuxième porte pour implémenter la troisième porte exactement de la même manière.

Tout d'abord, nous voulons effacer tous les drapeaux qui ont été donnés à notre adresse afin que cette course à travers les chaînes définisse l'état correct sans les drapeaux obsolètes d'avant :

sudo iptables -A GATE3 -m recent --name AUTH2 --remove

Ensuite, nous testerons si la tentative de connexion correspond à la troisième cible de frappe. Si c'est le cas, nous définissons l'indicateur AUTH3, qui indique que le client a réussi tous les coups requis. Comme d'habitude, nous laissons tomber le paquet après.

sudo iptables -A GATE3 -p tcp --dport 3333 -m recent --name AUTH3 --set -j DROP

À partir de là, nous renvoyons à nouveau le trafic qui ne correspondait pas à la troisième cible de frappe vers la première porte pour voir s'il doit compter comme un premier coup réussi pour redémarrer la séquence :

sudo iptables -A GATE3 -j GATE1

À ce stade, les clients qui ont terminé la séquence de frappe correcte doivent être signalés par AUTH3, ce qui nous permettra d'ouvrir facilement le service pour eux dans la chaîne PASSED.

Configurer la chaîne passée


Cette chaîne est utilisée pour ouvrir le démon SSH pendant 30 secondes au client qui a frappé avec succès la séquence correcte.

Nous commençons cela de la même manière que les autres. Le démon SSH ne sera disponible que si le prochain paquet envoyé par le client le demande. Cela oblige les personnes qui tentent au hasard de passer outre les coups à tenter une connexion SSH entre chaque tentative.

Tout d'abord, nous effectuons les réinitialisations habituelles des drapeaux :

sudo iptables -A PASSED -m recent --name AUTH3 --remove

Ensuite, nous acceptons les connexions SSH des utilisateurs qui sont entrés dans cette chaîne :

sudo iptables -A PASSED -p tcp --dport 22 -j ACCEPT

Une fois de plus, nous renvoyons tout le trafic qui ne correspond pas à travers notre première chaîne pour voir s'il correspond à la première cible de frappe de port :

sudo iptables -A PASSED -j GATE1

Maintenant, toutes nos sous-chaînes sont configurées, sauf notre chaîne KNOCKING générale, qui transmettra le trafic à ces chaînes individuelles.

Configurer la chaîne de frappe


Maintenant que toutes nos sous-chaînes sont configurées, nous pouvons les rattacher à notre chaîne KNOCKING générale et créer la logique de transmission du trafic.

Tout d'abord, nous transmettrons le trafic des clients qui ont réussi tous les coups directement dans la chaîne PASSED.

Nous avons cependant quelques options. Nous pouvons implémenter une limite de temps pour ne donner au client réussi qu'une fenêtre de 30 secondes pour se connecter au démon. Après cela, la règle ne correspondra plus avec succès.

sudo iptables -A KNOCKING -m recent --rcheck --seconds 30 --name AUTH3 -j PASSED

Ensuite, nous testerons chacun des autres drapeaux du plus restrictif au moins. Nous pouvons également ajouter un délai de 10 secondes avant l'expiration du coup précédent. Cela obligera nos clients à terminer l'étape suivante du knock dans les 10 secondes, puis à se connecter au démon SSH dans les 30 secondes supplémentaires.

sudo iptables -A KNOCKING -m recent --rcheck --seconds 10 --name AUTH2 -j GATE3
sudo iptables -A KNOCKING -m recent --rcheck --seconds 10 --name AUTH1 -j GATE2

Maintenant, nous voulons renvoyer tout le trafic qui n'a pas encore correspondu à GATE1, comme d'habitude. Cela attrapera toute tentative pour le premier coup :

sudo iptables -A KNOCKING -j GATE1

Cela définira essentiellement une politique de suppression par défaut pour notre chaîne KNOCKING en ajoutant implicitement la logique GATE1 à la fin de la chaîne KNOCKING.

À ce stade, nous avons toutes nos chaînes de frappe en place. Nous avons ajouté une structure supplémentaire pour compartimenter notre logique. Toute la structure de la chaîne KNOCKING et ses sous-chaînes sont reliées à notre chaîne d'entrée régulière.

À ce stade, notre mécanisme de frappe de port est configuré. Il est temps de le tester.

Testez notre frappe au port


Il existe un certain nombre d'utilitaires qui peuvent être utilisés pour générer les paquets TCP dont nous avons besoin pour notre configuration de frappe de port. Nous utiliserons la commande nmap, car elle est présente sur la plupart des systèmes par défaut.

Nmap utilise les paquets TCP par défaut. Nous devons cependant lui dire de laisser tomber la partie découverte de l'hôte de son comportement par défaut afin que ces paquets n'interfèrent pas avec notre frappe. De plus, nous voulons que notre connexion expire après seulement une seconde, afin que nous puissions continuer jusqu'au coup suivant.

Avec ces exigences, un seul coup peut ressembler à ceci. Nous utiliserons notre première cible de frappe comme exemple :

nmap -Pn --host_timeout 201 --max-retries 0 -p 1111 votre_serveur

Par conséquent, toute notre séquence de frappe pourrait être représentée par ces commandes :

nmap -Pn --host_timeout 201 --max-retries 0 -p 1111 votre_serveur nmap -Pn --host_timeout 201 --max-retries 0 -p 2222 votre_serveur nmap -Pn --host_timeout 201 --max-retries 0 -p 3333 votre_serveur

Nous aurions alors 30 secondes pour nous connecter avec notre client SSH.

Nous pouvons tirer parti de quelques scripts bash vraiment basiques pour automatiser un peu cela. Nous pouvons utiliser une boucle "for" pour parcourir notre séquence de ports, puis la transmettre au client SSH :

 pour x dans 1111 2222 3333 ;  do nmap -Pn --host_timeout 201 --max-retries 0 -p $x your_server && sleep 1;  terminé && utilisateur ssh @ votre_serveur

Cela frappera sur le premier port, attendra une seconde, frappera sur le suivant, et ainsi de suite jusqu'à ce que la séquence soit terminée. Il tentera alors de se connecter au démon SSH du serveur.

Nous pouvons mettre cela dans un fichier pour le nettoyer un peu. Nous l'appellerons knock_client. Créez-le dans un éditeur de texte :

 nano knock_client
  #!/bin/bah
ports="1111 2222 3333" hôte=" votre_serveur "
for x in $ports do nmap -Pn --host_timeout 201 --max-retries 0 -p $x $host sleep 1 done utilisateur ssh @${host}

Enregistrez et fermez le fichier.

Rendez le fichier exécutable avec cette commande :

chmod 755 knock_client

Maintenant, nous pouvons nous connecter à notre serveur en tapant :

./knock_client

Maintenant que nous avons vérifié que nos règles fonctionnent comme prévu, nous pouvons rendre nos règles de pare-feu persistantes en téléchargeant un package séparé sur notre serveur :

sudo apt-get install iptables-persistent

Nous pouvons appliquer nos règles au démarrage en activant ce service :

sudo service iptables-persistent start

Conclusion


À présent, vous devriez disposer d'un système de frappe de port entièrement opérationnel en utilisant uniquement les fonctionnalités incluses dans le pare-feu iptables. Cela a quelques avantages. Tout d'abord, iptables est très couramment utilisé et est souvent audité pour les problèmes de sécurité. Cela signifie que tant que vos règles font ce que vous pensez qu'elles font, cela devrait être assez sûr.

Un autre avantage que cette configuration offre par rapport à un démon de frappe séparé est qu'il n'y a aucune possibilité que le service de frappe échoue et vous laisse exclu de votre serveur. Si le service iptables échoue, vous pourrez au moins entrer dans votre serveur pour le réparer.

Par Justin Ellingwood