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 *:80'' : indique le port concerné, 80 c'est http (et ça ne se bidouille pas !). Toutes les informations concernant le site sont entre ces deux balises "VirtualHost".
* ''ServerName'' : à renseigner obligatoirement. C'est le nom de domaine qui permet d'accéder au site.
* ''DocumentRoot'' : nécessaire aussi ! Indique où sont les fichiers du site web sur le serveur. Astuce "bonne pratique", créez un dossier dans /var/www au nom de votre domaine/sous-domaines.
* ''RewriteEngine On'' : indique d'utiliser la réécriture des URL (voir plus bas)
* Les deux lignes suivantes sont là pour rediriger en https ; la première est lié à l'usage de [[fr:https_ssl#let_s_encryptcertbot]] et s'adapte suivant quel sorte de certificat SSL vous utilisez.
Le vhosts en https a un port différent, et c'est là qu'on configurera toutes les options : alias, etc.
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
Options FollowSymLinks MultiViews
AllowOverride All
Require all granted
* Le port, cette fois, est 443.
* Il faut renseigner à nouveau ''ServerName'' et ''DocumentRoot'', comme pour le 80.
* ''SSLEngine on'' : active la prise en charge du certificat SSL, ce qui est un peu obligatoire (ceci dit, quand le module est actif, oublier cette option dans le vhost ne semble pas gêner la prise en charge du certificat...).
* ''SSLCertificateFile'' et ''SSLCertificateKeyFile'' : indique le chemin des deux fichiers du certificat. Il faut évidement adapter le chemin au nom de domaine, et avoir généré le certificat (on voit ça plus bas).
* ''Alias'' : permet de faire des URL plus élégantes. Une option parmi d'autres... Ici, sans alias, le dokuwiki serait accessible avec le lien "monsite.org/undossier/unautredossier/dokuwiki" ce qui est longuet ; l'alias permet que le lien "monsite.org/dokuwiki" serve le dokuwiki. On peut même pointer un dossier hors de ''/var/www'' (par exemple ''/home/moi/unboutdesite''. Il y a parfois des bonnes raisons de le faire ;). Voir plus bas le détail !
* ''Directory'' : va permettre de déclarer diverses options, rendant le dossier (et donc le site web associé) utilisable pour la navigation web, en tirant partie par exemple des possibilités de php, mais aussi en indiquant ce qui est permis et interdit et contribue donc un peu à la sécurité. Ici, ce sont des options classiques qui fonctionnent dans 90% des cas. Mais il faut adapter parfois suivant les dossiers :
* ''Options'' : attention à déclarer uniquement ce qui est utile.
* ''Indexes'' permet de lister les fichiers dans un répertoire si aucun fichier index (comme index.html ou index.php) n'est présent, ce qui peut poser des problèmes de sécurité. Donc on peut éviter ?
* ''FollowSymLinks'' : Autorise Apache à suivre les liens symboliques (symlinks) dans le répertoire. Voir aussi la doc sur ''SymLinksIfOwnerMatch'' (usage plus spécifique).
* ''MultiViews'' : Permet à Apache de servir différentes versions d'un même fichier selon la requête du client (langue, type de contenu, etc.)
* ''ExecCGI'', ''Includes'', ''IncludesNOEXEC'' sont intéressants mais allez voir la doc officielle, parce que c'est assez pointu comme usage.
* ''None'' : pour interdire toutes les options dans un répertoire.
* ''AllowOverride All'' permet l'utilisation de fichiers .htaccess ; cela peut avoir un impact sur les performances. Mais pas mal de CMS utilisent les htaccess.
* ''Require all granted'' : Remplace les anciennes directives ''Order allow,deny'' et ''allow from all''. Cela autorise toutes les requêtes à accéder à ce répertoire.
* ''Require all denied'' pour interdire l'accès (utile pour s'assurer que certains dossiers ne seront pas du tout accessibles)
* ''Require ip'' : Permet de restreindre l'accès à des adresses IP spécifiques ou à des plages d'adresses IP.
* ''Require host'' : Permet d'autoriser l'accès basé sur le nom d'hôte de la requête.
* ''Require user'' et ''Require valid-user'' : Permet d'accorder l'accès à des utilisateurs spécifiques ce qui demande d'utiliser des mécanismes d'authentification
* ''Require env'' : Permet d'accorder l'accès en fonction d'une variable d'environnement, ça commence à être assez pointu comme usage.
* ''Require expr'' : Permet d'utiliser une expression conditionnelle pour contrôler l'accès. Par exemple toutes les ip du réseau interne.
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 :
* var
* www
* monsite
* dossier1
* dossier2
* index.html
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 Lambda((oui, notre utilisateur test s'appelle "Lambda".)), 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
# Cacher la version d'Apache2
ServerTokens Prod
# Cache la signature de "Apache" dans les pages d'erreurs et répertoires
ServerSignature Off
# Désactive la méthode HTTP TRACE utilisée dans des attaques XST
TraceEnable Off
sudo apachectl a2enconf security
==== Vhost avec variables ====
On peut utiliser des macros, ce qui va permettre d'utiliser des variables pour générer nos fichiers.
sudo a2enmod macro
On crée ensuite les fichiers de "macros" :
# Les parties "tout le monde pareil" dans les configs apache.
# Pour vhost 80
ServerName $domain
# Redirection tout le trafic HTTP vers HTTPS
RewriteEngine On
RewriteCond %{REQUEST_URI} !.well-known/acme-challenge
RewriteRule ^(.*)$ https://%{SERVER_NAME}$1 [R=301,L]
# Les parties "tout le monde pareil" dans les configs apache. Pour vhost 443
ServerName $domain
# Logs
ErrorLog ${APACHE_LOG_DIR}/$domain_error.log
CustomLog ${APACHE_LOG_DIR}/$domain_access.log combined
# Configuration SSL avec Let’s Encrypt
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/$domain/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/$domain/privkey.pem
# Redirection pour les sous-domaines non déclarés (à condition d'avoir son DNS bien configuré aussi)
RewriteEngine On
RewriteCond %{HTTP_HOST} !^%{SERVER_NAME}$ [NC]
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301]
Un vhost d'un site précis va ensuite ressembler à ceci (remplacez ''exemple.org''...) :
# Déclare la macro, son appel et la variable pour le nom de domaine
Use common_config_80 exemple.org
# Déclare les sous-domaines qui sont en réalité le même site
ServerAlias www.exemple.org
Use common_config_443 exemple.org
ServerAlias www.exemple.org
# Si besoin d'alias
#Alias /machin /var/www/html
DocumentRoot /var/www/exemple.org
Options FollowSymLinks MultiViews
AllowOverride All
Require all granted
On active ensuite :
sudo a2enconf macro_common_config_443
sudo a2enconf macro_common_config_80
sudo a2ensite exemple.org.conf
sudo apachectl -t
sudo apachectl graceful
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)
#À partir de la version 2.4.11 d'apache
SSLSessionTickets Off
Pour la liste ''SSLCipherSuite'', consulter les préconisations de [[https://mozilla.github.io/server-side-tls/ssl-config-generator/|Mozilla SSL Configuration Generator]] et lire tranquillement l'explication si dessous avant de modifier la proposition
# 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,notranslate"
# É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 du site dans un site ou logiciel tiers
Header set X-Permitted-Cross-Domain-Policies none
# Protège la vie privée en évitant de transmettre trop d'infos lorsqu'on naviguer vers une autre page.
Header set Referrer-Policy "strict-origin-when-cross-origin"
# X-Clacks, ça sert à rien, c'est donc vital.
header set X-Clacks-Overhead "GNU Terry Pratchett"
Les explications :
* Header set X-Robots-Tag : http://robots-txt.com/x-robots-tag/
* CSP : https://ole.michelsen.dk/blog/secure-your-website-with-content-security-policy.html
=== 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.
Je conseille de faire des règles CSP différentes suivant les CMS...
Le site de référence est [[https://content-security-policy.com/]]. En anglais, mais il contient toute la documentation officielle sur le sujet.
* Premier cas : pas de politique CSP. Certains CMS permettent aux utilisateurs d'appeler "des bouts de web" venant d'ailleurs, généralement les images, mais dans certains cas aussi du code... Un attaquant peut se servir de ça pour appeler sur le serveur un code malicieux. Un CMS sécurisé réduit beaucoup les possibilités, mais le risque zéro n'existe pas, et la plupart des CMS ont des failles, c'est un fait.
* Second cas : une politique CSP stricte (paramétrée uniquement sur ''self''). Ici, plus moyen d'appeler un truc d'ailleurs. Par contre cela va bloquer le fonctionnement légitime de certains CMS, entre autre ce qui concerne les scripts (pourquoi, je n'ai pas pas encore bien compris, mais c'est un fait).
* Troisième cas : ajouter des règles comme ''unsafe-eval'' et ''unsafe-inline''. Cela va permettre aux scripts en question de fonctionner MAIS cela permet aussi à certains attaquant d'utiliser des failles : comme leur nom l'indique, cela est considéré comme "non sécurisé". Ils autorisent explicitement certains trucs à marcher, sans plus de vérification. Cela ouvre la porte à des injections. Cependant, d'après mes tests, les scripts ayant une adresse externe ne sont PAS exécutés sur le domaine. Ne vous sentez pas en confiance pour autant.
* Quatrième cas : exécuter localement uniquement les scripts validés explicitement. Cela demande de rajouter la variable ''nonce'' ou ''hash'', puis d'ajouter dans chacun des scripts de notre serveur la clé associée (un hash sur les scripts, ou bien une clé dans ces derniers). Cela veut donc dire : avoir la main sur tout... c'est assez irréaliste dans la majorité des cas, et entre autre pour les CMS qui embarquent trop de scripts et qui écraseront nos modifications à chaque mise à jour. Cela demande aussi un certain niveau de développement, or la plupart des sysadmin/webmestres sont surtout des bidouilleuses, pas des développeuses.
== Quelques exemples ==
L'option suivante permet à Dokuwiki et Simple Machine Forum de marcher, mais pas à Etherpad, et ne vaut rien aux yeux de [[https://observatory.mozilla.org/|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'; ";
Et voici une autre façon d'écrire les Content-Security-Policy, un peu plus "lisible". Cela couvre des besoins normaux de façon relativement sécurisée, mais comme on l'a vu, il faudra adapter aux pads, à OnlyOffice...
Header set Content-Security-Policy "
default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' https: ;
font-src 'self';
connect-src 'self' https://bosh.jabberfr.org/ *.numenaute.org;
frame-src https://chat.jabberfr.org/ *.numenaute.org/;
object-src 'self';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
"
Ces règles sont un compromis entre "fonctionnel" et "sécurisé" (avec quelques suggestions de "quoi mettre d'autre") :
* ''default-src 'self';''Tout provient du même domaine sauf mention contraire.
* Les scripts, au choix...
* ''script-src 'self' 'unsafe-inline' 'unsafe-eval';'' Permet les scripts inline et eval(), nécessaires pour certaines applications.
* ''script-src 'self';'' Cette version est sécurisée mais... ben potentiellement certaines applis ne fonctionneront pas. Celles avec des potentielles failles :P
* L'usage de Hashes et Nonces serait idéale mais avec les cms, c'est compliqué.
* ''style-src 'self';'' Permet les styles inline.
* ''style-src 'self' 'unsafe-inline';'' Pour faire marcher les sites mal branlés (style dans le html)
* ''img-src 'self' https: ;'' Autorise les images venant du même domaine et de certaines sources externes via https.
* ''font-src 'self';'' Autorise les polices venant du même domaine.
* ''connect-src 'self' https://bosh.jabberfr.org/ *.numenaute.org;'' Permet les connexions vers des ressources externes indiquées
* ''frame-src https://chat.jabberfr.org/ *.numenaute.org/;'' Autorise l'encadrement (frames) par certains domaines
* ''object-src 'self';'' Limite l'utilisation des éléments