Table des matières

Configuration d'Apache

Apache est un serveur web, que nous utilisons sur certains de nos serveurs. Une autre solution populaire est Nginx. Les deux sont très bien, répondant à des logiques similaires et adapté à de nombreuses situations. Dans le cas des ordinateurs les moins puissants (type Raspberry), on préférera tout de même des logiciels plus léger comme Lighttpd.

Apache est un composant de première importance pour les sites web. Son paramétrage correct et l'attention à certaines options améliorent la sécurité globale du serveur ; à l'inverse, oublier certains détails peut amener des failles exploitables par des attaquants.

Apache a un avantage dans le cas d'une architecture “pare-feu qui protège des serveurs”, il est assez facile d'avoir une communication mixte entre le pare-feu et les serveurs, avec et sans chiffrement. Certains logiciels ont besoin que toutes les communications soient protégés ; par exemple Teampass ne fonctionne pas sans https sur le serveur où il est installé (même si le pare-feu, lui, sert l'accès à l'internaute en https).

Pour l'installation, sur Debian et dérivées :

sudo apt install apache2

Pour connaître sa version d'apache :

apache -v

Tester la configuration et relancer le service

C'est une manipulation à refaire après avoir modifié les fichiers, alors autant donner les commandes dès le début…

Pour vérifier avant tout que la syntaxe est propre :

sudo apachectl -t

Pour relancer le serveur apache :

sudo apachectl graceful

Cette commande redémarre le démon Apache httpd en douceur. Si le démon n'est pas en cours d'exécution, il est démarré. À la différence d'un redémarrage normal, les connexions en cours ne sont pas fermées. Comme effet de bord, les anciens fichiers journaux ne seront pas fermés immédiatement. Cela signifie que si l'on utilise un script de rotation des journaux, un délai suffisant sera nécessaire afin d'être sûr que les fichiers journaux seront bien fermés avant leur traitement par le script de rotation. Cette option vérifie automatiquement les fichiers de configuration (de la même manière que l'option configtest ) avant de lancer le redémarrage, afin d'être sûr que le fonctionnement du démon ne sera pas compromis. Équivalent à apachectl -k graceful.

Renseigner les vhosts de son site

Pour chaque domaine et sous-domaine, on crée un fichier conf dans /etc/apache2/sites-available/. Pour s'y retrouver, mieux vaut donner le nom du sous-domaine au fichier en question… Il y a toujours deux fichiers à faire : celui pour “http” et celui pour “https”, qu'on appelle vhosts. Dans les faits, le http renvoie directement sur https, aussi il va être très sobre.

Cela ressemblera à quelque chose comme ça :

txt /etc/apache2/sites-available/monsite-org.conf
<VirtualHost *:80>
    ServerName monsite.org
    DocumentRoot /var/www/monsite

    RewriteEngine On
    RewriteCond %{REQUEST_URI} !.well-known/acme-challenge
    RewriteRule ^(.*)$ https://%{SERVER_NAME}$1 [R=301,L]

</VirtualHost>

Le vhosts en https a un port différent, et c'est là qu'on configurera toutes les options : alias, etc.

txt /etc/apache2/sites-available/monsite-org-ssl.conf
<VirtualHost *:443>
    ServerName monsite.org
    DocumentRoot /var/www/monsite
 
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/monsite.org/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/monsite.org/privkey.pem

    Alias /dokuwiki /var/www/monsite/undossier/unautredossier/dokuwiki

        <Directory /var/www/monsite/ >
                Options FollowSymLinks MultiViews
                AllowOverride All
                Require all granted
        </Directory>

</VirtualHost>

Après chaque modification de ces fichiers, afin que ce soit pris en compte, vérifiez la configuration et relancez le service apache

sudo apachectl -t && sudo apachectl graceful

Modifier les urls pour aller aux dossiers (Alias)

Avec une configuration basique, Apache indique qu'il faut lire le répertoire renseigné dans DocumentRoot comme répertoire de base du site, chaque dossier se rajoutant à l'adresse. Par exemple si l'option est DocumentRoot /var/www/monsite et que votre dossier a la hiérarchie suivante :

Alors pour accéder via le web à page1 il faudra mettre dans la barre d'adresse du navigateur monsite.org/dossier1/dossier2/index.html

On change ça en faisant des alias dans le fichier /etc/apache2/sites-enable/000-default.conf, de cette façon :

Alias /adresse /var/www/monsite/dossier1/dossier2

Changez /adresse par ce que vous voulez. Ici, dans cet exemple, notre page “index.html” sera à présent accessible à l'adresse monsite.org/adresse/index.html

Vous pouvez aussi pointer vers des adresses hors de /var/www , par exemple pointer vers home/user/monsite, ce qui vous permet de travailler dans un répertoire avec des droits utilisateurs basique.

Droits sur www

Plusieurs possibilités pour permettre, en tant qu'utilisateur Lambda1), de modifier ce qui se trouve dans le dossier /var/www.

Le plus simple et rapide est d'attribuer les droits de ce dossier au groupe www-data, et de mettre lambda dans le groupe www-data.

sudo adduser lambda www-data
chown -R www-data: /var/www

Méthode alternative :

Pour ajouter l'utilisateur lambda à www-data, il y a aussi la commande

usermod -a -G www-data lambda

Les deux sont similaires.

Relancer la session pour que les droits soient pris en compte pour l'utilisateur en cours.

Il vaut mieux laisser le groupe www-data gérer les droits, de base, parce que sinon c'est un beau bazar. Ajouter l'utilisateur “lambda” dans ce groupe permet de modifier tout sans se prendre la tête.

Si certains cms posent problèmes, la suite de commande suivante sur le dossier en question peut réattribuer les droits à www-data et permettre de les résoudre :

sudo chgrp -R www-data Dossier
sudo chown -R www-data Dossier
sudo chmod -R g+w Dossier

Cacher la version d'apache

Ceci est une option améliorant la sécurité.

En principe nos serveurs sont à jours, hein. Mais en cas d'oubli, ne facilitons pas la tâche des observateurs :

nano /etc/apache2/conf-available/security.conf
# Cacher la version d'Apache2
ServerTokens Prod
ServerSignature Off
service apache2 restart

À refaire sur chacun de ses serveurs !

On peut aussi paramétrer (et modifier) ces options dans /etc/apache2/apache2.conf mais c'est moins élégant.

Il faut activer le fichier, non ? Cette partie du tuto demande à être vérifiée.

Activation et paramétrage des modules

Par défaut, Apache est assez “sobre”. Il faut activer divers modules pour bénéficier de certaines fonctionnalités. Certains sont nécessaires pour la sécurité, d'autres sont juste tellement utiles qu'on s'en passe rarement.

Dans les modules à activer quoi qu'il arrive (voir plus bas le détail) :

sudo a2enmod headers ssl

Module SSL

Aujourd'hui, rien ne permet de justifier la navigation non chiffrée. SSL est une mesure de sécurité, qui ne vous coûte rien en tant que sysadmin (grâce à Let's Encrypt) et qui peut éviter un certain nombre de soucis. Alors, par défaut, vos sites doivent être en https. C'est tout.

Pour connaître sa version d'apache et d'openssl :

apache -v
openssl version

À utiliser sur Mozilla SSL Configuration Generator pour générer les options de base à mettre dans sa configuration, ce sera probablement plus à jour que ce tutoriel au fil du temps.

Activer le module ssl dans Apache si ce n'est pas déjà fait :

a2enmod ssl

Puis modifiez le fichier /etc/apache2/mods-available/ssl.conf suivant ces informations :

SSLProtocol +TLSv1.2
SSLCompression off
SSLCipherSuite HIGH:!aNULL:!eNULL:!LOW:!MEDIUM:!EXP:!RC4:!3DES:!MD5:!PSK:!kRSA:!SRP:-DH:+ECDH
SSLHonorCipherOrder On

# OCSP Stapling, only in httpd 2.3.3 and later
SSLUseStapling          on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache        shmcb:/var/run/ocsp(128000)

Pour la liste SSLCipherSuite, consulter les préconisations de Mozilla SSL Configuration Generator et lire tranquillement l'explication si dessous avant de modifier la proposition mise à jour le 29 novembre 2017.

À partir de la version 2.4.11 d'apache, vous pouvez ajouter dans le fichier /etc/apache2/mods-available/ssl.conf :

SSLSessionTickets Off

Explications

Ce qui suit est extrait d'une conversation avec TychoBrahe ; j'ai conservé son style fleuri si savoureux.

zatalyz 2016/12/30 13:27

Une ciphersuite est un ensemble de 4 algorithmes différents, chacun servant à un rôle distinct :

Un exemple : DHE-RSA-AES256-SHA256

On pourrait croire qu'il y a 5 algorithmes, par exemple avec ECDHE-RSA-AES128-GCM-SHA256. En fait, GCM est un des modes de fonctionnement d'AES, donc AES128-GCM désigne de l'AES en mode GCM avec une clé de 128 bits. Pour info, les EC devant ECDHE et parfois ECDSA c'est pour elliptic curve, donc l'utilisation de courbes elliptiques au lieu de nombres premiers.

SSL et TLS permettent d'utiliser non pas une seule combinaison, mais plusieurs, ce qui fait que ces protocoles intègrent une phase de négociation de la cipher suite. Chaque version de SSL ou TLS autorise ou non certaines cipher suites etc, bref c'est le bordel, sachant qu'il faut, avant ça, négocier la version de SSL ou TLS utilisée. Soit dit en passant, il existe une cipher suite NULL qui dit qu'il n'y a aucun chiffrement, du coup cette phase de négociation a été attaquée, un MITM2) permettant de forcer une cipher suite (genre NULL ou une faible).

Afin d'éviter les ennuis, on va dire au serveur de n'utiliser que certaines cipher suites et pas d'autres : c'est l'option SSLCipherSuite. Chaque cipher suite est séparée par : et s'il y a un ! devant son nom, c'est pour explicitement l'interdire.

Le site de Mozilla cite toutes les ciphersuites, c'est sans doute bien, mais ils ont juste oublié un truc : à tout citer explicitement, il faut faire évoluer la liste avec les avancées en matière de recherche. Personnellement j'utilise et recommande d'utiliser des familles. Ces familles sont définies par la librairie SSL/TLS utilisée :

Du coup on fait confiance dans les familles définies dans les lib crypto, mais en imposant des restrictions sur certains trucs trop limite pour y être inclus mais qui ont des chances de tout de même s'y retrouver.

Les librairies ont un outil pour lister les familles, qui liste soit toutes les cipher suites supportées, soit, si on précise, la liste de ce qui est autorisé :

openssl ciphers
openssl ciphers HIGH
openssl ciphers 'HIGH:!AES'

Voir aussi

man 1 ciphers
L'échange de clefs

C'est un mécanisme permettant l'échange de clefs en toute confidentialité, sans qu'un tiers puisse avoir connaissance de celles-ci.

Le chiffrement a/symétrique

La différence entre le chiffrement symétrique et le chiffrement asymétrique est que dans le premier cas, il n'y a besoin que d'une seule clef, qui permet aussi bien de chiffrer un message que de le déchiffrer. Pour le chiffrement asymétrique, on utilise une clef pour le chiffrement, et une autre clef différente de la première pour le déchiffrement. C'est pour cela qu'on parle de clef dite publique (celle que tout le monde peut voir et avec laquelle on va chiffrer les messages qui nous sont destinés) et de clef dite privée (celle avec laquelle on va déchiffrer notre message ; si on n'a pas accès à cette clef privée, on ne peut pas déchiffrer le message).

Le contrôle

Afin de vérifier l'intégrité des messages que l'on transmet, on calcule une somme de contrôle que l'on envoie avec le message. Une fois le message et sa somme de contrôle réceptionnés, on peut recalculer la somme de contrôle du message et vérifier qu'elle correspond bien à celle qui a été transmise. Si elles diffèrent, c'est que le message a été altéré (ou qu'il y a une collision, c'est à dire que pour deux messages différents on obtient la même somme de contrôle, mais ce cas ne devrait quasiment presque jamais arriver).

Module header

Activer les headers dans Apache si ce n'est pas déjà fait :

sudo a2enmod headers

Puis modifiez le fichier /etc/apache2/mods-available/headers.conf :

# Ce qui suit vient de
# https://blog.adminrezo.fr/2016/12/securiser-serveur-apache-https-headers/
# Contrôler l’accès des bots de facon plus fine qu'avec robots.txt :
Header set X-Robots-Tag "index,follow,noarchive"
# Évite que le contenu soit interprété différemment que définit dans le mime Type
Header set X-Content-Type-Options nosniff
# Protection contre le clickjacking
Header set X-Frame-Options "SAMEORIGIN"
# Protection contre les failles X-XSS
Header set X-XSS-Protection "1; mode=block"
# Faille spécifique IE8, on espère que plus personne ne l'utilise, mais...
Header set X-Download-Options noopen;
# Interdire l'embarquement de tout ou partie de votre site dans un site ou logiciel tiers 
Header set X-Permitted-Cross-Domain-Policies none
# X-Clacks, ça sert à rien, c'est donc vital.
header set X-Clacks-Overhead "GNU Terry Pratchett"
# Enfin, les CSP permettent de vérifier l'origine des éléments du site
# CSP, pour éviter de charger des scripts d'ailleurs. /!\ partie complexe à gérer suivant vos CMS
Header set Content-Security-Policy "default-src 'self' *.monsite.org 'unsafe-eval' 'unsafe-inline' "

Les explications :

Content Security Policy (CSP)

Les CSP améliorent grandement la sécurité d'une installation, en interdisant à certaines ressources de s'exécuter, par exemple des scripts malicieux injectés dans vos sites webs.

Mais il est difficile de faire marcher les CMS tout en ayant une politique sécurisée sur les CSP.

Le site de référence est https://content-security-policy.com/. En anglais, mais il contient toute la documentation officielle sur le sujet.

Quelques exemples

L'option suivante permet à Dokuwiki et Simple Machine Forum de marcher, mais pas à Etherpad, et ne vaut rien aux yeux de l'Observatoire Mozilla. Cependant, même l'etherpad de Mozilla ne fait pas mieux.

Header set Content-Security-Policy "default-src 'self' *khaganat.net; script-src 'self' 'unsafe-inline' *khaganat.net; style-src 'self' 'unsafe-inline'; img-src * "

img-src * ici accepte tout, mais sans ça, on n'affiche plus les images en lien, par exemple dans le forum, ce qui demande une solution interne pour les héberger.

Pour onlyoffice, après de nombreuses galères : la solution a été la CSP frame-ancestors pour permettre l'accès à une autre instance Onlyoffice par plusieurs instances nextcloud. Dans ce cas sur nginx avec le module more_headers, ça a donné ça :

more_set_headers "Content-Security-Policy : frame-ancestors https://site1.example.com/nextcloud https://site2.example.com/ https://site3.example.com/nextcloud ";

La règle suivante, assez générique, va “fonctionner” pour la plupart des CMS. La mettre dans une règle sur le proxy, appelée par les diverses configurations :

add_header Content-Security-Policy "default-src 'self' *.monsite.org 'unsafe-eval' 'unsafe-inline'; ";

Activer la réécriture des URLs

Pour la ferme de wiki ou le pastebin (entre autre), il faut activer la réécriture des URLs.

Lancez la commande :

sudo a2enmod rewrite

Dans les vhosts (/etc/apache2/sites-available/monsite-ssl.conf), mettez l'option AllowOverride sur All là où il y a besoin de réécriture d'url. Généralement, tout le dossier /var/www pour pas se compliquer la tâche.

txt /etc/apache2/sites-available/monsite-org-ssl.conf
<VirtualHost *:443>
    ServerName monsite.org
    DocumentRoot /var/www/monsite

        <Directory /var/www/monsite/ >
                Options Indexes FollowSymLinks MultiViews
                AllowOverride All
                Order allow,deny
                allow from all
        </Directory>
    [...]
</VirtualHost>

Options lorsqu'un proxy est actif

Le proxy permet d'avoir un intermédiaire qui relaie les requêtes aux serveurs cibles. Typiquement quand on a une seule ipv4 et des VM sur le réseau interne, c'est un peu obligé ; mais cela peut aussi s'appliquer dans d'autres cas, par exemple pour faire du load balancing, de la mise en cache, pour des aspects de sécurité, etc.

Il faut bien activer les modules apache correspondants :

a2enmod proxy
a2enmod proxy_http

Les arguments proxy

Les options concernant le cache et les buffers (absolument dispensable) :

Load Balancing (voir plus bas pour un exemple plus concret) :

Sur le serveur même : servir un port particulier

Certains services sont accessibles via des ports particuliers. C'est ce que fait Etherpad par exemple : lors de son installation, il est accessible à l'adresse https://monserveur.org:9001.

Pour qu'on puisse y accéder via l'adresse web https://monserveur.org/pad, il faut mettre un proxy en place dans Apache.

Commencer par activer les modules de proxy :

sudo a2enmod proxy proxy_http

Puis ajouter ce genre d'information dans /etc/apache2/sites-availables/monsite.conf :

<VirtualHost *:443>
[...]

  ProxyVia On
  ProxyRequests Off
  ProxyPass /pad/ http://localhost:9001/
  ProxyPassReverse /pad/ http://localhost:9001/
  ProxyPreserveHost on
  <Proxy *>
    Options FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    allow from all
  </Proxy>
  
[...]
</VirtualHost>

Relancez le service apache

sudo apachectl -t && sudo apachectl graceful

Votre etherpad devrait être accessible à la bonne adresse !

Un serveur pare-feu et d'autres derrière

Dans certaines architectures (et entre autre chez Khaganat), nous fonctionnons avec un pare-feu. Toute communication entrante arrive au même endroit, est filtrée, puis redistribuée à diverses VM/containers afin d'isoler les services suivant leurs contraintes.

Dans ce cas, chaque vhost sur le serveur du pare-feu doit contenir ceci :

ServerName sousdomaine.monserveur.net

# Proxy : permet de renvoyer vers l'adresse ip du serveur. 
# Ici l'exemple est dans le cas de VM Xen, c'est donc une adresse locale.
ProxyPass / http://192.168.20.43/
ProxyPassReverse / http://192.168.20.43/

ProxyRequests off
ProxyPreserveHost on
                <Proxy *>
                Options FollowSymLinks MultiViews
                AllowOverride All
                Order allow,deny
                allow from all
                </Proxy>

# SSL
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/monsite.org/certificate.pem
    SSLCertificateFile /etc/letsencrypt/live/monsite.org/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/monsite.org/privkey.pem

# HSTS (mod_headers requis) (15768000 seconds = 6 months)(63072000 = 24 mois)
Header set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"

HSTS (module Header) permet de déclarer au client directement dans la réponse HTTP qu'il faut communiquer en HTTPS. Cet en-tête permet d'éviter le vol de cookies et le downgrade SSL.

# Le paramètre suivant est valide si vous avez amélioré la clé Diffie Hellman
SSLDHParametersFile /etc/letsencrypt/live/MONSITE.COM/dhparams.pem

Je n'ai sans doute pas tout compris, ou alors ce n'est pas compatible avec ma version d'apache, mais si je l'ajoute ça me fait une erreur.

zatalyz 2017/01/01 18:33

Faire suivre les IP derrière les reverse proxy

Si vous avez une VM (A) qui sert de pare-feu avant de redistribuer le trafic aux autres VM (B) de votre serveur, il y a un petit souci : les VM B croient que tout le trafic vient de l'ip de la VM A. Ce qui pose un gros souci dans le cas où vous avez du spam et que votre CMS favori permet de bannir par IP… si vous bannissez la VM A, plus rien ne passera, même les utilisateurs légitimes.

Il faut donc activer le transfert des IP sur les VMs destinataires (pas toucher au pare-feu, ce n'est pas là que ça se joue).

Créer /etc/apache2/conf-available/remoteip.conf et lui donner ceci :

RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 192.168.20.35

Remplacer 192.168.20.35 par l'IP interne de la VM pare-feu.

Activer le module remoteip qui fait ça :

a2enmod remoteip
a2enconf remoteip
apache2ctl configtest && service apache2 restart

Cela devrait marcher. À répeter sur chaque VM du réseau.

Load balancing

C'est utile pour les services critiques ou fortement sollicités. Je met la doc ici mais nous n'avons pas (encore) eu l'occasion de vraiment essayer ça.

Un fichier de conf sur le proxy ressemblera à ceci :

<VirtualHost *:80>
    ServerName example.org

    # Proxy vers un backend principal avec timeout
    ProxyPass /app http://backend_server/app retry=5 timeout=60
    ProxyPassReverse /app http://backend_server/app

    # Configuration d'un cluster de load balancing
    <Proxy balancer://mycluster>
        BalancerMember http://backend1.example.org
        BalancerMember http://backend2.example.org status=+H
        ProxySet lbmethod=byrequests
    </Proxy>

    ProxyPass /cluster balancer://mycluster/
    ProxyPassReverse /cluster balancer://mycluster/
    
    # Ajustement des en-têtes
    ProxyPreserveHost On
    ProxyErrorOverride On
</VirtualHost>

Lorsqu'une visiteuse arrive sur example.org, elle est renvoyée aléatoirement vers le serveur backend1 ou backend2, afin d'éviter de surcharger. retry=5 pour la directive ProxyPass indique qu'Apache essaiera jusqu'à cinq fois de se reconnecter au serveur backend, et s'arrêtera après 60 secondes à chercher (ce qui est long !).

Configuration personnalisées

On peut se faire un fichier de configuration appelant diverses modifs sur tous les sites, par exemple dans /etc/apache2/conf-available/bidouilles.conf.

Ensuite on peut l'appeler dans chaque config de site en ajoutant la ligne suivante (dans /etc/apache2/sites-enabled/monsite-ssl.conf, entre les balises VirtualHost) :

Include /etc/apache2/conf-available/bidouilles.conf

Cela évite de réécrire les mêmes règles partout.

Virer le tracker de Facebook

Facebook changeant régulièrement ses règles, vérifiez que cette bidouille est toujours pertinente.

Quand on partage un lien sur Facebook, et qu'on arrive sur le site, Facebook fait de l'injection pour suivre ses internautes. Vos visiteurs vont visiter vos pages avec un tracker collé à l'url, du type https://monsite.org/?fbclid=IwAR1RNFCx5Gu9SHRAbuj67ebqbu3Hc7YGgkOKh. C'est pas propre, et puis ça peut mettre le bazar dans certains sites.

On peut régler ça au niveau d'Apache et mettre Facebook dehors, en ajoutant cela dans un fichier de conf (par exemple dans /etc/apache2/conf-available/bidouilles.conf comme expliqué juste avant) :

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{QUERY_STRING} ^(.*)(?:^|&)fbclid=(?:[^&]*)((?:&|$).*)$ [NC]
  RewriteCond %1%2 (^|&)([^&].*|$)
  RewriteRule ^(.*) $1?%2 [R=301,L]
</IfModule>

Il faut bien sûr avoir le module rewrite activé.

Relancez apache ;)

Astuce tirée de ce site avec quelques aménagements.

Could not reliably determine the server's fully qualified domain name

À chaque modif du serveur, vous avez sans doute droit à ce message d'erreur :

apache2: Could not reliably determine the server's fully qualified domain name, using [IP]. Set the 'ServerName' directive globally to suppress this message

On va donc configurer ça… juste pour ne pas avoir ce message. Nos sites sont configurés par ailleurs, donc cette demande a peu de sens ; on peut l'ignorer, on peut aussi la supprimer. On va créer un fichier de conf globale pour ça !

sudo nano /etc/apache2/conf-available/full-qualified-domain-name.conf

Ajoutez uniquement la ligne suivante (sans rien changer) :

ServerName localhost

Puis activez tout cela :

sudo a2enconf full-qualified-domain-name
sudo apachectl graceful

Et voilà.

Liens utiles

1)
oui, notre utilisateur test s'appelle “Lambda”.