Aller au contenu

Nginx : sécurité

Des réglages simples réduisent fortement la surface d’attaque d’un serveur Nginx. Les exemples utilisent des noms génériques.

Dans /etc/nginx/nginx.conf, contexte http, modifier la ligne existante :

server_tokens off;
Ubuntu Ligne d’origine
24.04 # server_tokens off; (en commentaire : retirer le #)
26.04 server_tokens build; (remplacer build par off)

Les en-têtes de réponse et les pages d’erreur n’indiquent plus la version de Nginx. Vérifier : curl -sI http://localhost | grep -i server doit afficher server: nginx seulement.

Fenêtre de terminal
sudo tee /etc/nginx/snippets/securite.conf <<'CONF'
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
CONF
server {
# …
include snippets/securite.conf;
add_header Strict-Transport-Security "max-age=31536000" always;
}
En-tête Rôle
X-Content-Type-Options: nosniff Empêche le navigateur de deviner le type des fichiers
X-Frame-Options: SAMEORIGIN Interdit l’affichage du site dans une iframe d’un autre site
Referrer-Policy Limite les informations transmises dans l’en-tête Referer
Permissions-Policy Désactive des fonctions du navigateur inutiles
Strict-Transport-Security Impose HTTPS (voir HTTPS et certificats)
Content-Security-Policy Liste les origines autorisées pour scripts, styles, images (à tester soigneusement)
Fenêtre de terminal
sudo apt install apache2-utils # fournit htpasswd
sudo htpasswd -c /etc/nginx/.htpasswd alice # crée le fichier avec un premier utilisateur
sudo htpasswd /etc/nginx/.htpasswd bob # ajoute un utilisateur
sudo chown root:www-data /etc/nginx/.htpasswd
sudo chmod 640 /etc/nginx/.htpasswd
location /prive/ {
auth_basic "Zone privée";
auth_basic_user_file /etc/nginx/.htpasswd;
try_files $uri $uri/ =404;
}

Pour protéger tout le site, placer les deux directives dans le bloc server. Pour exempter un chemin : auth_basic off; dans son location.

location /admin/ {
allow 192.168.1.0/24;
allow 203.0.113.10;
deny all;
proxy_pass http://127.0.0.1:9000;
}

Les règles sont évaluées dans l’ordre. Combiner IP et mot de passe : satisfy all; (les deux requis) ou satisfy any; (l’un des deux suffit).

# Fichiers cachés (.git, .env…) sauf .well-known (certificats)
location ~ /\.(?!well-known) {
deny all;
}
# Sauvegardes et fichiers de configuration
location ~* \.(bak|sql|log|conf|ini|swp)$ {
deny all;
}

Ne jamais déployer .git ni .env dans le dossier servi, même avec ces règles.

client_max_body_size 10m; # corps de requête
client_body_timeout 15s;
client_header_timeout 15s;
send_timeout 30s;
keepalive_timeout 30s;
# Contexte http
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=connexion:10m rate=5r/m;
limit_conn_zone $binary_remote_addr zone=parip:10m;
server {
location / {
limit_req zone=general burst=20 nodelay; # 10 requêtes/s, avec rafales jusqu'à 20
limit_conn parip 20; # 20 connexions simultanées par IP
}
location = /connexion {
limit_req zone=connexion burst=3 nodelay; # 5 par minute : freine les essais de mots de passe
limit_req_status 429;
proxy_pass http://127.0.0.1:3000;
}
}
Directive Rôle
limit_req_zone Définit une zone (clé, mémoire, débit) dans le contexte http
limit_req Applique la limite (burst : rafale tolérée, nodelay : pas d’attente)
limit_conn Nombre de connexions simultanées par clé
limit_req_status 429 Code renvoyé (503 par défaut)

Sans nodelay, les requêtes en excès dans la limite de burst ne sont pas refusées mais retardées pour respecter le débit (12 secondes d’attente chacune avec 5 requêtes par minute) : nodelay les traite aussitôt et refuse celles qui dépassent le burst. Avec burst=3 nodelay, les 4 premières requêtes passent puis les suivantes reçoivent 429.

Derrière un proxy ou un CDN, remplacer $binary_remote_addr par l’adresse réelle du client (voir Reverse proxy).

if ($request_method !~ ^(GET|HEAD|POST)$) {
return 405;
}
Fenêtre de terminal
sudo apt install fail2ban
sudo tee /etc/fail2ban/jail.d/nginx.local <<'CONF'
[nginx-http-auth]
enabled = true
[nginx-limit-req]
enabled = true
[nginx-botsearch]
enabled = true
CONF
sudo systemctl restart fail2ban
sudo fail2ban-client status nginx-http-auth
Jail Détecte
nginx-http-auth Échecs de l’authentification basique
nginx-limit-req Dépassements de limit_req (journalisés dans error.log)
nginx-botsearch Recherche de scripts et pages inexistantes

Limiter les protocoles à TLSv1.2 et TLSv1.3 (valeur par défaut du nginx.conf d’Ubuntu 26.04) : voir HTTPS et certificats.

Fenêtre de terminal
sudo nginx -t && sudo systemctl reload nginx
curl -sI https://exemple.com | grep -iE "server|strict|x-content|x-frame|referrer"
curl -I https://exemple.com/.git/config # doit répondre 403 ou 404
curl -u alice:mauvais https://exemple.com/prive/ # 401
for i in $(seq 1 30); do curl -s -o /dev/null -w "%{http_code} " https://exemple.com/; done; echo # 429 ou 503 attendus après la limite
Symptôme Piste
Les en-têtes de sécurité disparaissent sur certaines pages add_header d’un location qui remplace ceux du server (voir l’avertissement ci-dessus)
401 en boucle Mot de passe incorrect, ou fichier .htpasswd illisible pour www-data
Des visiteurs légitimes reçoivent 429 ou 503 Augmenter rate ou burst ; clé de limitation incorrecte derrière un proxy
limit_req_zone : unknown directive Directive à placer dans le contexte http, pas dans server
Le fichier .well-known est bloqué (certificats) Garder l’exception (?!well-known) dans la règle des fichiers cachés

Ubuntu 24.04 et 26.04 : différences à connaître

Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »