formations/cesi/hebergement_web/05-security.md

306 lines
6.6 KiB
Markdown
Raw Permalink Normal View History

2019-05-15 12:23:31 +02:00
% Introduction à la sécurité d'un serveur web
% Sylvain Eliade — S.C.O.P. Cadoles
## Introduction à la sécurité d'un serveur web
## Fail2ban
S'il ne faut en retenir qu'un c'est celui-là !
`apt install fail2ban`
Il lit les logs en permanence et détecte les tentatives d'intrusion (mauvais mot de passe SSH, email, HTTP…) et bloque les IP automatiquement !
Activer les filtres dans `/etc/fail2ban/jail.conf` (passer `enabled` à `true`). Normalement la plupart des filtres nécessaires sont activés par défaut, mais ça vaut le coup de regarder si on peut en activer d'autres, ou de faire les siens !
## Mises à jours de sécurité
Ça semble évident, mais ça ne l'est pas pour tout le monde.
Activer les mises à jour automatique de sécurité avec `unattended-upgrades`.
```
apt install unattended-upgrades
```
---
## Pare-feu (firewall)
Sous Linux, les ports sont fermés par défaut si un service n'écoute pas dessus, donc c'est "sécurisé" par défaut. Alors pourquoi un firewall ?
Parce que si un attaquant parvient à ouvrir un port sur votre machine il peut s'en servir pour lui donner des ordres, ou faire des requêtes vers d'autres machines (par exemple transformer votre serveur en attaquant DDoS).
Du coup un firewall est utile pour restreindre le risque en cas d'attaque.
---
## Pare-feu Linux
Le noyau Linux contient déjà un pare-feu, c'est Netfilter, accessible via la commande `iptables`.
Comme elle est un peu complexe, on conseille en général d'utiliser `ufw` (Uncomplicated FireWall), qui est une interface iptables simplifiée.
---
## UFW
Installer avec `apt install ufw`, et activer avec `ufw enable`.
Consulter le statut avec `ufw status verbose`.
```
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
```
Lister les règles disponibles : `ufw app list`
---
(Dés)Activer le blocage par défaut :
```
ufw default allow incoming
ufw default deny outgoing
```
Activer un service :
```
ufw allow in WWW
ufw allow out VNC
```
---
Autoriser un port :
```
ufw allow 53
ufw allow 25/tcp
```
Bloquer une IP :
```
ufw deny from X.X.X.X to any
```
---
## Restriction par IP
Si on veut restreindre l'accès à un serveur web à certaines IP il y a plusieurs stratégies possibles :
* au niveau du firewall (mieux, car le plus tôt dans la connexion réseau)
* via TCP Wrappers ou systemd
* via le serveur web
---
## Avec UFW
```
ufw deny 80
ufw allow from X.X.X.X to any port 80
```
---
## TCP Wrappers
Mécanisme ancien, simple, mais aujourd'hui on utilise un firewall.
Malgré le nom, il gère aussi UDP.
La configuration se fait dans les fichiers `/etc/hosts.allow` et `/etc/hosts.deny`.
N'est plus supporté par systemd.
---
```
# /etc/hosts.allow
sshd: 192.168.1.0/255.255.255.0
# /etc/hosts.deny
sshd: ALL
````
---
## Restriction avec systemd
Se fait au niveau du fichier `.service` :
```
IPAddressDeny=1.1.1.1
IPAddressAllow=8.8.8.8
```
Encore une fois, mieux vaut préférer un firewall.
---
## Restriction avec Apache
Avantage : peut se faire par répertoire, vhost, fichier…
Tout autoriser sauf une IP :
```
<RequireAll>
Require all granted
Require not ip 10.252.46.165
</RequireAll>
```
---
Tout bloquer sauf si connexion valide OU adresse IP spécifique :
```
<RequireAll>
Require all denied
<RequireAny>
Require ip 192.168.1.12
Require valid-user
</RequireAny>
</RequireAll>
```
---
## Ne pas se tirer une balle dans le pied
* Utiliser PHP 7.2 ou 7.3 ! Abandonnez PHP 5 et PHP 7.0 (plus supportés !) ! Enfin si c'est possible…
* Configurer le serveur web pour n'écouter que sur l'interface / port nécessaire (`/etc/apache2/ports.conf`)
* Ne pas exposer sa version de PHP ou Apache (ou nginx)
* Désactiver le vhost par défaut d'apache, dont la page HTML peut contenir des infos utiles à un attaquant
* Bloquer l'accès aux répertoires .svn et .git !
```
RedirectMatch 404 /\.git
RedirectMatch 404 /\.svn
```
---
## Cacher les versions
Pourquoi ? Contre les bots qui scannent les serveurs pas à jour.
Dans `/etc/apache2/conf-enabled/security.conf` :
```
ServerTokens Prod
ServerSignature Off
```
---
Avant :
`Server: Apache/2.4.25 (Debian)`
Après :
`Server: Apache`
---
Dans `/etc/php/7.0/apache/conf.d/local.ini` ajouter :
```
expose_php = off
```
---
## Restreindre la surface d'attaque (Apache)
Désactiver les index de répertoires, l'exécution de CGI, les liens symboliques et les inclusions :
```
<Directory />
Options -Indexes -ExecCGI -FollowSymLinks -Includes
</Directory>
```
Désactiver les .htaccess si possible.
---
## Restreindre la surface d'attaque (PHP)
Restreindre les répertoires accessibles de PHP (dans le vhost Apache) :
```
php_admin_value open_basedir /var/www/monsite.com
```
Interdire l'exécution de programme externe :
```
disable_functions = exec,passthru,shell_exec,system,proc_open,popen
```
à mettre dans le `/etc/php/7.0/apache/conf.d/local.ini`, ou dans un `php_admin_value` par vhost.
---
## Aller plus loin
Vérifier sa config :
* Audit automatisé : mieux que ne rien faire, mais à ne pas faire en prod, laisse pas mal de traces (logs), peut surcharger le serveur
* Audit manuel : de bonnes connaissances en sécu, ou un bon chéquier !
* Hardening PHP : ça restreint certaines fonctions et attaques, mais c'est bien mais ça peut casser des applis :(
* WAF (Web Application Firewall) : idem, ça détecte des attaques connues, bonne stratégie défensive, mais attention aux effets de bord.
---
* [Auditer son site avec Nikto](https://doc.ubuntu-fr.org/nikto)
* [Hardening PHP : snuffleupagus (Apache)](https://github.com/nbs-system/snuffleupagus)
* [Tester son certificat SSL avec SSL Labs](https://www.ssllabs.com/ssltest/)
* [Mise en place de WAF avec mod_security pour Apache](https://www.it-connect.fr/installation-de-mod_security-devant-un-serveur-web-apache/)
* [WAF pour nginx avec naxsi](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-naxsi-on-ubuntu-16-04)
---
## Exercice 1
Installer `ufw` et n'autoriser que le port 80 en entrée.
Vérifier avec :
```
nmap -p 80 ADRESSE_IP
nmap -p 443 ADRESSE_IP
```
La première doit renvoyer que le port est ouvert, mais pas la seconde.
---
## Exercice 2
Modifier le `.htaccess` du répertoire `secret` précédemment créé pour autoriser aussi l'adresse IP `127.0.0.1` à y accéder sans mot de passe.
Vérifier avec curl.
---
## Exercice 3
Cacher les versions de PHP et Apache. Vérifier avec Curl.
---
## Exercice 4 (facultatif)
Installer Nikto et scanner les vhosts du serveur web. Nikto est dans les dépôts `non-free` de Debian : https://debian-facile.org/doc:systeme:apt:sources.list:sources.list-non-free