One place for hosting & domains

      Comment configurer Packet Filter (PF) sous FreeBSD 12.1


      L’auteur a choisi le COVID-19 Relief Fund pour recevoir un don dans le cadre du programme Write for DOnations.

      Introduction

      Le pare-feu est sans doute l’une des plus importantes lignes de défense contre les cyberattaques. La capacité de configurer un pare-feu à partir de zéro est une compétence qui donne à l’administrateur le pouvoir de prendre le contrôle de ses réseaux.

      Packet Filter (PF) est une application de pare-feu renommée qui est maintenue en amont par le projet OpenBSD axé sur la sécurité. Il s’exprime plus précisément comme un outil de filtrage de paquets, d’où son nom, et il est connu pour sa syntaxe simple, sa facilité d’utilisation et ses nombreuses fonctionnalités. PF est un pare-feu à état par défaut, qui stocke des informations sur les connexions dans une table d’état accessible à des fins d’analyse. PF fait partie du système de base de FreeBSD et est soutenu par une forte communauté de développeurs. Bien qu’il existe des différences entre les versions FreeBSD et OpenBSD de PF concernant les architectures de noyau, en général leur syntaxe est similaire. En fonction de leur complexité, les règlements communs peuvent être modifiés pour fonctionner sur l’une ou l’autre distribution avec relativement peu d’efforts.

      Dans ce tutoriel, vous allez construire un pare-feu à partir de zéro sur un serveur FreeBSD 12.1 avec PF. Vous concevrez un ensemble de règles de base qui pourra servir de modèle pour de futurs projets. Vous explorerez également certaines des fonctionnalités avancées de PF telles que l’hygiène des paquets, la prévention de la force brute, la surveillance et l’enregistrement, ainsi que d’autres outils tiers.

      Conditions préalables

      Avant de débuter ce tutoriel, vous aurez besoin des éléments suivants :

      • Un serveur 1G FreeBSD 12.1 (soit ZFS ou UFS). Vous pouvez utiliser notre tutoriel Comment démarrer avec FreeBSD pour configurer votre serveur selon vos préférences.
      • FreeBSD n’a pas de pare-feu activé par défaut – la personnalisation est une caractéristique de l’éthique de FreeBSD. Par conséquent, lorsque vous lancez votre serveur pour la première fois, vous avez besoin d’une protection temporaire pendant que PF est en cours de configuration. Si vous utilisez DigitalOcean, vous pouvez activer votre pare-feu dans le nuage immédiatement après avoir fait tourner le serveur. Reportez-vous au tutoriel Démarrage rapide du pare-feu de DigitalOcean pour obtenir des instructions sur la configuration d’un pare-feu en nuage. Si vous utilisez un autre fournisseur de services en ligne, déterminez le chemin le plus rapide vers une protection immédiate avant de commencer. Quelle que soit la méthode que vous choisissez, votre pare-feu temporaire doit autoriser uniquement le trafic SSH entrant et peut autoriser tous les types de trafic sortant.

      Étape 1 – Établissement de votre règlement préliminaire

      Vous commencerez ce tutoriel en rédigeant un ensemble de règles préliminaires qui assurent une protection de base et l’accès aux services essentiels sur l’internet. À ce stade, vous avez un serveur FreeBSD 12.1 en cours d’exécution avec un pare-feu en nuage actif.

      Il existe deux approches pour construire un pare-feu : le refus par défaut et le permis par défaut. L’approche de refus par défaut bloque tout le trafic, et n’autorise que ce qui est spécifié dans une règle. L’approche du permis par défaut fait exactement le contraire : il passe tout le trafic, et ne bloque que ce qui est spécifié dans une règle. Vous utiliserez l’approche de refus par défaut.

      Les règlements PF sont écrits dans un fichier de configuration nommé /etc/pf.conf, qui est également son emplacement par défaut. Il est possible de stocker ce fichier ailleurs, à condition que cela soit spécifié dans le Fichier de configuration /etc/rc.conf. Dans ce tutoriel, vous utiliserez l’emplacement par défaut.

      Connectez-vous à votre serveur avec votre utilisateur non racine :

      • ssh freebsd@your_server_ip

      Créez ensuite votre fichier /etc/pf.conf :

      Remarque : Si vous souhaitez voir l’ensemble complet du règlement de base à un moment quelconque du tutoriel, vous pouvez vous référer aux exemples de l’étape 4 ou de l’étape 8.

      PF filtre les paquets en fonction de trois actions principales : bloquer, passer et faire correspondre. Lorsqu’elles sont combinées avec d’autres options, elles forment des règles. Une mesure est prise lorsqu’un paquet répond aux critères spécifiés dans une règle. Comme vous pouvez vous en douter, les règles de passage et de blocage passeront et bloqueront le trafic. Une règle de correspondance effectue une action sur un paquet lorsqu’elle trouve un critère de correspondance, mais ne le passe pas ou ne le bloque pas. Par exemple, vous pouvez effectuer une traduction d’adresse réseau (NAT) sur un paquet correspondant sans le transmettre ou le bloquer, et il restera là jusqu’à ce que vous lui demandiez de faire quelque chose dans une autre règle, comme le router vers une autre machine ou une autre passerelle.

      Ensuite, ajoutez la première règle à votre fichier /etc/pf.conf :

      /etc/pf.conf

      block all
      

      Cette règle bloque toute forme de trafic dans toutes les directions. Comme il ne spécifie pas de direction, il indique par défaut les entrées et les sorties. Cette règle est légitime pour un poste de travail local qui doit être isolé du monde, mais elle est largement inapplicable et ne fonctionnera pas sur un serveur distant car elle ne permet pas le trafic SSH. En fait, si vous aviez activé PF, vous vous seriez enfermé hors du serveur.

      Révisez votre fichier /etc/pf.conf pour autoriser le trafic SSH avec la ligne surlignée suivante :

      /etc/pf.conf

      block all
      pass in proto tcp to port 22
      

      Remarque : vous pouvez également utiliser le nom du protocole :

      /etc/pf.conf

      block all
      pass in proto tcp to port ssh
      

      Par souci de cohérence, nous utiliserons les numéros de port, à moins qu’il n’y ait une raison valable de ne pas le faire. Vous trouverez une liste détaillée des protocoles et de leurs numéros de port respectifs dans le fichier /etc/services, que nous vous invitons à consulter.

      PF traite les règles de manière séquentielle de haut en bas, donc votre règlement actuel bloque initialement tout le trafic, mais le passe ensuite si les critères de la ligne suivante sont respectés, ce qui dans ce cas est le trafic SSH.

      Vous pouvez maintenant utiliser le SSH sur votre serveur, mais vous continuez à bloquer toute forme de trafic sortant. Cela pose problème car vous ne pouvez pas accéder à des services essentiels depuis l’internet pour installer des paquets, mettre à jour vos paramètres de temps, etc.

      Pour y remédier, ajoutez la règle surlignée suivante à la fin de votre fichier /etc/pf.conf :

      /etc/pf.conf

      block all
      pass in proto tcp to port { 22 }
      pass out proto { tcp udp } to port { 22 53 80 123 443 }
      

      Votre ensemble de règles autorise désormais le trafic sortant SSH, DNS, HTTP, NTP et HTTPS, ainsi que le blocage de tout trafic entrant (à l’exception du SSH). Vous placez les numéros de port et les protocoles entre parenthèses, ce qui forme une liste dans la syntaxe PF, vous permettant d’ajouter d’autres numéros de port si nécessaire. Vous ajoutez également une règle de distribution pour le protocole UDP sur les ports 53 et 123 car le DNS et le NTP basculent souvent entre les protocoles TCP et UDP.   Vous avez presque terminé l’ensemble des règles préliminaires, et il vous suffit d’ajouter quelques règles pour obtenir une fonctionnalité de base.

      Complétez le règlement préliminaire avec les règles mises en évidence :

      Preliminary Ruleset /etc/pf.conf

      set skip on lo0
      block all
      pass in proto tcp to port { 22 }
      pass out proto { tcp udp } to port { 22 53 80 123 443 }
      pass out inet proto icmp icmp-type { echoreq }
      

      Enregistrez et quittez le fichier.

      Vous créez une règle de saut définie pour le dispositif de bouclage car il n’a pas besoin de filtrer le trafic et risquerait d’amener votre serveur à un crawl. Vous ajoutez une règle pass out inet pour le protocole ICMP, qui vous permet d’utiliser l’utilitaire ping(8) pour le dépannage. L’option inet représente la famille d’adresses IPv4.

      L’ICMP est un protocole de messagerie polyvalent utilisé par les appareils en réseau pour divers types de communication. L’utilitaire ping, par exemple, utilise un type de message appelé echo request, que vous avez ajouté à votre liste icmp_type. Par mesure de précaution, vous n’autorisez que les types de messages dont vous avez besoin pour éviter que des appareils indésirables n’entrent en contact avec votre serveur. À mesure que vos besoins augmentent, vous pouvez ajouter d’autres types de messages à votre liste.

      Vous disposez désormais d’un règlement de fonctionnement qui fournit des fonctionnalités de base à la plupart des machines. Dans la section suivante, nous allons confirmer que tout fonctionne correctement en activant PF et en testant votre règlement préliminaire.

      Étape 2 – Test de votre règlement préliminaire

      Au cours de cette étape, vous testerez votre règlement préliminaire et ferez la transition de votre pare-feu dans le nuage à votre pare-feu PF, permettant à PF de prendre complètement le relais. Vous activerez votre règlement avec l’utilitaire pfctl, qui est l’outil de ligne de commande intégré de PF, et la principale méthode d’interface avec PF. 

      Les règlements de la PF ne sont rien d’autre que des fichiers texte, ce qui signifie que le chargement de nouveaux règlement n’implique aucune procédure délicate. Vous pouvez charger un nouveau règlement, et l’ancien est parti. Il est rarement, voire jamais, nécessaire de vider un règlement existant.

      FreeBSD utilise un réseau de scripts shell connu sous le nom de système rc pour gérer la façon dont les services sont démarrés au démarrage ; nous spécifions ces services dans divers fichiers de configuration rc. Pour les services globaux tels que PF, vous utilisez le fichier /etc/rc.conf. Comme les fichiers rc sont essentiels au bien-être d’un système FreeBSD, ils ne doivent pas être édités directement. A la place, FreeBSD fournit un utilitaire en ligne de commande connu sous le nom de sysrc, conçu pour vous aider à modifier ces fichiers en toute sécurité.

      Activons PF en utilisant l’utilitaire de ligne de commande sysrc :

      • sudo sysrc pf_enable="YES"
      • sudo sysrc pflog_enable="YES"

      Vérifiez ces changements en imprimant le contenu de votre fichier /etc/rc.conf :

      Vous verrez le résultat suivant :

      Output

      pf_enable="YES" pflog_enable="YES"

      Vous activez également le service pflog, qui, à son tour, active le démon pflogd pour se connecter à PF. Vous travaillerez sur la connexion dans une étape ultérieure.

      Vous spécifiez deux services globaux dans votre fichier /etc/rc.conf, mais ils ne s’initialiseront pas tant que vous n’aurez pas redémarré le serveur ou que vous ne les aurez pas démarrés manuellement. Redémarrez le serveur afin de pouvoir également tester votre accès SSH.

      Démarrez PF en redémarrant le serveur :

      La connexion sera interrompue. Donnez-lui quelques minutes pour mettre à jour.

      Maintenant, SSH est de retour sur le serveur :

      • ssh freebsd@your_server_ip

      Bien que vous ayez initialisé vos services PF, vous n’avez pas encore chargé votre règlement /etc/pf.conf, ce qui signifie que votre pare-feu n’est pas encore actif.

      Chargez le règlement avec pfctl :

      • sudo pfctl -f /etc/pf.conf

      S’il n’y a pas d’erreurs ou de messages, cela signifie que votre règlement ne contient pas d’erreurs et que le pare-feu est actif.

      Maintenant que PF fonctionne, vous pouvez détacher votre serveur de votre pare-feu dans le nuage. Cela peut se faire dans le panneau de contrôle de votre compte DigitalOcean en retirant votre Droplet du portail de votre pare-feu dans le nuage. Si vous utilisez un autre fournisseur de services en nuage, assurez-vous que ce que vous utilisez pour la protection temporaire est désactivé. Faire fonctionner deux pare-feu différents sur un serveur posera presque certainement des problèmes.

      Pour une bonne mesure, redémarrez votre serveur :

      Après quelques minutes, SSH revient sur votre serveur :

      • ssh freebsd@your_server_ip

      PF est maintenant votre pare-feu. Vous pouvez vous assurer qu’il fonctionne en accédant à certaines données avec l’utilitaire pfctl.

      Voyons quelques statistiques et compteurs avec pfctl -si :

      Vous passez devant les drapeaux -si, qui signifient show info. C’est l’une des nombreuses combinaisons de paramètres de filtrage que vous pouvez utiliser avec pfctl pour analyser les données concernant l’activité de votre pare-feu.

      Vous verrez les données tabulaires suivantes (les valeurs varient d’une machine à l’autre) :

      Output

      Status: Enabled for 0 days 00:01:53 Debug: Urgent State Table Total Rate current entries 5 searches 144 1.3/s inserts 11 0.1/s removals 6 0.1/s Counters match 23 0.2/s bad-offset 0 0.0/s fragment 0 0.0/s short 0 0.0/s normalize 0 0.0/s memory 0 0.0/s bad-timestamp 0 0.0/s congestion 0 0.0/s ip-option 0 0.0/s proto-cksum 0 0.0/s state-insert 0 0.0/s state-limit 0 0.0/s src-limit 0 0.0/s synproxy 0 0.0/s map-failed 0 0.0/s

      Comme vous venez d’activer votre ensemble de règles, vous ne verrez pas encore beaucoup d’informations. Cependant, ce résultat montre que PF a déjà enregistré 23 règles correspondantes, ce qui signifie que les critères de votre ensemble de règles ont été adaptés 23 fois. La sortie confirme également que votre pare-feu fonctionne.

      Votre règlement permet également au trafic sortant d’accéder à certains services essentiels de l’internet, y compris l’utilitaire ping.

      Vérifions la connectivité internet et le service DNS avec un ping contre google.com : 

      Depuis que vous avez lancé le drapeau du compte-c 3, vous verrez trois réponses de connexion réussies :

      Output

      PING google.com (172.217.0.46): 56 data bytes 64 bytes from 172.217.0.46: icmp_seq=0 ttl=56 time=2.088 ms 64 bytes from 172.217.0.46: icmp_seq=1 ttl=56 time=1.469 ms 64 bytes from 172.217.0.46: icmp_seq=2 ttl=56 time=1.466 ms --- google.com ping statistics --- 3 packets transmitted, 3 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 1.466/1.674/2.088/0.293 ms

      Assurez-vous que vous pouvez accéder au dépôt pkgs avec la commande suivante :

      S’il y a des paquets à mettre à niveau, allez-y, mettez-les à niveau.

      Si ces deux services fonctionnent, cela signifie que votre pare-feu fonctionne et que vous pouvez maintenant continuer. Bien que votre ensemble de règles préliminaires offre une protection et des fonctionnalités, il reste un ensemble de règles élémentaires et pourrait bénéficier de quelques améliorations. Dans les autres sections, vous compléterez votre règlement de base et utiliserez certaines des fonctionnalités avancées de PF.

      Au cours de cette étape, vous vous appuierez sur l’ensemble de règles préliminaires pour compléter votre règlement de base. Vous réorganiserez certaines de vos règles et travaillerez avec des concepts plus avancés.

      Incorporation de macros et de tableaux

      Dans votre ensemble de règles préliminaires, vous avez codé en dur tous vos paramètres dans chaque règle, c’est-à-dire les numéros de port qui composent les listes. Cela peut devenir ingérable à l’avenir, en fonction de la nature de vos réseaux. Pour des raisons d’organisation, PF comprend des macros, des listes et des tableaux. Vous avez déjà inclus des listes directement dans vos règles, mais vous pouvez également les séparer de vos règles et les affecter à une variable à l’aide de macros.

      Ouvrez votre fichier pour transférer certains de vos paramètres dans des macros :

      Ajoutez maintenant le contenu suivant tout en haut du règlement :

      /etc/pf.conf

      vtnet0 = "vtnet0"
      icmp_types = "{ echoreq }"
      . . .
      

      Modifiez vos anciennes règles SSH et ICMP avec vos nouvelles variables :

      /etc/pf.conf

      . . .
      pass in on $vtnet0 proto tcp to port { 22 }
      . . .
      pass inet proto icmp icmp-type $icmp_types
      . . .
      

      Vos anciennes règles SSH et ICMP utilisent désormais des macros. Les noms des variables sont désignés par la syntaxe du signe du dollar de PF. Vous attribuez votre interface vtnet0 à une variable portant le même nom juste comme une formalité, ce qui vous donne la possibilité de la renommer à l’avenir si nécessaire. D’autres noms de variables courantes pour les interfaces publiques comprennent $pub_if ou $ext_if.

      Ensuite, vous instaurerez une table, qui est similaire à une macro, mais conçu pour contenir des groupes d’adresses IP. Créons une table pour les adresses IP non routables, qui jouent souvent un rôle dans les attaques par déni de service (DOS). Vous pouvez utiliser les adresses IP spécifiées dans la RFC6890, qui définit les registres d’adresses IP à usage spécifique. Votre serveur ne devrait pas envoyer ou recevoir de paquets à destination ou en provenance de ces adresses via l’interface publique.

      Créez cette table en ajoutant le contenu suivant directement sous la macro icmp_types :

      /etc/pf.conf

      . . .
      table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          
                        172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    
                        192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            
                        240.0.0.0/4 255.255.255.255/32 }
      . . .
      

      Ajoutez maintenant vos règles pour la table <rfc6890> sous la règle set skip on lo0 :

      /etc/pf.conf

      . . .
      set skip on lo0
      block in quick on egress from <rfc6890>
      block return out quick on egress to <rfc6890>
      . . .
      

      Vous introduisez ici l’option de retour, qui complète votre règle de blocage. Les paquets sont alors déposés et un message RST est envoyé à l’hôte qui a essayé d’établir ces connexions, ce qui est utile pour analyser l’activité de l’hôte.   Ensuite, vous ajoutez le mot-clé egress, qui trouve automatiquement la (les) route(s) par défaut sur une (des) interface(s) donnée(s). C’est généralement une méthode plus propre pour trouver des itinéraires par défaut, surtout avec des réseaux complexes. Le mot-clé quick exécute les règles immédiatement sans tenir compte du reste de l’ensemble des règles. Par exemple, si un paquet avec une adresse IP illogique tente de se connecter au serveur, vous voulez immédiatement interrompre la connexion et vous n’avez aucune raison de faire passer ce paquet par le reste du règlement.

      Protéger vos ports SSH

      Comme votre port SSH est ouvert au public, il est sujet à l’exploitation. L’un des signes d’alerte les plus évidents d’un agresseur est la quantité massive de tentatives de connexion. Par exemple, si la même adresse IP essaie de se connecter à votre serveur dix fois en une seconde, vous pouvez supposer que cela n’a pas été fait par des mains humaines, mais par un logiciel informatique qui a essayé de craquer votre mot de passe de connexion. Ces types d’exploits systématiques sont souvent appelés “attaques par force brute” et réussissent généralement si le serveur a des mots de passe faibles.

      Avertissement : Nous recommandons vivement l’utilisation d’une authentification par clé publique sur tous les serveurs. Consultez le tutoriel de DigitalOcean sur l’authentification par clé.

      PF dispose de fonctions intégrées pour gérer la force brute et d’autres attaques similaires. Avec PF, vous pouvez limiter le nombre de tentatives de connexion simultanées autorisées par un seul hôte. Si un hôte dépasse ces limites, la connexion sera interrompue et il sera banni du serveur. Pour ce faire, vous utiliserez le mécanisme de surcharge de PF qui gère une table d’adresses IP interdites.

      Modifiez votre ancienne règle SSH pour limiter le nombre de connexions simultanées à partir d’un seul hôte comme suit :

      /etc/pf.conf

      . . .
      pass in on $vtnet0 proto tcp to port { 22 } 
          keep state (max-src-conn 15, max-src-conn-rate 3/1, 
              overload <bruteforce> flush global)
      . . .
      

      Vous ajoutez l’option keep state qui vous permet de définir les critères d’état pour la table de surcharge. Vous passez le paramètre max-src-conn pour spécifier le nombre de connexions simultanées autorisées à partir d’un seul hôte par seconde, et le paramètre max-src-conn-rate pour spécifier le nombre de nouvelles connexions autorisées à partir d’un seul hôte par seconde. Vous spécifiez 15 connexions pour max-src-conn, et 3 connexions pour max-src-conn-rate. Si ces limites sont dépassées par un hôte, le mécanisme de surcharge ajoute l’IP source à la table <bruteforce>, ce qui les interdit au serveur. Enfin, l’option flush global supprime immédiatement la connexion.

      Vous avez défini une table de surcharge dans votre règle SSH, mais vous n’avez pas déclaré cette table dans votre règlement.

      Ajoutez la table <bruteforce> sous la macro icmp_types :

      /etc/pf.conf

      . . .
      icmp_types = "{ echoreq }"
      table <bruteforce> persist
      . . .
      

      Le mot-clé persist permet à une table vide d’exister dans le règlement. Sans lui, PF se plaindra qu’il n’y a pas d’adresses IP dans la table.

      Ces mesures garantissent que votre port SSH est protégé par un puissant mécanisme de sécurité. PF vous permet de configurer des solutions rapides pour vous protéger contre des formes d’exploitation désastreuses. Dans les sections suivantes, vous allez prendre des mesures pour nettoyer les paquets lorsqu’ils arrivent sur votre serveur.

      Assainir votre trafic

      Remarque : Les sections suivantes décrivent les principes fondamentaux de la suite de protocoles TCP/IP.   Si vous envisagez de créer des applications web ou des réseaux, il est dans votre intérêt de maîtriser ces concepts. Consultez le tutoriel Introduction à la terminologie, aux interfaces et aux protocoles de réseau de DigitalOcean.

      En raison de la complexité de la suite de protocoles TCP/IP et de la persistance d’acteurs malveillants, les paquets arrivent souvent avec des divergences et des ambiguïtés telles que des fragments d’IP qui se chevauchent, de fausses adresses IP, etc. Il est impératif que vous assainissiez votre trafic avant qu’il n’entre dans le système. Le terme technique pour ce processus est la normalisation.

      Lorsque les données circulent sur Internet, elles sont généralement divisées en petits fragments à leur source pour tenir compte des paramètres de transmission de l’hôte cible où elles sont réassemblées en paquets complets. Malheureusement, un intrus peut détourner ce processus de plusieurs façons qui vont au-delà de la portée de ce tutoriel. Cependant, avec PF, vous pouvez gérer la fragmentation avec une seule règle. PF comprend un mot-clé scrub qui normalise les paquets.

      Ajoutez le mot-clé scrub précédant directement votre règle block all : 

      /etc/pf.conf

      . . .
      set skip on lo0
      scrub in all fragment reassemble max-mss 1440
      block all
      . . .
      

      Cette règle s’applique à l’épuration de tout le trafic entrant. Vous incluez l’option scrub in all fragment reassemble qui empêche les fragments d’entrer dans le système. Au lieu de cela, elles sont mises en cache en mémoire jusqu’à ce qu’elles soient réassemblées en paquets complets, ce qui signifie que vos règles de filtrage n’auront à faire face qu’à des paquets uniformes. Vous incluez également l’option max-mss 1440, qui représente la taille maximale du segment des paquets TCP réassemblés, également connue sous le nom de charge utile.   Vous spécifiez une valeur de 1440 octets, ce qui établit un équilibre entre la taille et les performances, laissant beaucoup de place pour les en-têtes.

      Un autre aspect important de la fragmentation est un terme connu sous le nom d’unité de transmission maximale (MTU). Les protocoles TCP/IP permettent aux appareils de négocier la taille des paquets pour établir des connexions. L’hôte cible utilise les messages ICMP pour informer l’IP source de son MTU, un processus connu sous le nom de découverte de chemin MTU. Le type de message ICMP spécifique concerne la destination inaccessible. Vous activerez la découverte du chemin MTU en ajoutant le type de message unreach à votre liste icmp_types.

      Vous utiliserez le MTU par défaut de votre serveur de 1500 octets qui peut être déterminé avec la commande ifconfig : 

      Vous verrez la sortie suivante qui inclut votre MTU actuelle :

      Output

      vtnet0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=6c07bb<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,TSO4,TSO6,LRO,VLAN_HWTSO,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6> . . .

      Mettez à jour la liste icmp_types pour y inclure le type de message de destination inaccessible :

      /etc/pf.conf

      vtnet0 = "vtnet0"
      icmp_types = "{ echoreq unreach}"
      . . .
      

      Maintenant que vous avez mis en place des politiques pour gérer la fragmentation, les paquets qui entrent dans votre système seront uniformes et cohérents. C’est souhaitable car il existe de nombreux appareils qui échangent des données sur l’internet.

      Vous allez maintenant vous efforcer d’éviter un autre problème de sécurité connu sous le nom de IP spoofing. Les attaquants changent souvent leurs IP sources pour faire croire qu’ils résident sur un nœud de confiance au sein d’une organisation. L’IP comprend une directive antispoofing pour le traitement des IPs de source usurpés Lorsqu’il est appliqué à une ou plusieurs interfaces spécifiques, l’antispoofing bloque tout le trafic provenant du réseau de cette interface (sauf s’il provient de cette interface). Par exemple, si vous appliquez l’antispoofing à une (des) interface(s) résidant au 5.5.5.1/24, tout le trafic du réseau 5.5.5.0/24 ne peut pas communiquer avec le système, sauf s’il provient de cette (ces) interface(s).

      Ajoutez le contenu surligné suivant pour appliquer l’antispoofing à votre interface vtnet0 :

      /etc/pf.conf

      . . .
      set skip on lo0
      scrub in
      antispoof quick for $vtnet0
      block all
      . . .
      

      Enregistrez et quittez le fichier.

      Cette règle antispoofing stipule que tout le trafic du (des) réseau(x) vtnet0 ne peut passer que par l’interface vtnet0, ou il sera immédiatement supprimé avec le mot-clé quick. Les mauvais éléments ne pourront pas se cacher dans le réseau de vtnet0 et communiquer avec d’autres nœuds. 

      Pour démontrer votre règle antispoofing, vous afficherez votre règlement à l’écran sous forme verbeuse. Les règles en PF sont généralement écrites sous une forme abrégée, mais elles peuvent également être écrites de manière verbeuse. Il n’est généralement pas pratique d’écrire les règles de cette manière, mais cela peut être utile à des fins de test.

      Imprimez le contenu de /etc/pf.conf en utilisant pfctl avec la commande suivante :

      • sudo pfctl -nvf /etc/pf.conf

      Cette commande pfctl prend les drapeaux -nvf, qui permettent d’imprimer le règlement et de le tester sans rien charger, ce qu’on appelle aussi un essai. Vous allez maintenant voir le contenu entier de /etc/pf.conf dans sa forme détaillée.

      Vous verrez quelque chose de similaire à la sortie suivante dans la partie antispoofing :

      Output

      . . . block drop in quick on ! vtnet0 inet from your_server_ip/20 to any block drop in quick on ! vtnet0 inet from network_address/16 to any block drop in quick inet from your_server_ip to any block drop in quick inet from network_address to any block drop in quick on vtnet0 inet6 from your_IPv6_address to any . . .

      Votre règle antispoofing a découvert qu’elle faisait partie du réseau your_server_ip/20. Il a également détecté que (pour l’exemple de ce tutoriel) le serveur fait partie d’un réseau adresse_réseau/16, et possède une adresse IPv6 supplémentaire. L’antispoofing empêche tous ces réseaux de communiquer avec le système, sauf si leur trafic passe par l’interface vtnet0. 

      Votre règle antispoofing est le dernier ajout à votre règlement de base. Dans l’étape suivante, vous lancerez ces changements et effectuerez quelques tests.

      Étape 4 – Tester votre règlement de base

      Au cours de cette étape, vous examinerez et testerez votre règlement de base pour vous assurer que tout fonctionne correctement. Il est préférable d’éviter de mettre en œuvre trop de règles à la fois sans les tester. La meilleure pratique consiste à commencer par l’essentiel, à développer progressivement et à remonter tout en modifiant la configuration.

      Voici votre règlement de base complet :

      Base Ruleset /etc/pf.conf

      vtnet0 = "vtnet0"
      icmp_types = "{ echoreq unreach }"
      table <bruteforce> persist
      table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          
                        172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    
                        192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            
                        240.0.0.0/4 255.255.255.255/32 }
      
      set skip on lo0
      scrub in all fragment reassemble max-mss 1440
      antispoof quick for $vtnet0
      block in quick on $vtnet0 from <rfc6890>
      block return out quick on egress to <rfc6890>
      block all
      pass in on $vtnet0 proto tcp to port { 22 } 
          keep state (max-src-conn 15, max-src-conn-rate 3/1, 
              overload <bruteforce> flush global)
      pass out proto { tcp udp } to port { 22 53 80 123 443 }
      pass inet proto icmp icmp-type $icmp_types
      

      Assurez-vous que votre fichier /etc/pf.conf est identique au règlement de base complet ici avant de continuer. Puis, enregistrez et quittez le fichier.

      Vous disposez d’un règlement de base complet :

      • Une collection de macros qui peuvent définir les services et appareils clés.
      • Des politiques d’hygiène du réseau pour remédier à la fragmentation des paquets et aux adresses IP illogiques.
      • Une structure de filtrage de refus par défaut qui bloque tout et n’autorise que ce que vous spécifiez.
      • Accès SSH entrant avec des limites sur le nombre de connexions simultanées qui peuvent être effectuées par un hôte.
      • Des politiques de trafic sortant qui vous permettent d’accéder à certains services essentiels sur internet.
      • Les politiques de l’ICMP qui donnent accès à l’utilitaire ping et à la découverte du chemin MTU.

      Exécutez la commande pfctl suivante pour faire un essai :

      • sudo pfctl -nf /etc/pf.conf

      Vous passez les drapeaux -nf qui indiquent à pfctl d’exécuter le règlement sans le charger, ce qui entraînera des erreurs si quelque chose ne va pas.

      Maintenant, si vous ne rencontrez aucune erreur, chargez le règlement :

      • sudo pfctl -f /etc/pf.conf

      S’il n’y a pas d’erreurs, cela signifie que votre règlement de base est actif et fonctionne correctement. Comme précédemment dans le tutoriel, vous allez effectuer quelques tests sur votre ensemble de règles.

      Premier test pour la connectivité internet et le service DNS :

      Vous verrez le résultat suivant :

      Output

      PING google.com (172.217.0.46): 56 data bytes 64 bytes from 172.217.0.46: icmp_seq=0 ttl=56 time=2.088 ms 64 bytes from 172.217.0.46: icmp_seq=1 ttl=56 time=1.469 ms 64 bytes from 172.217.0.46: icmp_seq=2 ttl=56 time=1.466 ms --- google.com ping statistics --- 3 packets transmitted, 3 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 1.466/1.674/2.088/0.293 ms

      Ensuite, vérifiez que vous atteignez le dépôt pkgs : 

      Encore une fois, améliorez les paquets si nécessaire.

      Enfin, redémarrez votre serveur :

      Donnez à votre serveur quelques minutes pour redémarrer. Vous avez achevé et mis en œuvre votre règlement de base, ce qui constitue une étape importante en termes de progrès. Vous êtes maintenant prêt à explorer certaines des fonctionnalités avancées de PF. Dans la prochaine étape, vous continuerez à prévenir les attaques par la force brute.

      Étape 5 – Gérer votre table de surcharge

      Avec le temps, la table de surcharge <bruteforce> se remplira d’adresses IP malveillantes et devra être nettoyé périodiquement. Il est peu probable qu’un attaquant continue à utiliser la même adresse IP, il est donc contre-intuitif de les stocker dans la table de surcharge pendant de longues périodes.

      Vous utiliserez pfctl pour effacer manuellement les adresses IP qui ont été stockées dans la table de surcharge pendant 48 heures ou plus avec la commande suivante :

      • sudo pfctl -t bruteforce -T expire 172800

      Vous verrez une sortie semblable à :

      Output

      0/0 addresses expired.

      Vous passez le drapeau -t bruteforce, qui signifie table bruteforce, et le drapeau -T, qui vous permet d’exécuter une poignée de commandes intégrées. Dans ce cas, vous dirigez la commandeexpire pour effacer toutes les entrées de -t bruteforce avec une valeur de temps représentée en secondes. Comme vous travaillez sur un nouveau serveur, il n’y a probablement pas encore d’adresses IP dans la table de surcharge.

      Cette règle fonctionne pour les solutions rapides, mais une solution plus robuste serait d’automatiser le processus avec cron, le planificateur de tâches de FreeBSD.   Créons plutôt un script shell qui exécute cette séquence de commandes.

      Créez un fichier de script shell dans le répertoire /usr/local/bin :

      • sudo vi /usr/local/bin/clear_overload.sh

      Ajoutez le contenu suivant au script shell :

      /usr/local/bin/clear_overload.sh

      #!/bin/sh
      
      pfctl -t bruteforce -T expire 172800
      

      Rendez le fichier exécutable avec la commande suivante :

      • sudo chmod 755 /usr/local/bin/clear_overload.sh

      Ensuite, vous allez créer une tâche cron. Il s’agit de tâches répétitives qui se déroulent selon une durée que vous spécifiez. Ils sont couramment utilisés pour les sauvegardes, ou tout processus qui doit s’exécuter à la même heure chaque jour. Vous créez des tâches cron avec des fichiers crontab. Veuillez consulter les pages du manuel pour en savoir plus surcron(8) et crontab(5). 

      Créez un fichier crontab pour l’utilisateur root ou racine avec la commande suivante :

      Ajoutez maintenant le contenu suivant au fichier crontab :

      crontab

      # minute    hour    mday    month   wday    command
      
        *             0     *       *     *     /usr/local/bin/clear_overload.sh
      

      Enregistrez et quittez le fichier.

      Remarque : Veuillez aligner chaque valeur sur l’entrée de table correspondante pour des raisons de lisibilité si les choses ne s’alignent pas correctement lorsque vous ajoutez le contenu.

      Cette tâche cron exécute le script clear_overload.sh tous les jours à minuit, en supprimant les adresses IP vieilles de 48 heures du tableau de surcharge <bruteforce>. Ensuite, vous ajouterez des ancres à votre règlement.

      Étape 6 – Introduction des ancres dans vos règlements

      Au cours de cette étape, vous introduisez des ancres, qui sont utilisées pour l’approvisionnement des règles dans le règlement principal, soit manuellement, soit à partir d’un fichier texte externe. Les ancres peuvent contenir des bribes de règles, des tables et même d’autres ancres, appelées ancres imbriquées. Montrons comment fonctionnent les ancres en ajoutant une table à un fichier externe, et en l’intégrant dans votre règlement de base. Votre table comprendra un groupe d’hôtes internes que vous voulez empêcher de se connecter au monde extérieur.

      Créez un fichier nommé /etc/blocked-hosts-anchor :

      • sudo vi /etc/blocked-hosts-anchor

      Ajoutez le contenu suivant au fichier :

      /etc/blocked-hosts-anchor

      table <blocked-hosts> { 192.168.47.1 192.168.47.2 192.168.47.3 }
      
      block return out quick on egress from <blocked-hosts>
      

      Enregistrez et quittez le fichier.

      Ces règles déclarent et définissent la table <blocked-hosts>, puis empêchent chaque adresse IP de la table <blocked-hosts> d’accéder aux services depuis le monde extérieur. Vous utilisez le mot-clé egress comme méthode privilégiée pour trouver l’itinéraire par défaut, ou la sortie vers internet.

      Vous devez encore déclarer l’ancre dans votre fichier /etc/pf.conf :

      Ajoutez maintenant les règles d’ancrage suivantes après la règle block all :

      /etc/pf.conf

      . . .
      block all
      anchor blocked_hosts
      load anchor blocked_hosts from "/etc/blocked-hosts-anchor"
      . . .
      

      Enregistrez et quittez le fichier.

      Ces règles déclarent les blocked_hosts et chargent les règles d’ancrage dans votre règlement principal à partir de /etc/blocked-hosts-anchorde l’entreprise. 

      Maintenant, initiez ces changements en rechargeant votre règlement avec pfctl :

      • sudo pfctl -f /etc/pf.conf

      S’il n’y a pas d’erreurs, cela signifie qu’il n’y a pas d’erreurs dans votre règlement et que vos modifications sont actives.

      Utilisez pfctl pour vérifier que votre ancre fonctionne :

      Le drapeau -s Anchors signifie show anchors (montrer les ancres). Vous verrez la sortie suivante :

      Output

      blocked_hosts

      L’utilitaire pfctl peut également analyser les règles spécifiques de votre ancre avec les drapeaux -a et -s : 

      • sudo pfctl -a blocked_hosts -s rules

      Vous verrez le résultat suivant :

      Output

      block return out quick on egress from <blocked-hosts> to any

      Une autre caractéristique des ancres est qu’elles vous permettent d’ajouter des règles à la demande sans avoir à recharger le règlement. Cela peut être utile pour les tests, les corrections rapides, les situations d’urgence, etc. Par exemple, si un hôte interne agit de manière particulière et que vous voulez l’empêcher d’établir des connexions vers l’extérieur, vous pouvez avoir une ancre en place qui vous permet d’intervenir rapidement depuis la ligne de commande.

      Ouvrons /etc/pf.conf et ajoutons une autre ancre :

      Vous nommerez l’ancre rogue_hosts, et la placerez sous la règle block all :

      /etc/pf.conf

      . . .
      block all
      anchor rogue_hosts
      . . .
      

      Enregistrez et quittez le fichier.

      Pour initier ces changements, rechargez le règlement avec pfctl : 

      • sudo pfctl -f /etc/pf.conf

      Encore une fois, utilisez pfctl pour vérifier que l’ancre est en marche :

      Cela donnera le résultat suivant :

      Output

      blocked_hosts rogue_hosts

      Maintenant que l’ancre est en marche, vous pouvez y ajouter des règles à tout moment. Testez ceci en ajoutant la règle suivante :

      • sudo sh -c 'echo "block return out quick on egress from 192.168.47.4" | pfctl -a rogue_hosts -f -'

      Ceci invoque la commande echo et son contenu de chaîne de caractères, qui est ensuite acheminé dans l’utilitaire pfctl avec le symbole |, où il est traité en une règle d’ancrage. Vous ouvrez une autre session shell avec la commande sh -c. En effet, vous établissez un conduit entre deux processus, mais vous avez besoin de privilèges sudo pour persister pendant toute la séquence de commande. Il existe plusieurs façons de résoudre ce problème ; ici, vous ouvrez un processus shell supplémentaire avec des privilèges sudo en utilisant sudo sh -c.

      Maintenant, utilisez à nouveau pfctl pour vérifier que ces règles sont actives :

      • sudo pfctl -a rogue_hosts -s rules

      Cela donnera le résultat suivant :

      Output

      block return out quick on egress inet from 192.168.47.4 to any

      L’utilisation des ancres est totalement situationnelle et souvent subjective. Comme toute autre caractéristique, il y a des avantages et des inconvénients à utiliser des ancres. Certaines applications telles que l’interface blacklistd avec les ancres par conception. Ensuite, vous vous concentrerez sur la journalisation avec PF, qui est un aspect essentiel de la sécurité du réseau. Votre pare-feu n’est pas utile si vous ne pouvez pas voir ce qu’il fait.

      Étape 7 – Enregistrer les activités de votre pare-feu

      Dans cette étape, vous travaillerez avec l’enregistrement PF, qui est géré par une pseudo-interface nommée pflog. La journalisation est activée au démarrage en ajoutant pflog_enabled=YES au fichier /etc/rc.conf, ce que vous avez fait à l’étape 2. Cela active le démon pflogd qui fait apparaître une interface nommée pflog0 et écrit les journaux au format binaire dans un fichier nommé /var/log/pflog. Les journaux peuvent être analysés en temps réel à partir de l’interface, ou lus dans le fichier /var/log/pflog avec l’utilitaire tcpdump(8).

      Accédez d’abord à certains journaux à partir du fichier /var/log/pflog :

      • sudo tcpdump -ner /var/log/pflog

      Vous passez les drapeaux -ner qui formatent la sortie pour la lisibilité, et spécifiez également un fichier à lire, qui dans votre cas est /var/log/pflog. 

      Vous verrez le résultat suivant :

      Output

      reading from file /var/log/pflog, link-type PFLOG (OpenBSD pflog file)

      Dans ces premières étapes, il se peut qu’il n’y ait aucune donnée dans le fichier /var/log/pflog. Dans un court laps de temps, le fichier journal commencera à se développer.

      Vous pouvez également consulter les journaux en temps réel à partir de l’interface pflog0 en utilisant la commande suivante :

      Vous passez les drapeaux -nei, qui formatent également la sortie pour la lisibilité, mais cette fois-ci vous spécifiez une interface, qui dans votre cas est pflog0.

      Vous verrez le résultat suivant :

      Output

      tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 262144 bytes

      Vous verrez maintenant les connexions en temps réel. Si possible, effectuez un ping sur votre serveur à partir d’une machine distante et vous verrez les connexions se produire. Le serveur restera dans cet état jusqu’à ce que vous en sortiez.

      Pour sortir de cet état et revenir à la ligne de commande, appuyez sur CTRL + Z. 

      Il existe sur Internet une multitude d’informations sur le tcpdump(8), y compris le site officiel. 

      Accéder aux fichiers journaux avec pftop

      L’utilitaire pftop est un outil permettant de visualiser rapidement l’activité du pare-feu en temps réel. Son nom provient de l’utilitaire de pointe bien connu d’Unix.

      Pour l’utiliser, vous devez installer le paquet pftop :

      Maintenant, lancez le binaire pftop : 

      Cela produira le résultat suivant (vos IP seront différents) :

      Output

      PR DIR SRC DEST STATE AGE EXP PKTS BYTES tcp In 251.155.237.90:27537 157.225.173.58:22 ESTABLISHED:ESTABLISHED 00:12:35 23:59:55 1890 265K tcp In 222.186.42.15:25884 157.225.173.58:22 TIME_WAIT:TIME_WAIT 00:01:25 00:00:06 22 3801 udp Out 157.245.171.59:4699 67.203.62.5:53 MULTIPLE:SINGLE 00:00:14 00:00:16 2 227

      Création d’interfaces de journal supplémentaires

      Comme toute autre interface, plusieurs interfaces de journalisation peuvent être créées et nommées à l’aide d’un fichier /etc/hostname. Vous pouvez trouver cela utile à des fins d’organisation, par exemple si vous souhaitez enregistrer certains types d’activité séparément.

      Créer une interface de journalisation supplémentaire appelée pflog1 : 

      • sudo vi /etc/hostname.pflog1

      Ajoutez le contenu suivant au fichier /etc/hostname.pflog1 :

      /etc/hostname.pflog1

      up
      

      Activez maintenant le périphérique au moment du démarrage dans votre fichier /etc/rc.conf :

      • sudo sysrc pflog1_enable="YES"

      Vous pouvez maintenant surveiller et enregistrer l’activité de votre pare-feu. Cela vous permet de voir qui établit des connexions à votre serveur et les types de connexions effectuées.

      Tout au long de ce tutoriel, vous avez intégré certains concepts avancés dans votre ensemble de règles PF. Il est seulement nécessaire de mettre en œuvre des fonctionnalités avancées au fur et à mesure de vos besoins. Cela dit, dans la prochaine étape, vous reviendrez au règlement de base.

      Étape 8 – Retour à votre règlement de base

      Dans cette dernière section, vous reviendrez à votre règlement de base. C’est une étape rapide qui vous ramènera à un état de fonctionnalité minimaliste.

      Ouvrez le règlement de base avec la commande suivante :

      Supprimez le règlement actuel dans votre fichier et remplacez-le par le règlement de base suivant :

      /etc/pf.conf

      vtnet0 = "vtnet0"
      icmp_types = "{ echoreq unreach }"
      table <bruteforce> persist
      table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          
                        172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    
                        192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            
                        240.0.0.0/4 255.255.255.255/32 }
      
      set skip on lo0
      scrub in all fragment reassemble max-mss 1440
      antispoof quick for $vtnet0
      block in quick on $vtnet0 from <rfc6890>
      block return out quick on egress to <rfc6890>
      block all
      pass in on $vtnet0 proto tcp to port { 22 } 
          keep state (max-src-conn 15, max-src-conn-rate 3/1, 
              overload <bruteforce> flush global)
      pass out proto { tcp udp } to port { 22 53 80 123 443 }
      pass inet proto icmp icmp-type $icmp_types
      

      Enregistrez et quittez le fichier.

      Rechargez le règlement :

      • sudo pfctl -f /etc/pf.conf

      S’il n’y a pas d’erreurs de la commande, alors il n’y a pas d’erreurs dans votre règlement et votre pare-feu fonctionne correctement.

      Vous devez également désactiver l’interface pflog1 que vous avez créée. Comme vous ne savez peut-être pas encore si vous en avez besoin, vous pouvez désactiver pflog1 avec l’utilitaire sysrc : 

      • sudo sysrc pflog1_enable="NO"

      Supprimez maintenant le fichier /etc/hostname.pflog1 du répertoire /etc :

      • sudo rm /etc/hostname.pflog1

      Avant de vous déconnecter, redémarrez le serveur une fois de plus pour vous assurer que toutes vos modifications sont actives et persistantes :

      Attendez quelques minutes avant de vous connecter à votre serveur.

      Si vous souhaitez mettre en œuvre la PF avec un serveur web, voici un ensemble de règles pour ce scénario. Cet ensemble de règles constitue un point de départ suffisant pour la plupart des applications web.

      Simple Web Server Ruleset

      vtnet0 = "vtnet0"
      icmp_types = "{ echoreq unreach }"
      table <bruteforce> persist
      table <webcrawlers> persist
      table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          
                        172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    
                        192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            
                        240.0.0.0/4 255.255.255.255/32 }
      
      set skip on lo0
      scrub in all fragment reassemble max-mss 1440
      antispoof quick for $vtnet0
      block in quick on $vtnet0 from <rfc6890>
      block return out quick on egress to <rfc6890>
      block all
      pass in on $vtnet0 proto tcp to port { 22 } 
          keep state (max-src-conn 15, max-src-conn-rate 3/1, 
              overload <bruteforce> flush global)
      pass in on $vtnet0 proto tcp to port { 80 443 } 
          keep state (max-src-conn 45, max-src-conn-rate 9/1, 
              overload <webcrawlers> flush global)
      pass out proto { tcp udp } to port { 22 53 80 123 443 }
      pass inet proto icmp icmp-type $icmp_types
      

      Cela crée une table de surcharge appelée <webcrawlers>, qui a une politique de surcharge plus libérale que votre port SSH basée sur les valeurs de max-src-conn 45 et max-src-conn-rate. C’est parce que toutes les surcharges ne sont pas le fait de mauvais acteurs. Elles peuvent également provenir de netbots non malveillants, ce qui vous permet d’éviter des mesures de sécurité excessives dans les ports 80 et 443. Si vous décidez de mettre en œuvre le règlement du serveur web, vous devez ajouter la table <webcrawlers> au fichier /etc/pf.conf, et supprimer les PA de la table périodiquement. Pour cela, reportez-vous à l’étape 5.

      Conclusion

      Dans ce tutoriel, vous avez configuré PF sous FreeBSD 12.1. Vous disposez maintenant d’un ensemble de règles de base qui peut servir de point de départ pour tous vos projets FreeBSD. Pour plus d’informations sur PF, consultez les pages de manuel pf.conf(5).

      Visitez notre page thématique sur FreeBSD pour plus de tutoriels et de questions-réponses.



      Source link

      Étapes recommandées pour renforcer Apache HTTP sous FreeBSD 12.0


      L’auteur a choisi le Free and Open Source Fund comme récipiendaire d’une donation dans le cadre du programme Write for Donations.

      Introduction

      Bien que l’installation par défaut d’un serveur Apache HTTP soit déjà sûre, sa configuration peut être considérablement améliorée grâce à quelques modifications. Vous pouvez compléter les mécanismes de sécurité déjà existants, par exemple en mettant en place des protections autour des cookies et des en-têtes, afin que les connexions ne puissent pas être altérées au niveau du client de l’utilisateur. Ce faisant, vous pouvez considérablement réduire les possibilités de plusieurs méthodes d’attaque, comme les attaques de type “Cross-Site Scripting” (également connues sous le nom de XSS). Vous pouvez également éviter d’autres types d’attaques, telles que la falsification de requête inter-sites, ou le détournement de session, ainsi que les attaques par déni de service.

      Dans ce tutoriel, vous allez implémenter certaines mesures recommandées pour réduire la quantité d’informations exposées sur votre serveur. Vous vérifierez la liste des répertoires et désactiverez l’indexation pour vérifier l’accès aux ressources. Vous modifierez également la valeur par défaut de la directive sur le délai d'attente afin d’atténuer les attaques de type déni de service. En outre, vous désactiverez la méthode TRACE afin que les sessions ne puissent pas être inversées et détournées. Enfin, vous sécuriserez les en-têtes et les cookies.

      La plupart des paramètres de configuration seront appliqués au fichier de configuration principal d’Apache HTTP qui se trouve dans /usr/local/etc/apache24/httpd.conf.

      Conditions préalables

      Avant de commencer ce guide, vous aurez besoin des éléments suivants :

      Une fois ces conditions préalables réunies, vous disposez d’un système FreeBSD avec une pile capable de servir du contenu web en utilisant tout ce qui est écrit en PHP, comme les principaux logiciels de gestion de contenu (CMS). De plus, vous avez chiffré des connexions sécurisées grâce à Let’s Encrypt.

      Réduire les informations sur le serveur

      La bannière de système d’exploitation est une méthode utilisée par les ordinateurs, les serveurs et les dispositifs de toutes sortes pour se présenter sur les réseaux. Des personnes malveillantes peuvent utiliser ces informations pour exploiter les systèmes concernés. Dans cette section, vous réduirez la quantité d’informations publiées par cette bannière.

      Des ensembles de directives contrôlent la manière dont ces informations sont affichées. À cet effet, la directive ServerTokens est importante ; par défaut, elle affiche au client qui s’y connecte tous les détails sur le système d’exploitation et les modules compilés.

      Vous utiliserez un outil de balayage du réseau pour vérifier quelles informations sont actuellement révélées avant d’appliquer tout changement. Pour installer nmap, exécutez la commande suivante :

      Pour obtenir l’adresse IP de votre serveur, vous pouvez exécuter la commande suivante :

      • ifconfig vtnet0 | awk '/inet / {print $2}'

      Vous pouvez vérifier la réponse du serveur web en utilisant la commande suivante :

      • nmap -sV -p 80 your-server-ip

      Vous appelez nmap pour effectuer un scan (d’où le drapeau -s), pour afficher la version (le drapeau -V) sur le port 80 (le drapeau -p) sur l’IP ou le domaine donné.

      Vous recevrez des informations sur votre serveur web, semblables à celles qui suivent :

      Output

      Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-22 00:30 CET Nmap scan report for 206.189.123.232 Host is up (0.054s latency). PORT STATE SERVICE VERSION 80/tcp open http Apache httpd 2.4.41 ((FreeBSD) OpenSSL/1.1.1d-freebsd Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 7.59 seconds

      Cette sortie montre que des informations telles que le système d’exploitation, la version d’Apache HTTP et OpenSSL sont visibles. Cela peut être utile aux attaquants pour obtenir des informations sur le serveur et choisir les bons outils à exploiter, par exemple, une vulnérabilité dans le logiciel fonctionnant sur le serveur.

      Vous placerez la directive ServerTokens dans le fichier de configuration principal puisqu’elle n’est pas configurée par défaut. L’absence de cette configuration fait qu’Apache HTTP affiche les informations complètes sur le serveur, comme l’indique la documentation. Pour limiter les informations qui sont révélées sur votre serveur et votre configuration, vous placerez la directive ServerTokens dans le fichier de configuration principal.

      Vous placerez cette directive à la suite de l’entrée ServerName dans le fichier de configuration. Exécutez la commande suivante pour trouver la directive :

      • grep -n 'ServerName' /usr/local/etc/apache24/httpd.conf

      Vous trouverez le numéro de ligne que vous pouvez ensuite rechercher avec vi :

      Output

      226 #ServerName www.example.com:80

      Exécutez la commande suivante :

      • sudo vi +226 /usr/local/etc/apache24/httpd.conf

      Ajoutez la ligne surlignée suivante :

      /usr/local/etc/apache24/httpd.conf

      . . .
      #ServerName www.example.com:80
      ServerTokens Prod
      

      Enregistrez et quittez le fichier avec :wq et ENTER.

      En réglant la directive ServerTokens sur Prod, on affichera uniquement qu’il s’agit d’un serveur web Apache.

      Pour que cela prenne effet, redémarrez le serveur Apache HTTP :

      Pour tester les changements, exécutez la commande suivante :

      • nmap -sV -p 80 your-server-ip

      Vous obtiendrez un résultat similaire à celui qui suit, avec un minimum d’informations sur votre serveur web Apache :

      Output

      Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-22 00:58 CET Nmap scan report for WPressBSD (206.189.123.232) Host is up (0.056s latency). PORT STATE SERVICE VERSION 80/tcp open http Apache httpd Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 7.59 seconds

      Vous avez vu quelles informations le serveur annonçait avant la modification et vous avez maintenant réduit celles-ci au minimum. De ce fait, vous fournissez moins d’indices sur votre serveur à un acteur externe. Au cours de l’étape suivante, vous gérerez les listes du répertoire pour votre serveur web.

      Gestion des listes du répertoire

      Au cours de cette étape, vous vous assurerez que les listes du répertoire sont correctement configurées, de sorte que les bonnes parties du système soient accessibles au public comme prévu, tandis que les autres sont protégées.

      Remarque : lorsqu’un argument est déclaré, il est actif, mais le + peut le renforcer visuellement, il est en fait activé. Lorsqu’un signe moins - est placé, l’argument est refusé, par exemple, Options -Indexes.

      Les arguments avec + et/ou - ne peuvent pas être mélangés, cela est considéré comme une mauvaise syntaxe dans Apache HTTP et peut être rejeté au démarrage.

      L’ajout de l’énoncé Options -Indexes permet de définir le contenu du chemin de données /usr/local/www/apache24/data pour qu’il ne soit pas indexé (read listed) automatiquement si un fichier .html n’existe pas, et qu’il n’indique pas si une URL correspond à ce répertoire. Cela s’appliquera également lors de l’utilisation de configurations d’hôtes virtuels telles que celui utilisé pour le tutoriel préalable au certificat Let’s Encrypt.

      Vous définirez la directive Options avec l’argument -Indexes et avec la directive +FollowSymLinks, qui permettra de suivre des liens symboliques. Vous utiliserez le symbole + afin de respecter les conventions HTTP d’Apache.

      Exécutez la commande suivante pour trouver la ligne à modifier dans le fichier de configuration :

      • grep -n 'Options Indexes FollowSymLinks' /usr/local/etc/apache24/httpd.conf

      Vous verrez une sortie similaire à ce qui suit :

      Output

      263 : Options Indexes FollowSymLinks

      Exécutez cette commande pour accéder directement à la ligne que vous souhaitez modifier :

      • sudo vi +263 /usr/local/etc/apache24/httpd.conf

      Modifiez maintenant la ligne conformément à la configuration :

      /usr/local/etc/apache24/httpd.conf

      . . .
      #
      Options -Indexes +FollowSymLinks
      
      #
      . . .
      

      Enregistrez et quittez le fichier avec :wq et ENTER.

      Redémarrez Apache HTTP pour implémenter ces modifications :

      Au niveau de votre domaine dans le navigateur, vous verrez un message d’accès interdit, également connu sous le nom d’erreur 403. Cela est dû aux changements que vous avez appliqués. Le placement de -Indexes dans la directive Options a désactivé la capacité d’auto-indexation d’Apache HTTP et il n’y a donc pas de fichier index.html dans le chemin des données.

      Vous pouvez résoudre ce problème en plaçant un fichier index.html à l’intérieur du VirtualHost que vous avez activé dans le tutoriel préalable au certificat Let’s Encrypt. Vous utiliserez le bloc par défaut dans Apache HTTP et le placerez dans le même dossier que le DocumentRoot que vous avez déclaré dans l’hôte virtuel.

      /usr/local/etc/apache24/extra/httpd-vhosts.conf

      <VirtualHost *:80>
          ServerAdmin your_email@your_domain.com
          DocumentRoot "/usr/local/www/apache24/data/your_domain.com"
          ServerName your_domain.com
          ServerAlias www.your_domain.com
          ErrorLog "/var/log/your_domain.com-error_log"
          CustomLog "/var/log/your_domain.com-access_log" common
      </VirtualHost>
      

      Utilisez la commande suivante pour ce faire :

      • sudo cp /usr/local/www/apache24/data/index.html /usr/local/www/apache24/data/your_domain.com/index.html

      Vous verrez maintenant un message Ça marche ! lorsque vous visiterez votre domaine.

      Dans cette section, vous avez imposé des restrictions à la directive Indexes afin de ne pas inclure et afficher automatiquement un contenu autre que celui que vous avez prévu. Désormais, s’il n’existe pas de fichier index.html dans le chemin de données, Apache HTTP ne créera pas automatiquement un index du contenu. Dans la prochaine étape, vous irez au-delà de l’obscurcissement des informations et vous adapterez différentes directives.

      Réduire la valeur de la directive sur le délai d’attente

      La directive Timeout fixe la limite du délai pendant lequel Apache HTTP attendra une nouvelle entrée/sortie avant l’échec de la demande de connexion. Cette échec peut être du à différentes circonstances telles que des paquets n’arrivant pas au serveur ou des données n’étant pas confirmées comme ayant été reçues par le client.

      Par défaut, le délai d’attente est fixé à 60 secondes. Dans les environnements où le service Internet est lent, cette valeur par défaut peut être raisonnable, mais une minute est une durée assez longue, en particulier si le serveur couvre une cible d’utilisateurs avec un service Internet plus rapide. En outre, la période pendant laquelle le serveur ne ferme pas la connexion peut être utilisée abusivement pour effectuer des attaques par déni de service (DoS). Si une invasion de ces connexions malveillantes se produit, le serveur faiblira et s’exposera à des risques de saturation et d’incapacité à répondre.

      Pour modifier la valeur, vous trouverez les entrées Timeout dans le fichier httpd-default.conf :

      • grep -n 'Timeout' /usr/local/etc/apache24/extra/httpd-default.conf

      Vous verrez une sortie similaire à :

      Output

      8 # Timeout: The number of seconds before receives and sends time out. 10 Timeout 60 26 # KeepAliveTimeout: Number of seconds to wait for the next request from the 29 KeepAliveTimeout 5 89 RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500

      Dans la ligne de sortie, 10 définit la valeur de la directive Timeout. Pour accéder directement à cette ligne, exécutez la commande suivante :

      • sudo vi +10 /usr/local/etc/apache24/extra/httpd-default.conf

      Vous la modifierez pour la régler sur 30 secondes, par exemple, comme suit :

      /usr/local/etc/apache24/extra/httpd-default.conf

      #
      # Timeout: The number of seconds before receives and sends time out.
      #
      Timeout 30
      

      Enregistrez et quittez le fichier avec :wq et ENTER.

      La valeur de la directive Timeout doit trouver un équilibre entre une période suffisamment longue pour que ces événements permettent une connexion légitime et réussie, et suffisamment courte pour empêcher des tentatives de connexion non souhaitées.

      Remarque : les attaques par déni de service peuvent drainer les ressources du serveur de manière assez efficace. Utiliser un MPM threadé pour obtenir les meilleures performances de la manière dont Apache HTTP gère les connexions et les processus constitue une contre-mesure complémentaire et très efficace. Dans ce tutoriel Comment configurer Apache HTTP avec l’événement MPM et PHP-FPM sous FreeBSD 12.0, il y a des étapes pour activer cette fonctionnalité.

      Pour que cette modification prenne effet, redémarrez le serveur Apache HTTP :

      Vous avez modifié la valeur par défaut de la directive Timeout afin d’atténuer partiellement les attaques par déni de service.

      Désactiver la méthode TRACE

      Le Hypertext Transport Protocol a été développé selon un modèle client-serveur et, à ce titre, le protocole dispose de méthodes de requête pour récupérer ou placer des informations depuis/vers le serveur. Le serveur doit comprendre ces ensembles de méthodes et l’interaction entre elles. Dans cette étape, vous configurerez les méthodes minimales nécessaires.

      La méthode TRACE, considérée comme inoffensive, a été utilisée pour réaliser des attaques de type Cross Site Tracing. Ces types d’attaques permettent à des acteurs malveillants de voler des sessions d’utilisateurs grâce à cette méthode. La méthode a été conçue à des fins de débogage. Le serveur renvoie la même requête que celle envoyée à l’origine par le client. Comme le cookie de la session du navigateur est envoyé au serveur, il sera renvoyé à nouveau. Cependant, cela peut potentiellement être intercepté par un acteur malveillant, qui peut alors rediriger la connexion d’un navigateur vers un site sous son contrôle et non vers le serveur d’origine.

      En raison de la possibilité d’une utilisation abusive de la méthode TRACE, il est recommandé de ne l’utiliser que pour le débogage et non en production. Dans cette section, vous désactiverez cette méthode.

      Modifiez le fichier httpd.conf avec la commande suivante, puis appuyez sur G pour atteindre la fin du fichier :

      • sudo vi /usr/local/etc/apache24/httpd.conf

      Ajoutez le chemin d’entrée suivant à la fin du fichier :

      /usr/local/etc/apache24/httpd.conf

      . . .
      TraceEnable off
      

      Une bonne pratique consiste à spécifier uniquement les méthodes que vous utiliserez dans votre serveur web Apache HTTP. Cela permettra de limiter les points d’entrée potentiels pour les acteurs malveillants.

      LimitExcept peut être utile à cette fin, car il n’autorise aucune autre méthode que celles qui y sont déclarées. Par exemple, une configuration peut être établie comme celle-ci :

      /usr/local/etc/apache24/httpd.conf

      DocumentRoot "/usr/local/www/apache24/data"
      <Directory "/usr/local/www/apache24/data">
          Options -Indexes +FollowSymLinks -Includes
          AllowOverride none
           <LimitExcept GET POST HEAD>
             deny from all
          </LimitExcept>
          Require all granted
      </Directory>
      

      Comme indiqué dans la directive LimitExcept, seules les méthodes GET, POST et HEAD sont autorisées dans la configuration.

      • La méthode GET fait partie du protocole HTTP et elle est utilisée pour récupérer des données.
      • La méthode POST fait également partie du protocole HTTP et est utilisée pour envoyer des données au serveur.
      • La méthode HEAD est similaire à la méthode GET, mais elle n’a pas d’organe de réponse.

      Vous utiliserez la commande suivante et placerez le bloc LimitExcept à l’intérieur du fichier :

      • sudo vi +272 /usr/local/etc/apache24/httpd.conf

      Pour définir cette configuration, vous placerez le bloc suivant dans l’entrée de la directive DocumentRoot où le contenu sera lu, plus précisément dans l’entrée Directory :

      /usr/local/etc/apache24/httpd.conf

      . . .
      <LimitExcept GET POST HEAD>
         deny from all
      </LimitExcept>
      . . .
      

      Pour appliquer les modifications, redémarrez Apache HTTP :

      La nouvelle directive AllowedMethods offre des fonctionnalités similaires, bien que son statut soit encore expérimental.

      Vous avez vu ce que sont les méthodes HTTP, leur utilisation et la protection qu’elles offrent contre les activités malveillantes se servant de la méthode TRACE, ainsi que la manière de déclarer les méthodes à utiliser. Maintenant, vous allez travailler avec d’autres protections dédiées aux en-têtes et aux cookies HTTP.

      Sécuriser des en-têtes et des cookies

      Au cours de cette étape, vous allez définir des directives spécifiques pour protéger les sessions que les machines clientes ouvriront lorsqu’elles visiteront votre serveur web Apache HTTP. De cette façon, votre serveur ne chargera pas de contenu indésirable, le chiffrage ne sera pas déclassé et vous éviterez que votre contenu soit fouillé.

      Les en-têtes sont des éléments des méthodes de requêtes. Il existe des en-têtes pour ajuster l’authentification, la communication entre le serveur et le client, la mise en cache, la négociation de contenu, etc.

      Les cookies sont des éléments d’information envoyés par le serveur au navigateur. Ces bits permettent au serveur de reconnaître le navigateur du client d’un ordinateur à l’autre. Ils permettent également aux serveurs de reconnaître les sessions des utilisateurs. Ils peuvent, par exemple, suivre le panier d’un utilisateur connecté, ses informations de paiement, son historique, etc. Les cookies sont utilisés et conservés dans le navigateur web du client puisque HTTP est un protocole apatride, ce qui signifie qu’une fois la connexion fermée, le serveur ne se souvient pas de la requête envoyée par un client, ou un autre.

      Il est important de protéger les en-têtes ainsi que les cookies car ils assurent la communication entre le client du navigateur web et le serveur web.

      Le module des en-têtes est activé par défaut. Pour vérifier s’il est chargé, vous utiliserez la commande suivante :

      • sudo apachectl -M | grep 'headers'

      Vous verrez la sortie suivante :

      Output

      headers_module (shared)

      Si vous ne voyez aucune sortie, vérifiez si le module est activé dans le fichier httpd.conf d’Apache :

      • grep -n 'mod_headers' /usr/local/etc/apache24/httpd.conf

      En sortie, vous verrez une ligne non commentée renvoyant au module spécifique pour les en-têtes :

      /usr/local/etc/apache24/httpd.conf

      . . .
      122  LoadModule headers_module libexec/apache24/mod_headers.so
      . . .
      

      Supprimez le hashtag au début de la ligne mod_headers.so, s’il est présent, pour activer la directive.

      En utilisant les directives HTTP Apache suivantes, vous protégerez les en-têtes et les cookies contre les activités malveillantes, afin de réduire le risque pour les clients et les serveurs.

      Vous allez maintenant régler la protection de l’en-tête. Vous placerez toutes ces valeurs d’en-tête dans un seul bloc. Vous pouvez choisir d’appliquer ces valeurs comme vous le souhaitez, mais toutes sont recommandées.

      Modifiez le fichier httpd.conf avec la commande suivante, puis appuyez sur G pour atteindre la fin du fichier :

      • sudo vi /usr/local/etc/apache24/httpd.conf

      Placez le bloc suivant à la fin du fichier :

      /usr/local/etc/apache24/httpd.conf

      . . .
      <IfModule mod_headers.c>
        # Add security and privacy related headers
        Header set Content-Security-Policy "default-src 'self'; upgrade-insecure-requests;"
        Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
        Header always edit Set-Cookie (.*) "$1; HttpOnly; Secure"
        Header set X-Content-Type-Options "nosniff"
        Header set X-XSS-Protection "1; mode=block"
        Header set Referrer-Policy "strict-origin"
        Header set X-Frame-Options: "deny"
        SetEnv modHeadersAvailable true
      </IfModule>
      
      • Jeu d'en-tête Strict-Transport-Security "max-age=31536000 ; includeSubDomains" : le HTTP Strict Transport Security (HTSTS) est un mécanisme permettant aux serveurs et clients web (principalement les navigateurs) d’établir des communications en utilisant uniquement le HTTPS. En l’implémentant, vous évitez les attaques de type “man-in-the-middle”, où une tierce partie entre les communications pourrait potentiellement accéder aux bits, mais aussi les altérer.

      • En-tête always edit Set-Cookie (. *) "$1 ; HttpOnly ; Secure" : les drapeaux HttpOnly et Secure sur les en-têtes aident à prévenir les attaques de type “cross-site scripting”, également connues sous le nom de XSS. Les cookies peuvent être utilisés à mauvais escient par les pirates pour se faire passer pour des visiteurs légitimes se présentant comme quelqu’un d’autre (vol d’identité), ou être trafiqués.

      • En-tête Referrer-Policy "strict-origin" : l’en-tête Referrer-Policy définit les informations qui sont incluses en tant qu’informations de référence dans le champ d’en-tête.

      • En-tête Content-Security-Policy "default-src 'self'; upgrade-insecure-requests;": l’en-tête Content-Security-Policy (CSP) empêchera complètement le chargement de contenu non spécifié dans les paramètres, ce qui est utile pour prévenir les attaques par script inter-sites (XSS). Il existe de nombreux paramètres possibles pour configurer la politique pour cet en-tête. L’essentiel est de le configurer pour charger le contenu du même site et de mettre à jour tout contenu ayant une origine HTTP.

      • En-tête X-XSS-Protection "1; mode=block" : cette option prend en charge les anciens navigateurs qui ne sont pas compatibles avec les en-têtes Content-Security-Policy. L’en-tête ‘X-XSS-Protection’ assure une protection contre les attaques de type Cross-Site Scripting. Vous n’avez pas besoin de définir cet en-tête, sauf si vous devez prendre en charge d’anciennes versions de navigateur, ce qui est rare.

      • En-tête X-Frame-Options: "deny": cela permet d’éviter les attaques de type “clickjacking”. L’en-tête “X-Frame-Options” indique au navigateur si une page peut être rendue dans un <frame>, <iframe>, <embed> ou <object>. Ainsi, le contenu d’autres sites ne peut pas être intégré à d’autres, ce qui empêche les attaques de type “clickjacking”. Ici, vous refusez tout rendu de trame afin que la page web ne puisse être intégrée nulle part ailleurs, pas même à l’intérieur du même site web. Vous pouvez l’adapter à vos besoins, si, par exemple, vous devez autoriser le rendu de certaines pages parce qu’il s’agit de publicités ou de collaborations avec des sites web spécifiques.

      • En-tête X-Content-Type-Options "nosniff": l’en-tête “X-Content-Type-Options” contrôle les types MIME afin qu’ils ne soient pas modifiés et suivis. Les types MIME sont des normes de format de fichier ; ils fonctionnent pour le texte, l’audio, la vidéo, l’image, etc. Cet en-tête empêche les acteurs malveillants de fouiller le contenu de ces fichiers et d’essayer de modifier les types de fichiers.

      Redémarrez maintenant Apache pour que les modifications prennent effet :

      Pour vérifier les niveaux de sécurité de vos paramètres de configuration, visitez le site web des en-têtes de sécurité. Après avoir suivi les étapes de ce tutoriel, votre domaine obtiendra la note A.

      Remarque : si vous faites vérifier vos en-têtes en visitant https://securityheaders.com/ et que vous obtenez une note F, cela pourrait être dû au fait qu’il n’y a pas d’index.html dans le DocumentRoot de votre site, comme indiqué à la fin de l’étape 2. Si, en vérifiant vos en-têtes, vous obtenez une note différente d’un A ou d’un F, vérifiez chaque ligne de l'ensemble des en-têtes à la recherche de toute faute d’orthographe qui aurait pu causer le déclassement.

      Dans cette étape, vous avez utilisé jusqu’à sept paramètres pour améliorer la sécurité de vos en-têtes et cookies. Ces mesures permettront d’éviter les attaques de type Cross-Site Scripting, le “clickjacking” et d’autres types d’attaques.

      Conclusion

      Dans ce tutoriel, vous avez abordé plusieurs aspects liés à la sécurité, à la divulgation d’informations à la protection des sessions, en passant par la définition d’autres paramètres de configuration pour les fonctionnalités importantes.

      Pour d’autres ressources concernant le renforcement d’Apache, voici quelques autres références :

      Pour connaître des outils supplémentaires de protection d’Apache HTTP :



      Source link