Sécurité sous Apache

 

La sécurité se fera tout d'abord au niveau du serveur Web pour protéger celui-ci d'attaques extérieures comme le DDOS par exemple, mais aussi pour ne pas géner d'éventuels utilisateurs qui en parallèle utilisent la même machine pour d'autres raisons: Limiter Apache dans la consommation des ressources disponibles et permettre ainsi aux autres utilisateurs/applications de la machine de travailler/fonctionner correctement.

Mais cela n'est pas tout, votre site web aura aussi besoin d'être sécurisé pour éviter que n'importe qui n'accède à des informations confidentielles par exemple...

 

Fichier de configuration

Suivant la distribution, le fichier de configuration principal d'Apache peut se situer sous

  • /etc/httpd/conf/httpd.conf
  • /etc/apache2/apache2.conf
 

 

 

Sécuriser le serveur Web Apache

A lire pour tous serveurs installés en zone DMZ, donc accessibles depuis l'extérieur.

La bannière

Une solution pour pirater un serveur pour un hacker est déjà de récupérer des informations sur ce serveur. Cela lui permettra de s'orienter sur tel ou tel solution d'attaque.

Or Apache peut être bavard ! Un peu trop même !

Il suffit de faire un telnet sur l'ip du serveur sur le port 80 (celui utilisé normalement pour le protocole http) pour récupérer des informations sur le serveur, sa version, la distribution (Linux, Microsoft) sur laquelle tourne le serveur Apache, la version php et les modules, ... (il s'agit de la bannière retournée par le serveur).

Ce qui devrait déjà bien orienter le hacker pour les failles et lui permettre un piratage de votre machine !

Bref il faut faire taire Apache !

Ajoutez (si non présent) dans

  • /etc/httpd/conf/httpd.conf
ou
  • /etc/apache2/apache2.conf
 

La ligne suivante:

ServerTokens Prod

 

Signature

En plus d'être bavard, il se signe ! Par exemple lors d'affichage des codes erreurs !

Vite, stoppez cela en ajoutant par la même occasion:

ServerSignature Off

De plus, créez vos pages de gestion des erreurs en restant le plus général que possible dans l'explication sur l'erreur (inutile de préciser que l'erreur vient de tel et tel chose. Dîtes simplement qu'il y a une erreur, la requète ne pourra pas aboutir !), cela reduira les risques !

 

Interdire l'utilisation d'encodage de / ou \

%2F pour / ou %5C pour \ peut permettre l'utilisation de séparateurs de chemin encodés. C'est à éviter pour ne pas risquer de se retrouver dans des chemins non sûrs:

AllowEncodedSlashes off : valeur par défaut dans apache, provoque une erreur 404

AllowEncodedSlashes nodecode : autorise l'utilisation de ces codes, mais ne seront pas décodé et laissés tel quel.

AllowEncodedSlashes on : autorise les URL et seront décodés , à utiliser dans ce cas avec PATH_INFO

 

Sécuriser les ressources de la machine

Le serveur Apache lance des processus (sorte de mini serveurs) qui serviront des requètes provenant d'un client. C'est processus consommant de la ressource machine.

La sécurité de votre serveur passe donc par la gestion des ressources attribuées aux processus gérant les requètes provenant des clients.

Le risque étant de:

  • saturer la mémoire vive car trop de processus par rapport aux ressources disponibles, ou à cause de fuite de mémoire liée à des bugs
  • ou encore un temps de réponse trop long, bloquant toutes les autres requètes qui arrivent et partent en file d'attente.

Pour réduire ce risque, il faudra poser des limites aux processus ...

 

La directive MaxClients

MaxClients permet d'indiquer le nombre maximum de requètes pouvant être servies en parallèle. Surtout utilisée lorsqu'il y a peu de mémoire RAM et éviter ainsi le swapping, puisque cela limitera le nombre de processus qui peuvent sinon faire grimper l'occupation mémoire (fuite de mémoire, utilisation de frameworks gourmands). Permet aussi de limiter le risque de faire tomber le serveur suite à des attaques.

Si vous avez positionné trop bas MaxClients, les requètes vont se retrouver en file d'attente (file d'attente elle même limitée en taille via la directive ListenBacklog), Ces requètes risquant aussi de tomber en time out si elles ne sont pas traitées suffisement à temps.

Si vous positionnez trop haut MaxClients, vous risquez d'exploser l'occupation en mémoire vive et de basculer en swapping des traitements.

Une solution pour estimer cette valeur sera de lancer la commande ps qui affiche la liste des processus, avec en paramètre "aux" pour avoir le détails des ressources occupées par tous les processus chargées en mémoire. Dans la colonne rss, la quantité de mémoire occupée par processus.

Arrêtez Apache, puis lancez la commande ps -aux

Faîtes la somme et vous connaîtrez ainsi la place mémoire occupée pour votre système et pour les utilisateurs.

Relancez Apache,

Vous pouvez retrouver ses processus Apache en relançant la commande ps -aux (l'utilisateur associé aux processus peut avoir divers noms dépendant de votre système. Par exemple www-data)

Sachant qu'un processus dans apache occupe un peu moins de 15 Mo avec du php (encore moins si static) et connaissant la quantité totale de mémoire vive, vous pourrez en déduire le nombre maximum de clients:

MaxClients = (Taille mémoire vive - taille processus) / 15

AttentionMaxClients peut avoir une valeur maximum égale à 256. Au delà, il faudra augmenter ServerLimit

NotePour les serveurs non threaded, voir Apache MPM prefork MaxClients qui est par défaut à 256

 

Gestion du nombre de processus et relance

Nombre de processus au lancement d'apache

StartServers permet d'indiquer le nombre de processus à créer au lancement d'apache.

StartServers 8 va ainsi créer 8 processus lors du démarrage.

 

Nombre de processus durant le fonctionnement d'apache

MinSpareServers, MaxSpareServers permettent de fixer le nombre de processus. Si le nombre est inférieur à MinSpareServers, de nouveaux processus seront créés. Si ce nombre de processus dépasse MaxSpareServers, des processus seront tués.

AttentionLa création d'un processus prend du temps, il faudra régler ce nombre suffisement correctement pour limiter ces ralentissements.

 

Nombre de requètes par processus

MaxRequestsPerChild: Permet de limiter le nombre de requètes sur un processus. Au delà, il sera supprimé et relancé

NoteDans le cas d'une connexion persistante , n requètes envoyées durant cette connexion persistante seront considérées comme 1 seule requète.

MaxRequestsPerChild 0 : Dans ce cas, le processus ne sera jamais tué.

Une tout autre valeur indiquant le nombre de requètes maximum avant de tuer et lancer un nouveau processus.

 

Timeout

Timeout nbseconde précise le temps que peut occuper une connexion avant de tomber en time out.

 

Limiter les connexions persistantes

Un processus peut répondre à une requète d'un client, mais peut aussi conserver une connexion avec celui-ci si le client désire en fait envoyer plusieurs "sous"-requètes. Ceci afin de limiter le nombre de connexions qui sont gourmandes en temps.

Je dis "sous"-requètes, car Apache considère toutes ces requètes globalement, c'est à dire comme une seule et même requète.

Si vous avez activé les connexions persistantes, le but ici sera de limiter le nombre de requètes lors de cette connexion persistante (là aussi, afin de limiter les problèmes liés par exemple à des fuites de mémoires) ainsi que de définir un time out sur les connexions persistantes prenant trop de temps.

D'où les explications qui suivent...

 

Réutilisation d'une connexion (ou connexion persistante)

KeepAlive est apparue avec la norme HTTP 1.1, et permet de réutiliser une connexion ouverte par un client (connexion persistante). Cela évite au client de refaire des ouvertures de connexions successives et donc gain de temps. Le processus gérant cette connexion n'est alors pas tué. Cela peut être intéressant d'avoir une valeur suffisante avec des pages utilisant fortement de l'ajax.

Vous activez la gestion d'une connexion persistante:

KeepAlive on

sur off sinon.

 

AttentionLe problème est qu'en cas d'attaque, le trafic devienne lent, la mémoire réservée par le processus fasse tomber le serveur via l'utilisation d'une faille provoquant l'apparition de fuites de mémoire, d'où l'importance des instructions qui suivent:

 

MaxKeepAliveRequests Pour limiter le nombre de requètes sur une connelxion persistante, en baissant la valeur, le processus lié à la connexion va mourir plus vite libérant ainsi la mémoire vive (dont les fuites de mémoires). Mais en contre partie, le client devra refaire plus de connexions, donc ralentissement possible.

MaxKeepAliveRequests 50 qui limite à 50 les requètes sur une connexion persistante.

 

KeepAliveTimeout: En seconde, permet d'indiquer un timeout et donc de limiter la durée de conservation d'une connexion persistante.

KeepAliveTimeout 5 limitera ainsi la connexion à 5 secondes

 

NoteMaxRequestsPerChild vs MaxKeepAliveRequests:

MaxRequestsPerChild ne comptabilise qu'une seule requète d'une connexion persistante même si n requètes sont émises par le client. MaxKeepAliveRequests comptabilise qu'en à lui n requètes durant une connexion persistante.

 

 

Sécuriser votre site

Après avoir sécurisé votre serveur Apache, il faut sécuriser votre site...

AllowOverride

En principe, une directive est positionnée sur un répertoire et par héritage aux sous répertoires.

Il est possible d'indiquer que les sous répertoires peuvent avoir eux-même leur propre fichier de directives (dans .htaccess) ou non.

AllowOverride None : interdit à Apache de gérer les fichiers .htaccess présents dans les sous répertoires.

AllowOverride All: autorise Apache à gérer toutes les directives des fichiers .htaccess présents dans les sous répertoires.

AllowOverride [type directive] [type directive] [...] pour autoriser certaines directives suivant le type directive précisé.

ou type directive peut être AuthConfig FileInfo Indexes Limit Options[=Option,...].

Cf. https://httpd.apache.org/docs/2.2/fr/mod/core.html#allowoverride pour plus de détails

 

Limité l'accès

Syntaxe Listen [adresse ip]:port [protocol]

ip: adresse ip v4 ou v6 (dans ce cas l'adresse doit être entre [])

protocol par défaut est http, https pour le port 443

Exemple:

Listen 80

Listen 8080

Le serveur écoutera le port 80 et 8080 pour le protocol http

Pour lancer un protocol sur un port non standard (ex. https)

Listen 8443 https

Si vous voulez limiter votre serveur Apache à une ip (serveur dev par exemple), utilisez/modifiez le paramétrage Listen par exemple Listen 192.168.0.1:80

Dans /etc/apache2/ports.conf, /etc/apache2.conf ou encore /etc/httpd/conf/httpd.conf suivant votre serveur apache.

Des listen imbriquées provoqueront une erreur fatale: (48)Address already in use: make_sock: could not bind to address [::]:80

 

Codage de votre site

L'autre point extrèmement important à surveiller et votre code lui-même. Surtout si celui-ci vient à manipuler des données saisissables...

Ces données pouvant provenir de champs de saisie, mais aussi être passé directement en paramètre dans votre URL.

De façon général, il ne faut pas traiter les données brutes qui arrivent, mais convertir tout ce qui pourrait être autre chose que des paramètres en paramètre même si inexploitable ensuite par votre code.

Interdit donc de traiter des chemins d'accès à vos pages webs, ils pourraient donner bien plus d'informations sur votre environnement ou permettre l'exécution de code distant pour hacker votre site ! Préférez l'utilisation de références à des pages, vous serez ainsi obligé de passer par une table de correspondance entre la référence et la page réelle.

Voici un exemple de tentative que je reçois régulièrement sur mon site:

2015-08-22 04:37:12 404bis --> Page non trouvée: ../../../../../../../../../../../etc/passwd
2015-08-22 04:37:15 404bis --> Page non trouvée: ../../../../../../../../../../../../etc/passwd
2015-08-22 04:37:09 404bis --> Page non trouvée: ../../../../../../../../../../etc/passwd
2015-08-22 04:37:07 404bis --> Page non trouvée: ../../../../../../../../../etc/passwd
2015-08-22 04:37:06 404bis --> Page non trouvée: ../../../../../../../../etc/passwd
2015-08-22 04:37:04 404bis --> Page non trouvée: ../../../../../../../etc/passwd
2015-08-22 04:37:01 404bis --> Page non trouvée: ../../../../../../etc/passwd
2015-08-22 04:36:59 404bis --> Page non trouvée: ../../../../../etc/passwd
2015-08-22 04:36:57 404bis --> Page non trouvée: ../../../../etc/passwd
2015-08-22 04:36:55 404bis --> Page non trouvée: ../../../etc/passwd
2015-08-22 04:36:52 404bis --> Page non trouvée: ../../etc/passwd
2015-08-22 04:36:51 404bis --> Page non trouvée: ../etc/passwd
2015-08-22 04:36:50 404bis --> Page non trouvée: /etc/passwd

Il le voulait le fichier passwd ! Mais il ne l'a pas eu !

Ou encore tentative d'exécution de code:

Page non trouvée: ftp://2015julho:eueu2301@ftp.uhserver.com/tt.php??

Page non trouvée: http://trojka.miedzyrzec.org.pl/grafika/made.jpg?

 

Mais attention, interdit aussi d'accepter des commandes SQL pour les mêmes raisons. On parlera alors d'injection SQL. Il s'agit d'ajouter à des paramètres une commandes SQL qui, si vous n'y prenez pas garde pourront retourner bien plus que ce que vous pensiez initialement !

Voici un exemple de commandes régulièrement saisies sur mon site:

Il y a bien passage d'un paramètre, ici 999999.9, puis juste derrière un "complément de paramètres" qui, sans protection, serait interprété par SQL comme étant un complément de ma commande SQL initiale

999999.9 union all select 0x31303235343830303536,0x31303235343830303536,0x31303235343830303536, [...]

Et j'en ai encore pleins d'autres des comme cela dans mon historique ...

Donc en recevant une donnée (j'ai presque envie de mettre un s à une donnée !), il faut impérativement neutraliser toutes fonctions qui pourraient y être intégrées...

Pensez-y lors de vos développements !

 

Cryptage des informations sur le réseau

Comprendre HTTPS sous apache, le HTTP crypté.

Apache sait travailler avec le protocole HTTPS (port 443). Cela passe cependant par un certificat SSL, une clef publique servant au décryptage signé numériquement par un clef privée. Ces clefs privées devraient être fournis par une Autorité de Certification légitime et fiable...dont le service est payant.

Ici, hors de question de payer pour cela:

  • Vous pouvez passer par startssl.com pour une version de certificat gratuit: https://www.startssl.com/Support?v=1
  • Vous faites donc vous même votre certificat, mais en contrepartie, les navigateurs indiqueront au moins une fois à l'utilisateur que votre serveur utilise un certificat non fiable...car le celui-ci n'a pas été signé par une source fiable.

Il faut les privilèges du root. Vous utiliserez donc sudo ou su.

Pour produire une clef SSL (TSL), vous pouvez utiliser openSSL

  • Créer un répertoire ssl qui recevra les fichiers:

Sous le chemin chemin_apache qui sera remplacé par /etc/apache2 ou /etc/httpd suivant la version de votre Apache.

mkdir /chemin_apache/ssl

  • Puis la commande openssl (installez le paquet openssl si nécessaire).

openssl req -x509 -nodes -days nb_jours -newkey rsa:2048 -out /chemin_apache/ssl/server.crt -keyout /chemin_apache/ssl/server.key

-x509 -nodes: type de certificat voulu

days: validité du certificat en jour (365 pour 1 an, ...)

rsa: Nombre de bits pour la clé RSA (ici 2048)

server.crt: certificat

server.key: la clef privée

 

Des questions vous seront posées:

Generating a 2048 bit RSA private key
...........+++
..........+++
writing new private key to '/etc/httpd/ssl/server.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:FR
State or Province Name (full name) [Default Province]:FRANCE
Locality Name (eg, city) [Default City]:votre_ville
Organization Name (eg, company) [Default Company Ltd]:le_nom_de_votre_société ou votre_pseudo par exemple
Organizational Unit Name (eg, section) []:Recopiez la ligne précédente
Common Name (e.g. server FQDN or YOUR name) []:Le nom_du_domaine_à_sécuriser
Email Address []:Eventuellement votre mail

  • Protégez votre clé privé générée dans le fichier server.key à la lecture en tapant:

chmod 700 /chemin_apache/ssl/server.key

  • Activer le SSL pour Apache. Il s'agit d'un module nommé ssl, donc:

a2enmod ssl

  • configurer les options par défaut des sites pour le SSL. Il s'agit d'indiquer la localisation du certificat et de la clef privée.

Suivant la version de votre serveur apache,

  • dupliquez le fichier /etc/httpd/conf/sites.d/00_default_vhosts.conf en 00_default_vhosts_ssl.conf

cp /etc/httpd/conf/sites.d/00_default_vhosts.conf /etc/httpd/conf/sites.d/00_default_vhosts_ssl.conf

  • ou dupliquez le fichier /etc/apache2/sites-available/default.conf en default-ssl.conf

cp /etc/apache2/sites-available/default.conf /etc/apache2/sites-available/default-ssl.conf

Et recopiez les lignes suivantes dans ce nouveau fichier de configuration:

SSLEngine on (ou off pour désactiver le moteur ssl)
SSLCertificateFile /chemin_apache/ssl/server.crt
SSLCertificateKeyFile /chemin_apache/ssl/server.key

  • Suivant la version de votre serveur apache, rendez enable votre nouveau fichier de configuration par défaut pour qu'Apache le traite par la suite:

a2ensites /etc/apache2/sites-available/default-ssl.conf

  • Indiquez à Apache qu'il doit se mettre en écoute sur le port 443

Là encore, suivant le version de votre serveur Apache, ajoutez (si absent) la ligne suivante:

Listen 443

  • Soit dans /etc/httpd/conf/httpd.conf
  • Soit dans /etc/apache2/ports.conf
  • Il sera possible de faire des redirections automatiques de votre site vers https si un visiteur arrive via http.

Il suffit de modifier vos fichiers de configuration de vos sites en ajoutant

<VirtualHost 192.168.0.n:80>

ServerName mon_site
Redirect / https://mon_site

</VirtualHost>

<VirtualHost 192.168.0.n:443>

ServerName mon_site
DocumentRoot /var/www/html/mon_site

SSLEngine on
SSLCertificateFile /chemin_apache/serverbis.crt
SSLCertificateKeyFile /chemin_apache/serverbis.key

</VirtualHost>

Vous noterez au passage que vous pouvez indiquer de nouveaux certificats ou clefs privées (ici serverbis.crt et serverbis.key) pour ces sites en ajoutant de nouveaux les lignes SSL...

  • Relancer votre serveur Apache pour prendre en compte vos modifications.

 

NotePensez bien à remplacer chemin_apache par le bon répertoire vers les fichiers de configuration du serveur Apache.

NoteN'oubliez pas de rediriger le port 443 vers votre serveur en zone DMZ sur votre router.

 

NotePour plus d'informations sur le Module Apache mod_ssl, voir https://httpd.apache.org/docs/2.4/fr/mod/mod_ssl.html#sslproxycheckpeercn

 

Allez plus loin

Sous Linux, il est déconseillé de déclarer un filtre Apache2 dans inet ou xinet. De plus, Apache2 ne possède pas la librairie pour une gestion sous tcp wrapper, donc Apache ne traite pas les fichiers /etc/hosts.allow et /etc/hosts.deny.

Il sera par contre possible d'utiliser l'outil fail2ban pour limiter les accès de type brute force pour les connexions demandant un mot de passe par exemple.

Pour interdire certaines adresses ip ou domaines, il sera possible de paramétrer votre fichier .htaccess (si disponible) ou, de la même façon, dans le fichier de configuration de votre serveur virtuel (si accessible).