One place for hosting & domains

      Comment convertir des types de données sous Python 3


      Introduction

      Sous Python, les data types servent à classer un type de données particulier. Ils permettent également de déterminer les valeurs que vous pouvez attribuer au type en question et les opérations que vous pouvez effectuer sur celui-ci. Au moment de la programmation, vous aurez parfois besoin de convertir des valeurs d’un type à l’autre pour pouvoir manipuler les valeurs différemment. Par exemple, il vous arrivera parfois de devoir concaténer des valeurs numériques avec des chaînes de caractères ou d’ajouter une décimale à des chiffres initialisés comme des valeurs entières.

      Ce tutoriel vous guidera à travers le processus de conversion de types de données, notamment les chiffres, les chaines, les tuples et les listes et vous proposera des exemples qui vous permettront de vous familiariser avec différents cas d’utilisation.

      Conversion des types de chiffres

      Sous Python, il existe deux types de données de chiffre : les entiers et les chiffres à virgule ou décimaux. Lorsque vous travaillez sur le code d’une autre personne, il arrive parfois que vous ayez besoin de convertir un chiffre entier en décimal ou vice versa, ou que vous constatiez que vous avez utilisé un entier alors qu’en réalité vous avez besoin d’un décimal. Python intègre des méthodes qui vous permettent de facilement convertir les entiers en décimaux et les décimaux en entiers.

      Conversion des entiers en décimaux

      La méthode float() de Python vous permettra de convertir les entiers en décimaux. Pour utiliser cette fonction, ajoutez un chiffre entier à l’intérieur des parenthèses :

      float(57)
      

      Dans ce cas, nous allons convertir 57 en 57.0.

      Vous pouvez également l’utiliser avec une variable. Disons que f est égal à 57, puis imprimons le nouveau décimal :

      f = 57
      print(float(f))
      

      Output

      57.0

      En utilisant la fonction float(), nous pouvons convertir les entiers en décimaux.

      Conversion des décimaux en entiers

      Python intègre également une fonction pour convertir les décimaux en entiers : int ().

      La fonction int() fonctionne de la même manière que la fonction float() : vous pouvez ajouter un chiffre à virgule à l’intérieur des parenthèses pour le convertir en entier :

      int(390.8)
      

      Dans ce cas, nous allons convertir 390,8 en 390.

      Vous pouvez également l’utiliser avec des variables. Disons que b est égal à 125,0, et que c est égal à 390,8, puis imprimons les nouveaux décimaux :

      b = 125.0
      c = 390.8
      
      print(int(b))
      print(int(c))
      

      Output

      125 390

      Lorsque vous convertissez des décimaux en entiers avec la fonction int(), Python supprime la décimale et les chiffres restants après la virgule pour créer un entier. Même si nous voulions arrondir 390,8 à 391, Python ne pourrait pas le faire avec la fonction int().

      Numéros convertis par division

      Dans Python 3, les quotients correspondants sont convertis d’entiers en décimaux lorsque vous exécuter division bien que cela ne soit pas possible sous Python 2. Autrement dit, dans Python 3, lorsque vous divisez 5 par 2, vous obtenez un chiffre décimal (2,5) :

      a = 5 / 2
      print(a)
      

      Output

      2.5

      Sous Python 2, étant donné que vous avez à faire à deux entiers, vous obtiendrez un entier à la place : 5 / 2 = 2. Consultez notre tutoriel « Python 2 vs Python 3 : considérations pratiques » pour avoir de plus amples informations sur les différences qui existent entre Python 2 et Python 3.

      Conversion avec des chaînes de caractères

      Une chaine de caractères est une séquence d’un ou plusieurs caractères (lettres, chiffres, symboles). Les chaines de caractères sont une forme de données que l’on trouve couramment dans les programmes informatiques. Il nous arrivera parfois de devoir convertir des chaines de caractères en chiffres ou des chiffres en chaines de caractères, spécialement lorsque nous intégrons des données générées par les utilisateurs.

      Conversion de chiffres en chaînes de caractères

      Nous pouvons convertir des chiffres en chaines de caractères en utilisant la méthode str(). Nous allons transmettre un chiffre ou une variable dans les parenthèses de la méthode. Ensuite, cette valeur numérique sera convertie en une valeur de chaine de caractères.

      Concentrons-nous tout d’abord sur la conversion des entiers. Pour convertir l’entier 12 en une valeur de chaine de caractères, vous pouvez placer 12 dans la méthode str() :

      str(12)
      

      En exécutant str(12) dans le shell interactif de Python avec la commande python dans la fenêtre du terminal, vous obtiendrez le résultat suivant :

      Output

      '12'

      Les guillemets qui entourent le chiffre 12 signifient que le nombre n’est plus un entier mais qu’il est maintenant une valeur de chaine de caractères.

      En combinaison avec des variables, nous pouvons commencer à voir à quel point il peut être intéressant de convertir des entiers en chaines de caractères. Supposons que nous voulions faire un suivi du progrès de la programmation quotidienne d’un utilisateur et que nous saisissions le nombre de lignes de code qu’ils écrivent à la fois. Nous voudrions montrer ce feedback à l’utilisateur et imprimerions les valeurs de chaines de caractères et d’entiers en même temps :

      user = "Sammy"
      lines = 50
      
      print("Congratulations, " + user + "! You just wrote " + lines + " lines of code.")
      

      Lorsque nous exécutons ce code, nous obtenons l’erreur suivante :

      Output

      TypeError: Can't convert 'int' object to str implicitly

      Nous ne sommes pas en mesure de concaténer des chaines de caractères et des entiers dans Python. Nous devrons donc convertir les lines de variables en chaines de caractères :

      user = "Sammy"
      lines = 50
      
      print("Congratulations, " + user + "! You just wrote " + str(lines) + " lines of code.")
      

      Maintenant, lorsque nous exécutons le code, nous obtenons le résultat suivant qui félicite notre utilisateur du progrès qu’il a réalisé :

      Output

      Congratulations, Sammy! You just wrote 50 lines of code.

      Si nous cherchons à convertir un décimal en une chaine de caractères plutôt qu’un entier en chaine de caractères, nous devons suivre les mêmes étapes et le même format. Lorsque nous saisissons un décimal dans la méthode de str(), la valeur de chaine de caractères du décimal sera renvoyée. Nous pouvons utiliser soit la valeur du décimal en elle-même ou une variable :

      print(str(421.034))
      
      f = 5524.53
      print(str(f))
      

      Output

      421.034 5524.53

      Nous pouvons tester si elle est correcte en la concaténant avec une chaine de caractères :

      f = 5524.53
      print("Sammy has " + str(f) + " points.")
      

      Output

      Sammy has 5524.53 points.

      Nous pouvons avoir la certitude que notre décimal a été correctement converti en une chaine de caractères car la concaténation a été effectuée sans erreur.

      Conversion de chaines de caractères en chiffres

      Vous pouvez convertir des chaines de caractères en chiffres en utilisant les méthodes int() et float().

      Si votre chaine de caractères ne dispose pas de décimal, vous voudrez très probablement la convertir en un entier en utilisant la méthode int().

      Utilisons l’exemple de l’utilisateur Sammy qui garde un suivi des lignes de code écrites quotidiennement. Nous souhaiterions éventuellement manipuler ces valeurs avec des calculs afin de fournir des commentaires plus intéressants à l’utilisateur. Cependant, ces valeurs sont actuellement stockées dans des chaines de caractères :

      lines_yesterday = "50"
      lines_today = "108"
      
      lines_more = lines_today - lines_yesterday
      
      print(lines_more)
      

      Output

      TypeError: unsupported operand type(s) for -: 'str' and 'str'

      Étant donné que les deux valeurs numériques ont été stockées dans des chaines de caractères, une erreur nous a été renvoyée. L’opérande - pour les soustractions n’est un opérande valable pour deux valeurs de chaines de caractères.

      Modifions le code pour inclure la méthode int() qui convertira les chaines de caractères en entiers et faisons quelques calculs avec les valeurs qui étaient initialement des chaines de caractères.

      lines_yesterday = "50"
      lines_today = "108"
      
      lines_more = int(lines_today) - int(lines_yesterday)
      
      print(lines_more)
      

      Output

      58

      La variable lines_more est automatiquement un entier et égale à la valeur numérique 58 dans cet exemple.

      Nous pouvons également convertir les chiffres dans l’exemple ci-dessus en valeurs décimales en utilisant la méthode float() à la place de la méthode int(). Au lieu de recevoir le résultat de 58, nous obtiendrons le résultat de 58.0, un chiffre décimal.

      L’utilisateur Sammy gagne des points en valeurs décimales

      total_points = "5524.53"
      new_points = "45.30"
      
      new_total_points = total_points + new_points
      
      print(new_total_points)
      

      Output

      5524.5345.30

      Dans ce cas, il est possible d’utiliser l’opérande + avec deux chaines de caractères, mais il concatène deux chaines de caractères au lieu d’additionner deux valeurs numériques. Notre résultat est donc inhabituel car il se contente juste de placer les deux valeurs l’une à côté de l’autre.

      Nous allons devoir convertir ces chaines de caractères en décimaux avant d’effectuer un calcul avec la méthode float() :

      total_points = "5524.53"
      new_points = "45.30"
      
      new_total_points = float(total_points) + float(new_points)
      
      print(new_total_points)
      

      Output

      5569.83

      Maintenant que nous avons converti les deux chaines de caractères en décimaux, nous obtenons le résultat anticipé qui additionne 45.30 et 5524.53.

      Si nous essayons de convertir une valeur de chaines de caractères avec des décimaux en un entier, nous obtiendrons une erreur :

      f = "54.23"
      print(int(f))
      

      Output

      ValueError: invalid literal for int() with base 10: '54.23'

      Si nous plaçons une valeur décimale dans une chaîne de caractères dans la méthode int(), nous obtiendrons une erreur car elle ne se convertira pas en un entier.

      En effet, en convertissant des chaines de caractères en chiffres, nous pouvons rapidement modifier le type de données avec lequel nous travaillons et effectuer des calculs sur des valeurs numériques qui ont été initialement saisies en tant que chaines de caractères.

      Conversion des tuples en listes

      Vous pouvez utiliser les méthodes list() et tuple() pour convertir les valeurs qui leur ont été transmises en type de données de liste et tuple respectivement. Sous Python :

      • une list est une séquence d’éléments ordonnés et altérables entre crochets [ ].
      • un tuple est une séquence d’éléments immuables et ordonnés entre parenthèses ( ).

      Conversion des tuples

      Commençons par convertir une liste en un tuple. Étant donné qu’il s’agit d’un type de données immuable, la conversion d’une liste en tuple peut permettre une optimisation substantielle aux programmes que nous créons. Lorsque nous utilisons la méthode tuple(), le système renverra la version tuple de la valeur qui lui a été soumise.

      print(tuple(['pull request', 'open source', 'repository', 'branch']))
      

      Output

      ('pull request', 'open source', 'repository', 'branch')

      Nous voyons qu’un tuple est imprimé dans le résultat car les éléments sont maintenant entre parenthèses et non entre crochets.

      Utilisons tuple() avec une variable qui représente une liste :

      sea_creatures = ['shark', 'cuttlefish', 'squid', 'mantis shrimp']
      print(tuple(sea_creatures))
      

      Output

      ('shark', 'cuttlefish', 'squid', 'mantis shrimp')

      À nouveau, nous voyons que la valeur de liste est modifiée en une valeur de tuple, indiquée par les parenthèses. Nous pouvons convertir tout type itérable en tuple, notamment des chaines de caractères :

      print(tuple('Sammy'))
      

      Output

      ('S', 'a', 'm', 'm', 'y')

      Étant donné que nous pouvons itérer des chaines de caractères, nous pouvons les convertir en tuples en utilisant la méthode tuple(). Cependant, en utilisant des types de données qui ne sont pas itérables, comme des entiers et des décimaux, nous obtiendrons une erreur de type :

      print(tuple(5000))
      

      Output

      TypeError: 'int' object is not iterable

      Bien qu’il soit possible de convertir l’entier en une chaîne de caractères et de le convertir ensuite en tuple, comme dans tuple(str(5000)), il est préférable d’opter pour un code lisible plutôt que des conversions compliquées.

      Conversion en listes

      Il est possible de convertir des valeurs, en particulier des tuples, en listes si vous avez besoin d’une version altérable de cette valeur.

      Nous allons utiliser la méthode list() pour convertir le tuple suivant en une liste. Étant donné que la syntaxe de création d’une liste utilise des parenthèses, veillez à bien inclure les parenthèses de la méthode list(), et dans le cas présent de la méthode print() également :

      print(list(('blue coral', 'staghorn coral', 'pillar coral')))
      

      Output

      ['blue coral', 'staghorn coral', 'pillar coral']

      Les crochets signalent qu’une liste a été renvoyée à partir de la valeur du tuple initialement transmise en utilisant la méthode list().

      Pour rendre le code plus lisible, nous pouvons supprimer l’une des paires de parenthèses en utilisant une variable :

      coral = ('blue coral', 'staghorn coral', 'pillar coral')
      list(coral)
      

      Si nous imprimons list(coral), nous obtiendrons le même résultat que celui ci-dessus.

      Tout comme les tuples, vous pouvez convertir des chaines de caractères en listes :

      print(list('shark'))
      

      Output

      ['s', 'h', 'a', 'r', 'k']

      Ici, la chaine de caractères 'shark' a été convertie en une liste, donnant une version altérable de la valeur d’origine.

      Conclusion

      Au cours de ce tutoriel sur Python, vous avez vu comment convertir plusieurs des importants types de données natives en d’autres types de données, en utilisant principalement des méthodes intégrées. Maintenant que vous savez convertir des types de données sous Python, vous disposez d’une plus grande flexibilité pour écrire vos programmes.



      Source link

      Comment lire et configurer les variables d’environnement et de shell sous Linux


      Introduction

      Au cours d’une interaction avec votre serveur via une session shell, shell compile de nombreuses informations pour déterminer son comportement et accéder aux ressources. Certains de ces réglages se font dans les paramètres de configuration, d’autres doivent être saisis par l’utilisateur.

      Le shell assure notamment le suivi de tous ces paramètres et ces détails par le biais d’une zone qu’il gère, appelée environnement. L’environnement est une zone que le shell construit à chaque fois qu’il démarre une session qui contient des variables définissant les propriétés du système.

      Dans ce guide, nous allons voir de quelle manière interagir avec l’environnement, lire ou configurer les variables d’environnement et de shell de manière interactive et via les fichiers de configuration.

      Chaque fois qu’une session shell est lancée, un processus est mis en place pour collecter et rassembler les informations qui devraient être à la disposition du processus shell et de ses processus enfant. Il obtient les données de ces paramètres à partir d’un grand nombre de fichiers et paramètres différents qui se trouvent sur le système.

      L’environnement fournit un moyen par lequel le processus shell peut obtenir ou configurer les paramètres et, à son tour, les transmettre à ses processus enfant.

      L’environnement est implémenté en tant que chaînes qui représentent des paires de valeurs clé. Si la transmission comporte plusieurs valeurs, elles sont généralement séparées par un :. Chaque paire ressemblera généralement à ceci :

      KEY=value1:value2:...
      

      Si la valeur contient un white-space significatif, des guillemets sont utilisés :

      KEY="value with spaces"
      

      Dans ces scénarios, les clés sont des variables. Elles peuvent être de deux types différents : les variables d’environnement ou les variables de shell.

      Les variables d’environnement sont des variables qui sont définies pour le shell en cours d’utilisation et héritées par tous les shells ou processus enfant. Les variables d’environnement servent à transmettre des informations dans les processus qui se déclenchent depuis le shell.

      Les variables de shell sont des variables qui sont exclusivement contenues dans le shell dans lequel elles ont été configurées ou définies. Elles sont couramment utilisées pour garder un suivi des données éphémères, comme le répertoire actuellement utilisé.

      Par convention, ces types de variables sont généralement définis par des majuscules. Cela aide les utilisateurs à distinguer les variables d’environnement dans d’autres contextes.

      Impression des variables de shell et d’environnement

      Chaque session de shell garde une trace de ses propres variables de shell et d’environnement. Nous pouvons y accéder de différentes façons.

      Nous pouvons voir une liste de toutes nos variables d’environnement en utilisant les commandes env ou printenv. Dans leur état par défaut, elles devraient fonctionner exactement de la même manière :

      Output

      SHELL=/bin/bash TERM=xterm USER=demouser LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca:... MAIL=/var/mail/demouser PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games PWD=/home/demouser LANG=en_US.UTF-8 SHLVL=1 HOME=/home/demouser LOGNAME=demouser LESSOPEN=| /usr/bin/lesspipe %s LESSCLOSE=/usr/bin/lesspipe %s %s _=/usr/bin/printenv

      Ceci est assez typique pour la sortie à la fois de printenv et env. La différence entre les deux commandes ne se voit que dans leur fonctionnalité plus spécifique. Par exemple, avec printenv, vous pouvez demander les valeurs de variables individuelles :

      Output

      /bin/bash

      En revanche, env vous permet de modifier l'environnement dans lequel les programmes s'exécutent en transmettant un ensemble de définitions de variables par le biais d'une commande, de la manière suivante :

      • env VAR1="value" command_to_run command_options

      Étant donné que, comme nous l'avons appris précédemment, les processus enfant héritent généralement des variables d'environnement du processus parent, vous pouvez remplacer les valeurs ou ajouter des variables supplémentaires à l'enfant.

      Comme vous pouvez le constater à partir du résultat de notre commande printenv, de nombreuses variables d'environnement sont configurées par les fichiers et les processus de notre système sans rien à saisir.

      Ces dernières montrent les variables d'environnement, mais comment consulter les variables de shell ?

      Pour cela, vous pouvez utiliser la commande set. Si nous saisissons set sans aucun autre paramètre, nous obtiendrons une liste de toutes les variables de shell, variables d'environnement, variables locales et fonctions de shell :

      Output

      BASH=/bin/bash BASHOPTS=checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath BASH_ALIASES=() BASH_ARGC=() BASH_ARGV=() BASH_CMDS=() . . .

      On se retrouve généralement avec une énorme liste. Il est vivement conseillé de les intégrer dans un programme de pagination afin de pouvoir traiter la quantité de résultats obtenus plus facilement :

      La quantité d'informations supplémentaires que nous recevons est quelque peu déroutante. Nous n'avons probablement pas à connaître toutes les fonctions de bash configurées, par exemple.

      Nous pouvons nettoyer le résultat en spécifiant que set devrait s'exécuter en mode POSIX, ce qui n'imprimera pas les fonctions de shell. Nous pouvons l'exécuter dans un sous-shell pour qu'il ne change pas notre environnement actuel :

      Vous obtiendrez ainsi une liste de toutes les variables d'environnement et de shell configurées.

      Nous pouvons tenter de comparer ce résultat avec celui obtenu avec les commandes env ou printenv afin d'obtenir une liste des variables de shell uniquement, mais cela risque d'être imparfait en raison des différentes façons dont ces commandes renverront les informations :

      • comm -23 <(set -o posix; set | sort) <(env | sort)

      Il est probable que la liste contienne encore quelques variables d'environnement, car la commande set déclenche les valeurs citées, tandis que les commandes printenv et env ne citent pas les valeurs des chaînes de caractères.

      Cela devrait vous donner une bonne idée des variables d'environnement et de shell qui se trouvent dans votre session.

      Ces variables sont utilisées pour toute sorte de choses. Elles vous offrent une alternative pour configurer des valeurs persistantes pour la session entre les processus, sans avoir à écrire les modifications sur un fichier.

      Variables d'environnement et de shell communes

      Certaines variables d'environnement et de shell sont très utiles et souvent référencées. Voici quelques variables d'environnement communes que vous allez rencontrer :

      • SHELL : cette variable décrit le shell qui interprétera les commandes que vous saisissez. Dans la plupart des cas, il s'agira de bash par défaut, mais d'autres valeurs peuvent être configurées si vous préférez utiliser d'autres options.
      • TERM : cette variable spécifie le type de terminal à émuler à l'exécution du shell. Il est possible d'émuler différents terminaux de matériel pour différentes exigences d'exploitation. Cependant, de manière générale, vous n'aurez pas à vous soucier de cela.
      • USER : l'utilisateur actuellement connecté.
      • PWD : le répertoire de travail en cours d'exécution.
      • OLDPWD : le précédent répertoire utilisé. Il est conservé par le shell afin de pouvoir revenir au précédent répertoire en exécutant cd-.
      • LS_COLORS : cette variable définit les codes de couleurs qui vous servent à ajouter une couleur aux résultats obtenus avec la commande ls. Elle vous permet de distinguer les différents types de fichiers et donne de plus amples informations à l'utilisateur en un coup d'œil.
      • MAIL : le chemin vers la boîte de réception de l'utilisateur en cours.
      • PATH : une liste des répertoires que le système vérifiera lorsque vous recherchez des commandes. Lorsqu'un utilisateur saisit une commande, le système vérifiera les répertoires dans cet ordre pour l'exécutable.
      • LANG : les paramètres actuels de langue et de localisation, y compris le codage de caractères.
      • HOME : le répertoire d'accueil de l'utilisateur actuellement connecté.
      • _ : la plus récente des précédentes commandes exécutées.

      En plus de ces variables d'environnement, vous verrez souvent les variables de shell suivantes :

      • BASHOPTS : la liste des options qui ont été utilisées lorsque bash a été exécuté. Cette variable peut s'avérer utile pour savoir si l'environnement de shell fonctionne de la manière dont vous le souhaitez.
      • BASH_VERSION : la version de bash en cours d'exécution, dans un format lisible par l'humain.
      • BASH_VERSINFO : la version de bash en cours d'exécution, dans un format lisible par une machine.
      • COLUMNS : le nombre de colonnes larges qui servent à dessiner le résultat à l'écran.
      • DIRSTACK : la pile des répertoires qui sont disponibles avec les commandes pushd et popd.
      • HISTFILESIZE : le nombre de lignes d'historique de commande enregistrées dans un fichier.
      • HISTSIZE : le nombre de lignes d'historique de commandes autorisées en mémoire.
      • HOSTNAME :le nom d'hôte de l'ordinateur du moment.
      • IFS : le séparateur de champ interne utilisé pour séparer les entrées sur la ligne de commande. Un espace est utilisé par défaut.
      • PS1 : la configuration de l'invite de la commande principale. Cette variable sert à définir à quoi ressemble votre invite lorsque vous commencez une session de shell. La variable PS2 permet de déclarer des invites secondaires lorsqu'une commande s'étend sur plusieurs lignes.
      • SHELLOPTS : les options de shell qui peuvent être configurées avec l'option set.
      • UID : l'IUD de l'utilisateur actuellement connecté.

      Configuration des variables de shell et d'environnement

      Pour vous aider à mieux comprendre la différence entre les variables de shell et les variables d'environnement et vous présenter la syntaxe à utiliser pour ces variables, nous allons faire une petite démonstration.

      Création de variables de shell

      Nous allons commencer par configurer une variable de shell dans notre session en cours. Ceci est facile à réaliser, nous n'avons qu'à spécifier un nom et une valeur. Nous allons adhérer à la convention qui consiste à utiliser uniquement des majuscules pour le nom de la variable et à la configurer sur une chaîne simple.

      Ici, nous avons utilisé des guillemets, car la valeur de notre variable contient un espace. De plus, nous avons utilisé des guillemets simples, car le point d'exclamation est un caractère spécial dans le shell bash qui se développe généralement en historique bash si on n'en sort pas ou s'il n'est pas mis entre des guillemets simples.

      Nous disposons maintenant d'une variable de shell. Cette variable est disponible dans notre session en cours, mais elle ne sera pas transmise aux processus enfant.

      Nous pouvons voir cela en recherchant notre nouvelle variable dans le résultat de set :

      Output

      TEST_VAR='Hello World!'

      Nous pouvons vérifier s'il ne s'agit pas d'une variable d'environnement en essayant la même méthode avec printenv :

      Aucun résultat ne devrait être renvoyé.

      Utilisons cela comme une opportunité de présenter un moyen d'accéder à la valeur de toute variable de shell ou d'environnement.

      Output

      Hello World!

      Comme vous pouvez le voir, vous faites référence à la valeur d'une variable en la faisant précéder d'un signe $. Le shell considère que cela signifie qu'il devrait substituer la valeur de la variable lorsqu'il la rencontre.

      Nous disposons donc maintenant d'une variable de shell. Elle ne devrait être transmise à aucun processus enfant. Nous pouvons générer un shell bash new à partir de notre shell actuel pour le démontrer :

      Si nous saisissons bash pour générer un shell enfant, puis tentons d'accéder ensuite au contenu de la variable, aucun résultat ne sera renvoyé. C'est ce à quoi nous nous attendions.

      Revenont à notre shell d'origine en saisissant exit :

      Création de variables d'environnement

      Maintenant, transformons notre variable de shell en variable d'environnement. Pour se faire, il faut exporter la variable. La commande qui permet de le faire se nomme à juste titre :

      Cela permettra de transformer notre variable en variable d'environnement. Nous pouvons vérifier cela en contrôlant à nouveau notre liste d'environnements :

      Output

      TEST_VAR=Hello World!

      Cette fois, notre variable s'affiche. Recommençons notre expérience avec notre shell enfant :

      Output

      Hello World!

      Super ! Notre shell enfant a reçu la variable définie par son parent. Avant de quitter ce shell enfant, essayons d'exporter une autre variable. Nous pouvons configurer les variables d'environnement en une seule étape, comme suit :

      • export NEW_VAR="Testing export"

      Vérifiez qu'elle est bien exportée en tant que variable d'environnement :

      Output

      NEW_VAR=Testing export

      Maintenant, retournons dans notre shell d'origine :

      Voyons si notre nouvelle variable est disponible :

      Aucun résultat n'est renvoyé.

      En effet, les variables d'environnement ne sont transmises qu'aux processus enfant. Il n'existe pas de moyen intégré de configurer les variables d'environnement du shell parent. Ce qui est une bonne chose dans la plupart des cas. Cela empêche également les programmes de modifier l'environnement d'exploitation à partir duquel ils ont été appelés.

      La variable NEW_VAR a été configurée comme une variable d'environnement dans notre shell enfant. Cette variable serait disponible pour elle-même et tous ses shells et processus enfant. Lorsque nous sommes revenus à notre shell principal, cet environnement a été détruit.

      Rétrogradation et annulation des variables

      Notre variable TEST-VAR est toujours définie comme une variable d'environnement. Nous pouvons la reconvertir en une variable de shell en saisissant :

      Il ne s'agit plus d'une variable d'environnement :

      Cependant, il s'agit toujours d'une variable deshell :

      Output

      TEST_VAR='Hello World!'

      Si nous voulons annuler complètement une variable, qu'elle soit de shell ou d'environnement, nous pouvons le faire avec la commande unset :

      Nous pouvons vérifier qu'elle n'est plus configurée :

      Aucun résultat n'est renvoyé car la variable a été annulée.

      Configuration de variables d'environnement à la connexion

      Nous avons déjà mentionné que de nombreux programmes utilisent des variables d'environnement pour décider des spécificités de l'utilisation de ces variables. Nous ne voulons pas avoir à configurer d'importantes variables à chaque fois que nous lançons une nouvelle session shell. Nous avons d'ailleurs déjà vu combien de variables sont déjà configurées lors de la connexion. Alors, de quelle manière créer et configurer des variables automatiquement ?

      Il s'agit en fait d'un problème plus complexe qu'il n'y paraît initialement, en raison des nombreux fichiers de configuration que le shell bash doit lire en fonction de la manière dont il est démarré.

      La différence entre les sessions de shell Login, Non-Login, Interactive et Non-Interactive

      Le shell bash lit différents fichiers de configuration en fonction de la façon dont la session est lancée.

      Il existe une manière de distinguer les différentes sessions qui consiste à établir si le shell est généré comme une session de login ou non-login.

      Un shell de login est une session de shell qui commence par l'authentification de l'utilisateur. Si vous vous connectez à une session via un terminal ou SSH et que vous vous authentifiez, votre session sera considérée comme un shell de login.

      Si vous démarrez une nouvelle session shell à partir de votre session authentifiée, comme nous l'avons fait en appelant la commande bash à partir du terminal, une session shell de non-login sera lancée. Vos données d'authentification ne vous ont pas été demandées lorsque vous avez démarré votre shell enfant.

      On peut également noter une autre distinction qui consiste à déterminer si une session de shell est interactive ou non-interactive.

      Une session shell interactive est une session shell qui est rattachée à un terminal. Une session shell non-interactive est une session qui n'est pas rattachée à une session de terminal.

      Donc, chaque session shell est classée comme étant de login ou non-login et interactive ou non-interactive.

      Une session normale qui commence par SSH est généralement une session shell de login interactive. Un script exécuté à partir de la ligne de commande est généralement exécuté dans une session shell non-interactive et non-login. Une session de terminal peut être une combinaison de ces deux propriétés.

      Que la session soit classée comme un shell de login ou non-login a des implications sur les fichiers à lire pour initialiser la session de shell.

      Une session lancée par comme une session de login lira les détails de configuration tout d'abord à partir du fichier /etc/profile. Ensuite, elle recherchera le premier fichier de configuration de shell de login qui se trouve dans le répertoire d'accueil de l'utilisateur pour obtenir des détails de configuration spécifiques.

      Elle lit le premier fichier qu'elle peut trouver sur ~/.bash_profile, ~/.bash_login et ~/.profile, et ne lit aucun autre fichier.

      En revanche, une session définie comme un shell de non-login lira le fichier /etc/bash.bashrc puis ~/.bashrc spécifique à l'utilisateur pour créer son environnement.

      Les shells non-interactifs lisent la variable d'environnement appelée BASH_ENV et lisent le fichier spécifié pour définir le nouvel environnement.

      Implémentation de variables d'environnement

      Comme vous pouvez le voir, il existe un grand nombre de fichiers différents que nous devrons généralement consulter pour placer nos paramètres.

      Cela permet une grande flexibilité et nous sera d'une grande utilité dans des situations spécifiques, lorsque nous souhaiterons avoir certains paramètres dans un shell de login et d'autres paramètres dans un shell de non-login. Cependant, la plupart du temps nous voudrons avoir les mêmes paramètres dans les deux situations.

      Heureusement, la plupart des distributions Linux configurent les fichiers de configuration de login pour obtenir les fichiers de configuration de non-login. Cela signifie que vous pouvez configurer les variables d'environnement que vous souhaitez avoir dans les deux à l'intérieur des fichiers de configuration de non-login. Ils seront ensuite lus dans les deux scénarios.

      Nous configurerons généralement des variables d'environnement spécifiques à l'utilisateur et souhaiterons que nos réglages soient disponibles dans les deux shells, de login et de non-login. Cela signifie que l'endroit où configurer ces variables se trouve dans le fichier ~/.bashrc.

      Maintenant, ouvrez ce fichier :

      Il est probable qu'il contienne déjà un certain nombre de données. La plupart des définitions ici servent à la configuration des options bash, qui ne sont pas liées à des variables d'environnement. Vous pouvez configurer les variables d'environnement comme vous le feriez avec la ligne de commande suivante :

      Toute nouvelle variable d'environnement peut être ajoutée n'importe où dans le fichier ~/.bashrc tant qu'elle n'est pas placée au milieu d'une autre commande ou pour une boucle. Ensuite, nous pouvons sauvegarder et fermer le fichier. La prochaine fois que vous lancerez une session de shell, la déclaration de votre variable d'environnement sera lue et transmise à l'environnement shell. Vous pouvez forcer votre session actuelle à lire le fichier en saisissant ce qui suit :

      Si vous devez configurer des variables à l'échelle du système, vous devriez éventuellement envisager de les ajouter à /etc/profile, /etc/bash.bashrc, ou /etc/environment.

      Conclusion

      Les variables d'environnement et de shell sont toujours présentes dans votre session shell et peuvent s'avérer très utiles. Il s'agit d'un moyen intéressant pour un processus parent de paramétrer les détails de configuration de ses processus enfant et de configurer des options en-dehors des fichiers.

      Ce qui peut être très avantageux dans des situations spécifiques. Par exemple, certains mécanismes de déploiement dépendent des variables d'environnement pour configurer les données d'authentification. Ceci est utile, car vous n'avez pas besoin de la conserver dans des fichiers qui pourraient être vus par des tiers.

      Il existe de nombreux autres scénarios, plus banals, mais plus courants, dans lesquels vous devrez lire ou modifier l'environnement de votre système. Avec ces outils et ces techniques, vous disposez d'une bonne base pour apporter ces modifications et les utiliser correctement.



      Source link

      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