LINUX:HTTP - Gestion des accès

De WIKI sur Linux (ADB)
Aller à la navigation Aller à la recherche

retour au serveur Web


But

Un aspect très important a trait à la gestion des accès à vos sites Web en totalité ou partiellement. Il a été abordé partiellement dans d'autres articles.

Nous allons passer en revue différentes approches globales ou particulières.


FireWall - IPTABLES

Un FireWall apporte une approche globale pour toute la machine.


Filtrage de base

Nous utilisons IPTABLES. Voyez l'article sur Firewall ou mur de feu.

Classiquement le port TCP/80 est utilisé pour le service HTTP et le port TCP/443 pour le service HTTPS. Il est possible d'utiliser d'autres ports.00

Dans les configurations qui suivent, nous ne présenterons que la partie strictement concernant le service HTTPD paramétré par défaut en entrée:

  • L'ouverture globale permet à tous d'avoir accès à vos sites Web.

...
-A INPUT -p tcp -m tcp --dport 80  -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
...
-A INPUT -j DROP

  • On peut vouloir ne donner l'accès qu'à certaines machines selon les adresses IP. Dans cet exemple, nous ne donnons l'accès qu'aux machines de notre LAN privé "192.168.1.0/24". Dans cette optique, on pourrait donner l'accès qu'à un partenaire de confiance selon son adresse IP publique.

...
-A INPUT -p tcp -m tcp --dport 80  -s 192.168.1.0/24 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -s 192.168.1.0/24 -m conntrack --ctstate NEW -j ACCEPT
...
-A INPUT -j DROP

  • On peut vouloir bloquer une machine particulière ("95.214.27.19") car elle nous fait régulièrement des attaques de type DOS mais ouvrir aux autres.

...
-A INPUT -p tcp -m tcp --dport 80  -s 95.214.27.19                            -j DROP
-A INPUT -p tcp -m tcp --dport 443 -s 95.214.27.19                            -j DROP
-A INPUT -p tcp -m tcp --dport 80                  -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443                 -m conntrack --ctstate NEW -j ACCEPT
...
-A INPUT -j DROP


Ces règles peuvent être démultipliées selon nos besoins.

Attention, l'ordre des règles est important. Par exemple, dans l'exemple précédent, si nos deux premières lignes de type "DROP" sont placées après nos lignes de type "ACCEPT", la machine "95.214.27.19" ne sera jamais bloquée. Car dès qu'une demande d'accès rentre dans les critères d'une règle, cette règle est appliquée et le traitement n'est pas poursuivi.


Filtrage par pays

Il est possible d'ajouter une fonctionnalité de filtrage à IPTABLES en suivant l'article sur XTABLES-ADDONS.

Un de ces filtrages peut se faire sur base du pays d'origine de la requête. Chaque pays a à sa disposition des tranches d'adresses IP; celles-ci sont regroupées dans une base de données. IPTABLES interroge celle-ci qui doit être mise à jour régulièrement.

Voici deux types d'approche:

  • Empêcher l'accès de requête provenant de divers pays, dans l'exemple, la Chine et la Russie.

...
-A INPUT -p tcp -m tcp --dport 80  -m geoip --src-cc CN,RU    -j DROP
-A INPUT -p tcp -m tcp --dport 443 -m geoip --src-cc CN,RU    -j DROP
-A INPUT -p tcp -m tcp --dport 80  -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
...
-A INPUT -j DROP

  • Ne permettre l'accès qu'à certains pays, dans l'exemple, la Belgique et ses pays limitrophes.

...
-A INPUT -p tcp -m tcp --dport 80  -m geoip --src-cc BE,FR,NL,DE,LU -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -m geoip --src-cc BE,FR,NL,DE,LU -m conntrack --ctstate NEW -j ACCEPT
...
-A INPUT -j DROP


Remarque

Il ne faut pas oublier de contrôler les accès en sortie. Nombre de sites Web font des accès vers d'autres sites Webs par exemple pour récupérer un script JavaScript ou une image hébergés sur une autre machine publique. Ils peuvent aussi envoyer des informations sur votre machine ou vos clients sans votre accord ou même valider une clé d'utilisation.


HTTPD - Apache

De son côté, Apache possède des contrôles d'accès beaucoup plus fins.

Ces règles peuvent être placées dans les fichiers ".htaccess", pour autant qu'ils soient activés via la directive "AllowOverride All" mais nous préférons les mettre dans les fichiers de configuration d'Apache pour avoir une vue centralisée, facile à sauvegarder.


Accès de base

Nous allons passer en revue quelques fonctions autour de la directive "Require" venant avec la version 2.4 d'Apache. Elles viennent avec les modules "mod_authz_core" et "mod_authz_host". Auparavant il existait une directive semblable que nous n'aborderons pas car elle est déconseillée.


Portées

Les règles doivent se retrouver à l'intérieur des balises:

  • <Directory ...> ... </Directory> : Les règles concernent les fichiers et sous-répertoires sous le répertoire spécifié à toute l'arborescence en dessous.
  • <Files ...> ... </Files> : Les règles concernent les fichiers spécifiés.
  • <Location ...> ... </Location> : Les règles ont une portées indépendantes des répertoires et fichiers. Elles concernent les gestionnaires d'Apache (handlers) spécifiés par la directive "SetHandler". On a rencontré quelques cas dans l'article sur les Informations et Activités d'Apache. On ne l'abordera pas mais les règles agissent de la même façon.

Dans ces balises, on spécifie un paramètre qui correspond respectivement à un nom de répertoire ou de fichiers.


  • Exemples pour "<Directory>":

Dans le fichier "/etc/httpd/conf/httpd.conf", on trouve les lignes suivantes:


<Directory />
  Require all denied
</Directory>

Elles permettent de protéger, bloquer tout accès à toute l'arborescence de la machine via sa racine ("/"). Elles sont fondamentales.

On peut ouvrir des sous parties de l'arborescence par la suite; par exemple:


<Directory /web/wordpress>
  Require all granted
</Directory>

on ouvre l'arborescence du sous-répertoire "/web/wordpress".

  • Exemple pour "<Files>":

Dans le fichier "/etc/httpd/conf/httpd.conf", on trouve les lignes suivantes:


<Files ".ht*">
  Require all denied
</Files>

qui protègent principalement les fichiers ".htaccess" qui contiennent des directives de configuration d'Apache; elles ne doivent pas être consultables au travers d'un interface Web.


Règles

Les règles viennent avec la directive "Require" suivie de divers paramètres; nous n'aborderons que les cas les plus courants:

  • Require all granted : Elle donne accès à tous.
  • Require all denied : Elle bloque l'accès à tous.
  • Require ip <adresse IP> : Elle donne l'accès au groupe d'adresses IP.
  • Require not ip <adresse IP> : Elle bloque l'accès au groupe d'adresses IP.
  • Require local : Elle donne l'accès à la machine locale; elle est équivalente à la règle "Require ip 127.0.0.1".
  • Require host <nom de machine> : Elle donne accès à la machine nommée.
  • Require not host <nom de machine> : Elle bloque accès à la machine nommée.


Prenons l'exemple simplifié, sans les autres options, d'un fichier de configuration pour le CMS WordPress:

  • On donne l'accès à tous.

DocumentRoot "/web/wordpress"
 
<Directory /web/wordpress>
  Require all granted
</Directory>

  • On ne donne l'accès qu'au réseau local ("192.168.1.0/24") et à la machine locale,; les autres sont bloqués.

DocumentRoot "/web/wordpress"
 
<Directory /web/wordpress>
  Require all denied
  Require local
  Require ip 192.168.1
</Directory>

Notons que la règle:


Require ip 192.168.1

est équivalente à:


Require ip 192.168.1.0/24

ou


Require ip 192.168.1.0/255.255.255.0

  • On veut donner l'accès à tous mais restreindre l'accès aux outils d'administration qu'aux machines du réseau local.

DocumentRoot "/web/wordpress"
 
<Directory /web/wordpress>
  Require all granted
</Directory>
 
<Directory /web/wordpress/wp-admin>
  Require all denied
  Require ip 192.168.1
</Directory>

  • On ajoute l'impossibilité de s'authentifier sauf pour ceux du réseau local. Pour y arriver, on filtre l'accès au fichier "wp-login.php".

DocumentRoot "/web/wordpress"
 
<Directory /web/wordpress>
  Require all granted
 
  <Files wp-login.php>
    Require all denied
    Require ip 192.168.1
  </Files>
</Directory>
 
<Directory /web/wordpress/wp-admin>
  Require all denied
  Require ip 192.168.1
</Directory>


Avec un peut d'habitude, dans un site, il y a beaucoup de sous-répertoires qui ne nécessitent pas un accès direct de l'utilisateur car ils sont seulement utilisés par Apache en interne au travers par exemple du sous-processus PHP.


Gestion groupée des règles

Il existe trois groupes de balises qui permettent une gestion de type logique des règles; elles peuvent être imbriquées pour un contrôle d'accès complexe:

  • <RequireAny> ... </RequireAny> : Au moins une des règles du groupe doit être validée. Elles sont définies par défaut.
  • <RequireAll> ... </RequireAll> : Toutes les règles du groupe doit être validée.
  • <RequireNone> ... </RequireNone> : Aucune les règles du groupe ne doit être validée.

Une règle peut donner l'accès ou la refuser.

  • Exemple 1:

Require all denied
Require ip 192.168.1

est équivalent à:


<RequireAny>
 Require all denied
 Require ip 192.168.1
</RequireAny>

  • Exemple 2:

<RequireAll>
 <RequireAny>
   Require all denied
   Require local
   Require ip 192.168.1
 </RequireAny>
 Require valid-user
</RequireAll>

Pour avoir accès, le machine client doit être soit locale ("127.0.0.1" ou "localhost") soit du réseau local "192.168.1.0/24". En outre l'utilisateur auquel on demande une authentification doit être correctement validé par le couple nom d'utilisateur et son mot de passe. Nous avons ici une combinaison d'une logique "ET" et "OU" imbriquées


Accès par authentification de l'utilisateur

Apache intègre un contrôle d'accès via une authentification d'un utilisateur. Cette approche est élémentaire mais elle peut aider si le site n'inclut pas cette stratégie. Nous allons seulement aborder le cas le plus simple, celle de base.


La première étape consiste à créer un fichier où sont repris les couples "nom d'utilisateur" et son "mot de passe":

htpasswd -c <nom de fichier d'authentification> <utilisateur> <mot de passe>

Par exemple, on crée l'utilisateur "pdupond" dans le fichier "/etc/httpd/conf.d/perso.users":

htpasswd -c /etc/httpd/conf.d/perso.users pdupond BateauIvre

Par la suite l'option "-c" est à remplacer par "-b" pour ajouter d'autres utilisateurs. Le mot de passe est crypté.


Dans le fichier de configuration d'Apache d'un site Web personnel, on ajoute les lignes suivantes:


DocumentRoot "/web/perso"
 
<Directory /web/perso>
  AuthType Basic
  AuthBasicProvider file
  AuthUserFile /etc/httpd/conf.d/perso.users
  AuthName "Accès au site Perso"
 
  Require all denied
  Require valid-user
</Directory>

On utilise une authentification de base ("Basic") sur base d'un fichier ("file") dont on donne le nom correspondant à celui créé plus haut ("/etc/httpd/conf.d/perso.users") pour les utilisateurs. Enfin on utilise une règle qui sert à valider une authentification réussie ("Require valid-user").


Accès par pays

Comme au niveau du FireWall, il est possible de filtrer les accès selon le pays.


Géolocalisation IP

La première étape consiste à installer la base de données de géolocalisation IP et de la mettre à jour régulièrement. Suivez l'article sur la Géolocalisation IP. La géolocalisation IP est un moyen de connaitre d'où vient la requête réseau via Internet en se basant sur l'adresse IP du correspondant.


Installation du module

Maintenant il faut installer un module pour Apache qui puisse interroger la base de données de géolocalisation IP via la commande:

dnf install mod_maxminddb


Interrogation de la base de données de géolocalisation IP

Pour interroger la base de données de géolocalisation IP, nous devons connaitre la structure de celle-ci.

La commande suivante permet d'obtenir une sortie de type JSON. L'exemple interroge une adresse IP donnée:

mmdblookup -f /usr/share/GeoIP/GeoLite2-Country.mmdb -i 81.246.173.44

La sortie a été réduite au niveau des langues.


 {
   "continent":
     {
       "code":
         "EU" <utf8_string>
       "geoname_id":
         6255148 <uint32>
       "names":
         {
           "en":
             "Europe" <utf8_string>
...
         }
     }
   "country":
     {
       "geoname_id":
         2802361 <uint32>
       "is_in_european_union":
         true <boolean>
       "iso_code":
         "BE" <utf8_string>
       "names":
         {
           "en":
             "Belgium" <utf8_string>
...
         }
     }
   "registered_country":
     {
       "geoname_id":
         2802361 <uint32>
       "is_in_european_union":
         true <boolean>
       "iso_code":
         "BE" <utf8_string>
       "names":
         {
           "en":
             "Belgium" <utf8_string>
...
         }
     }
 }

Ce qui va nous intéresser est la zone "iso_code" du pays ("country"). Nous avons donc deux niveaux: "country" suivi de "iso_code". Dans l'exemple nous y trouvons le code "BE" pour la Belgique.


Configuration d'Apache

Il faut ensuite configurer Apache afin de pouvoir utiliser ce type de filtrage.


La première partie concerne l'appel et la configuration du module "maxminddb".

Voici la configuration classique sur base du code du pays.


MaxMindDBEnable On
MaxMindDBFile COUNTRY_DB /usr/share/GeoIP/GeoLite2-Country.mmdb
MaxMindDBEnv MM_COUNTRY_CODE COUNTRY_DB/country/iso_code

  • La première ligne active le module.
  • La seconde définit que la base de données de géolocalisation par pays sera utilisée et range le nom du fichier de la base dans la variable "COUNTRY_DB".
  • La troisième définit la variable dans laquelle sera rangée le code du pays du requérant trouvé dans la base selon son adresse IP. Pour trouver la bonne valeur, la chaîne "COUNTRY_DB/country/iso_code" définit la suite des zones à suivre pour y arriver. Dans le fichier "COUNTRY_DB", on se place au niveau du pays ou "country" et parmi les valeurs qu'il rassemble, on sélectionne la variable "iso_code".


Ensuite on teste le code du pays récupéré en le comparant avec la liste désirée; si ce test est validé, la variable "AllowCountry" est créé. Ici la liste des pays retenus sont la Belgique et ses pays limitrophes.


SetEnvIf MM_COUNTRY_CODE ^(BE|FR|LU|DE|NL) AllowCountry

On peut placer une valeur dans cette variable, par exemple "1":


SetEnvIf MM_COUNTRY_CODE ^(BE|FR|LU|DE|NL) AllowCountry=1

Ce nom de variable peut être nommé selon votre désir.


Enfin vient la règle qui va tester la présence de cette variable.


Require env AllowCountry


Si on reprend la configuration de l'exemple pour WordPress plus haut, on peut étendre les permissions d'accès à l'administration et au "login" à la Belgique et à ses pays limitrophes.


DocumentRoot "/web/wordpress"
 
MaxMindDBEnable On
MaxMindDBFile COUNTRY_DB /usr/share/GeoIP/GeoLite2-Country.mmdb
MaxMindDBEnv MM_COUNTRY_CODE COUNTRY_DB/country/iso_code
 
<Directory /web/wordpress>
  Require all granted
 
  <Files wp-login.php>
    SetEnvIf MM_COUNTRY_CODE ^(BE|FR|LU|DE|NL) AllowCountry
    Require all denied
    Require ip 192.168.1
    Require env AllowCountry
  </Files>
</Directory>
 
<Directory /web/wordpress/wp-admin>
  SetEnvIf MM_COUNTRY_CODE ^(BE|FR|LU|DE|NL) AllowCountry
  Require all denied
  Require ip 192.168.1
  Require env AllowCountry
</Directory>

Évidemment le service Httpd doit être relancé pour que cette configuration entre en action.

Il est possible de filtrer par la négative par exemple pour bloquer certains pays au lieu de les accepter.


<RequireAll>
  Require all granted
  Require not env AllowCountry
</RequireAll>

Il est conseillé d'activer ce filtrage le plus localement possible car il ralentit le système.


Journalisation

Si on ajoute l'option suivante en début de fichier,:


MaxMindDBSetNotes On

on pourra afficher le contenu des variables dans le journal d'Apache "/var/log/https/access_log".

Mais il faut adapter le format qui se trouve habituellement dans le fichier "/etc/httpd/conf/httpd.conf". Par exemple pour les deux variables "MM_COUNTRY_CODE" et "AllowCountry", on ajoute deux zones au format:


LogFormat " ... %{MM_COUNTRY_CODE}e %{AllowCountry}e ... " ...

Notons que ce mode demande des ressources et est à utiliser comme un mode de "debug".




retour au serveur Web