Service présent sur bulbe.
Procédures
- Installation d'Nginx
- Installation d'AWStats
- Remplacement de Awstats par Goaccess
- Deinstallation finale d'Awstats
Bases d'authentification
Les fichiers servant à identifier les users pour l'authentification
HTTP sont regroupés dans /etc/nginx/passwd
. Ces fichiers sont au même
format que ceux d'Apache et sont manipulables avec la commande htpasswd
du paquet apache2-utils.
Certificat X.509
Le certificat X.509 utilisé est signé par Let's Encrypt, et maintenu par acmetool.
En-têtes relatifs à la sécurité
HTTP Strict Transport Security
Afin que les navigateurs se souviennent que le site de Nos oignons doit être
consulté en HTTPS,
on indique dans le VirtualHost
HTTPS :
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload
- La valeur de
max-age
vaut pour 12 mois. includeSubDomains
etpreload
sont requis pour HSTS Preload Le pré-chargement denos-oignons.net
dans les listes HSTS des navigateurs force l'utilisation de HTTPS (y compris lors de la première visite), qu'ils aient HTTPS Everywhere ou non.
Content Security Policy
Une CSP définit une politique décrivant quelles ressources la page peut charger, quelles requêtes peuvent être émises, et que faire vis-à-vis du referrer.
Ça vise à rendre difficile, voir impossible, une large famille d'attaques, en particulier les attaques XSS (Cross-Site Scripting, où un attaquant injecte du contenu dans une page, qui est typiquement interprété comme du HTML).
Malheureusement, certains applications (AWStats, Gitweb, Mailman, Request Tracker) utilisent des scripts ou des styles « en ligne », embarqués dans le corps du document, ce qui est mauvais d'un point de vue sécurité. De façon ironique, ce sont aussi les applications les plus à risque qui ont les plus mauvaises pratiques ...
Du coup, on définit deux politiques différentes :
- une politique par défaut, stricte ;
- une politique plus « coulante », qu'on applique au cas par cas.
Paramètres communs
La majeure partie de la politique est la même dans les deux cas :
default-src 'none'
: par défaut, aucun contenu ne peut être chargé ; on travaille en mode « liste blanche » ;img-src 'self'; font-src 'self'
: les images et fontes peuvent être chargées depuis la même origine (https://nos-oignons.net) ;form-action 'self'
: les formulaires ne peuvent pas déclancher de requête vers un domaine tiers ;frame-ancestors 'none'
: notre site ne peut pas être embarqué dans une « iframe » ;upgrade-insecure-requests; block-all-mixed-content
: les requêtes HTTP sans TLS sont interdites, et remplacées par HTTPS automatiquement ;sandbox allow-forms allow-same-origin allow-scripts
: le bac à sable est configuré pour interdire les popups, les greffons du navigateur, l'API Javascript de navigation, et cette permettant de manipuler la souris.reflected-xss block
: on demande au navigateur d'utiliser des heuristiques qui détectent les tentatives de reflected XSS, cfX-Xss-Protection
;referrer origin-when-cross-origin
: lorsque le domaine change, le navigateur ne doit pas fournir plus d'informations que « le site dont on vient est nos-oignons.net. »
Politique par défaut
On définit les paramètres suivants :
script-src 'self'; style-src 'self'
: on peut charger des scripts et des feuilles de styles depuis le domaine courant ;connect-src https://onionoo.torproject.org/
: les scripts peuvent se connecter à Onionoo (requis par Graphnion).
Politique « inline »
On définit, à la place, ces paramêtres :
script-src 'self' 'unsafe-inline' 'unsafe-eval'
: on autorise le Javascript inline et l'utilisation deeval()
(requise par RT);style-src 'self' 'unsafe-inline'
: on autorise le CSS inline.connect-src 'self'
: requis par Request Tracker.
Implémentation dans Nginx
La politique est implémentée dans Nginx de cette façon :
le fichier
snippets/csp-header.conf
est inclus dans le blocserver
, et définit la politique par défaut :# En-tête Content-Security-Policy pour la majeure partie du site. add_header "Content-Security-Policy" "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self'; connect-src https://onionoo.torproject.org/; frame-ancestors 'none'; form-action 'self'; upgrade-insecure-requests; block-all-mixed-content; sandbox allow-forms allow-same-origin allow-scripts; reflected-xss block; referrer origin-when-cross-origin;";
le fichier
snippets/csp-inline.conf
est inclus dans chaque bloclocation
qui doit utiliser la politique plus laxe :# En-tête Content-Security-Policy plus laxe pour AWStats, Request Tracker et gitweb add_header "Content-Security-Policy" "default-src 'none'; connect-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' ; img-src 'self'; font-src 'self'; frame-ancestors 'none'; form-action 'self'; upgrade-insecure-requests; block-all-mixed-content; sandbox allow-forms allow-sa me-origin allow-scripts; reflected-xss block; referrer origin-when-cross-origin;"; # On (ré-)inclus les en-têtes définis au par avant, # parce que utiliser add_header invalide tous les en-têtes définis dans un contexte moins spécifique include snippets/headers.conf;
En-têtes complémentaires
Quelques en-têtes complémentaires sont définis dans snippets/headers.conf
,
qui est inclus au début du bloc server
:
# Ne laisse pas charger notre site dans une <frame>.
# Ça empêche les attaques par « clickjacking »
add_header "X-Frame-Options" "deny";
# Active une protection contre le XSS réflectif dans IE, Chrome & Safari
# Il faudra qu'on vérifie que ça ne casse pas de scripts chez nous.
add_header "X-Xss-Protection" "1; mode=block";
# Force le navigateur à honorer le type MIME transmi par le serveur.
# Ça peut éviter qu'une page HTML ou une image soit subitement
# interpretée comme un JavaScript ou comme un .exe
add_header "X-Content-Type-Options" "nosniff";
Statistiques
Les statistiques sont accessibles sur https://nos-oignons.net/goaccess/. Les pages web (statiques) sont régénérées chaque semaine. L'accès est protégé avec la même base d'authentification que celle du wiki du conseil d'administration.
Gitweb
Afin d'avoir une interface web pour naviguer dans les dépôts
Git, gitweb
est installé et accessible à l'adresse :
https://nos-oignons.net/gitweb/
Sa configuration se trouve dans /etc/gitweb.conf
et dans
/etc/nginx/sites-available/https
. Les dépôts listés sont ceux présents dans
le répertoire /var/cache/git
.
Interaction avec les scripts CGI
Nginx ne sachant pas interagir avec les scripts CGI (et leur préfère FastCGI),
on utilise fcgiwrap
.
ATTENTION : fcgiwrap
permet (à quiconque peut écrire sur le socket FastCGI)
de lancer des commandes arbitraires. Pour atténuer le problème, on a des instances
de fcgiwrap
séparées pour un nombre restreint d'utilisateurs (list
, git
,
wiki-admin
, wiki-ca
, website
), et confinées à l'aide des fonctionnalités de
sécurité de systemd
.
Pour un utilisateur donné, l'instance de fcgiwrap
écoute sur le socket
/run/fcgiwrap-${USERNAME}.sock
(en fait, systemd
écoute là, puisqu'on
utilise la socket activation). On peut obtenir les logs associés à une
instance de fcgiwrap
donnée en invoquant sudo journalctl -u fcgiwrap@${USERNAME}
.
Modèle de service
Pour nous éviter de longs copier-coller, on utilise un modèle d'unit file systemd :
# /etc/systemd/system/fcgiwrap@.service
[Unit]
Description=Simple CGI Server as user %i
After=nss-user-lookup.target
[Service]
ExecStart=/usr/sbin/fcgiwrap
User=%i
Group=%i
PrivateTmp=true
PrivateDevices=true
PrivateNetwork=true
ProtectSystem=full
ProtectHome=true
NoNewPrivileges=true
CapabilityBoundingSet=
InaccessibleDirectories=/srv/association /srv/awstats /srv/postgresql
InaccessibleDirectories=/srv/request-tracker4 /srv/schleuder
[Install]
Also=fcgiwrap@%i.socket
# /etc/systemd/system/fcgiwrap@.socket
[Unit]
Description=fcgiwrap socket for user %i
[Socket]
ListenStream=/run/fcgiwrap-%i.sock
SocketUser=www-data
SocketGroup=www-data
SocketMode=0600
[Install]
WantedBy=sockets.target
On peut dès lors ajouter une instance de fcgiwrap
très simplement :
systemctl enable fcgiwrap@user2
systemctl start fcgiwrap@user2
Confinement spécifique
Les unit files pour fcgiwrap
contiennent déjà des mesures de sécurité génériques.
Cependant, on peut vouloir appliquer des restrictions supplémentaires à une instance donnée.
Ça se fait très simplement en utilisant un drop in : un fichier qui s'ajoute à la configuration d'un service.
# /etc/systemd/system/fcgiwrap@git.service.d/sandbox.conf
[Service]
InaccessibleDirectories=/var/log
InaccessibleDirectories=/srv/git /srv/mailman /srv/ikiwiki
InaccessibleDirectories=/srv/http/awstats /srv/http/campagne2015
InaccessibleDirectories=/srv/http/website /srv/http/website-ecrire
InaccessibleDirectories=/srv/http/wiki-admin /srv/http/wiki-admin-ecrire
InaccessibleDirectories=/srv/http/wiki-ca