Sécuriser son serveur
=====================
La plupart des attaques que va subir votre serveur seront réalisées par
des robots. Ce sont des petits programmes qui vont scanner le système
afin de déceler une faille de sécurité et l’exploiter.
Il est aussi possible qu’un pirate mène l’attaque. Ce dernier plus
intelligent sera le plus dangereux.
Voici plusieurs types d’attaques que peut subir votre serveur, et
comment s’en protéger :
- Un service (http, mail, ssh) est directement attaqué afin d’en
exploiter une faille de sécurité connue. Les mises à jour de
sécurité veillent à garder les services fiables
(voir [Mises à jour de sécurite](#mises-à-jour-de-sécurite)).
- Un attaquant peut effectuer de nombreuses requêtes afin de déceler
sur quels ports il peut trouver une faille. Un parefeu (voir
[Parefeu](#parefeu)) va limiter le nombre de ports à l’écoute et portsentry
(voir [Portsentry](#portsentry)) va empêcher que l’on scanne les ports ouverts
sur votre serveur.
- Si un service est disponible (http ou ssh par exemple), un attaquant
peut essayer des milliers de combinaisons d’identifiants et mots de
passe. Cela a deux effets. Tout d’abord, votre serveur est surchargé
et ralenti. De plus, un essai de connexion peut malheureusement
réussir à un moment donné après des milliers d’essais.
Fail2ban (voir [Fail2ban](#fail2ban)) va bannir ceux qui tenteraient ce passage
en force.
Imaginez votre serveur un peu comme votre maison.
En général, vous fermez les portes à clé, comme le parefeu ferme
certains ports.
Un cambrioleur va d'abord repérer si des portes sont ouvertes.
C'est équivalent à scanner les ports de votre serveur (voir
Portsentry).
Vous pouvez aussi rajouter une alarme à vote maison, avec un mot
de passe pour la désactiver. Fail2ban tient
ce rôle en quelque sorte, sauf que lui il jette les cambrioleurs à
coups de pieds au fesses s'ils échouent à s'identifier.
Cette liste n’est bien sûr pas exhaustive. Bien qu’un serveur
auto-hébergé présente moins d’intérêt pour un pirate que ceux de google
et risque donc moins d’être attaqué, veillez à vous renseigner un
minimum sur la façon de sécuriser votre serveur. *L’utilisation de
fail2ban et de “phrases de passe” longues* vous permettront d’esquiver
une grande partie des assauts.
Mises à jour de sécurité
------------------------
Une des choses les plus importantes pour prendre soin de son serveur,
c’est de le mettre à jour et ainsi profiter des patchs que debian
propose.
Petite piqûre de rappel pour mettre votre système debian à jour :
```
# apt-get update
# apt-get upgrade
# apt-get dist-update
```
### Unattended-upgrades
Afin d’effectuer les mises à jours de sécurité, il est possible de
configurer votre serveur pour qu’il vous envoie un mail lorsque ces
mises à jours sont disponibles.
Tout d’abord, installez les paquets suivants :
```
# apt-get install unattended-upgrades apt-listchanges
```
Il faut ensuite configurer unattended-upgrades en éditant le fichier
`/etc/apt/apt.conf.d/50unattended-upgrades`.
Dans la partie contenant `Unattended-Upgrade::Origins-Pattern { `, vous
pouvez décommenter (en retirant les `//` au début de ligne) les sections
de debian à mettre à jour automatiquement. *Je vous le déconseille, le
mieux étant toujours de faire la mise à jour directement “à la main”.*
Par contre, pour être averti par mail, il est nécessaire de décommenter
la ligne suivante :
```
//Unattended-Upgrade::Mail "root";
```
Enfin, pour activer unattended-upgrades, lancez la commande suivante :
```
dpkg-reconfigure -plow unattended-upgrades
```
Il y a alors un fichier `/etc/apt/apt.conf.d/20auto-upgrades` de créé,
qui contient :
```
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
```
Pour éviter que les mises à jour soient automatiques, changez la
deuxième ligne pour avoir :
```
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "0";
```
Parefeu
-------
Un parefeu, c'est un programme qui va faire la douane à
l'entrée de votre serveur. Selon les règles que vous lui avez
donné, il ne laissera passer les visiteurs que par les ports que
vous avez ouvert.
Un parefeu bien configuré est essentiel pour la sécurité de votre
serveur. C’est un premier rempart contre les attaques des pirates ou
robots.
**Le paquet arno-iptables-firewall** est parfait pour faciliter cette opération.
Lors de l’installation, il vous posera quelques questions pour configurer
le parefeu. En cas de modifications ultérieures, modifiez le fichier
`/etc/arno-iptables-firewall/conf.d/00debconf.conf`
Ce fichier ressemble à ceci :
```
EXT_IF="eth0"
EXT_IF_DHCP_IP=1
OPEN_TCP="22 443 587 80 25 143 993"
OPEN_UDP=""
INT_IF="192.168.1.66"
NAT=0
INTERNAL_NET=""
NAT_INTERNAL_NET=""
OPEN_ICMP=0
```
La partie qui nous intéresse principalement, c’est les variables
`OPEN_TCP` et `OPEN_UDP`, dans lesquelles on peut rajouter des numéros
de ports.
Pensez juste à relancer le parefeu une fois vos modifications terminées :
```
# service arno-iptables-firewall restart
```
**Certains préféreront utiliser *ufw* ** pour gérer leur parefeu,
qui est tout aussi valable. Voici quelques commandes utiles :
- `ufw default deny` : refuse tout en entrée. Il *faut* entrer cette
commande en premier, puis seulement ensuite ouvrir les ports au cas
par cas.
- `ufw allow 22/tcp` : autorise le port 22 en TCP.
- `ufw enable` : Active ufw après les modifications
Par défaut, iptables, le parefeu de linux (enfin la
surcouche à netfilter pour les puristes) laisse tout passer. C'est
pourquoi il est important de tout fermer en entrée du serveur,
puis ouvrir uniquement ce que vous voulez rendre disponible au monde.
Il existe 2 types de protocole : TCP et UDP. Chaque port peut être
ouvert seulement pour ne laisser passer qu'un seul de ces deux
protocoles. Il n'est pas nécessaire
de bien comprendre la différence entre les 2. Il s'agit très
grossièrement de la façon dont le serveur et le visiteur vont se
parler.
Fail2ban
--------
Fail2ban est sans doute le logiciel le plus important à avoir pour
protéger votre serveur. C’est une sorte de gardien intelligent. Il va
surveiller qui tente d’accéder à votre serveur, et si cette personne
échoue plusieurs fois (par exemple à cause d’un mauvais mot de passe),
alors elle est bannie et on ne l’écoute plus.
Fail2ban fonctionne avec ssh, mais aussi le serveur mail postfix et
dovecot, ainsi que d’autres services comme le ftp.
Pour l’installer, c’est toujours aussi simple :
```
# apt-get install fail2ban
```
### Mieux comprendre la configuration
La configuration de fail2ban se déroule dans le fichier
`/etc/fail2ban/jail.local`.
Ce fichier est découpé en plusieurs sections que l’on repère facilement
puisqu’elles sont entre crochets : `[section]`.
La première section est `[DEFAULT]` et permet de définir des valeurs qui
seront utilisée par la suite, sauf si vous les modifiez dans les
sections.
Voyons ce que signifient certaines options :
- `port` : permet de préciser sur quel port le service écoute. Par
exemple, pour nginx, c’est le 80 ou `http`.
- `bantime` : C’est le nombre de secondes pendant lequel les éventuels
attaquants seront bannis. Évitez les chiffres ronds, puisque ce sont
souvent des robots qui réalisent les attaques.
- `maxretry` : Nombre d’essais autorisés pendant le temps `findtime`
- `findtime` : Nombre de secondes pendant lequel on regarde si
l’attaquant tente un nouvel assaut.
- `logpath` : l’emplacement du fichier de log (fichier qui enregistre
l’activité du service)
Vous avez bien sûr la possibilité de créer vos propres filtres, mais
cela relève d’une documentation propre à fail2ban. Vous pouvez toutefois
visiter [le site de
fail2ban](http://www.fail2ban.org/wiki/index.php/Main_Page) si le sujet
vous intéresse.
Dans tous les cas, je vous conseille de jeter un œil au
fichier `/etc/fail2ban/jail.conf` pour d’autres exemples.
### Configuration rapide
Je vous propose ci-dessous une configuration déjà toute prête. Pour le
fichier `/etc/fail2ban/jail.local` :
```
[DEFAULT]
ignoreip = 127.0.0.1/8
ignorecommand =
bantime = 610
findtime = 600
maxretry = 3
backend = auto
usedns = warn
destemail = root@localhost
sendername = Fail2Ban
sender = fail2ban@localhost
banaction = iptables-multiport
mta = sendmail
protocol = tcp
action = %(action_mwl)s
[ssh]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
[pam-generic]
enabled = true
filter = pam-generic
port = all
banaction = iptables-allports
logpath = /var/log/auth.log
maxretry = 3
[xinetd-fail]
enabled = true
filter = xinetd-fail
port = all
banaction = iptables-multiport-log
logpath = /var/log/daemon.log
maxretry = 2
[ssh-ddos]
enabled = true
port = ssh
filter = sshd-ddos
logpath = /var/log/auth.log
maxretry = 3
[ssh-route]
enabled = false
filter = sshd
action = route
logpath = /var/log/sshd.log
maxretry = 6
[ssh-iptables-ipset4]
enabled = false
port = ssh
filter = sshd
banaction = iptables-ipset-proto4
logpath = /var/log/sshd.log
maxretry = 6
[ssh-iptables-ipset6]
enabled = false
port = ssh
filter = sshd
banaction = iptables-ipset-proto6
logpath = /var/log/sshd.log
maxretry = 6
[php-url-fopen]
enabled = false
port = http,https
filter = php-url-fopen
logpath = /var/www/*/logs/access_log
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
[vsftpd]
enabled = false
port = ftp,ftp-data,ftps,ftps-data
filter = vsftpd
logpath = /var/log/vsftpd.log
maxretry = 6
[postfix]
enabled = true
port = smtp,ssmtp,submission
filter = postfix
logpath = /var/log/mail.log
[sasl]
enabled = true
port = smtp,ssmtp,submission,imap2,imap3,imaps,pop3,pop3s
filter = postfix-sasl
logpath = /var/log/mail.log
[dovecot]
enabled = true
port = smtp,ssmtp,submission,imap2,imap3,imaps,pop3,pop3s
filter = dovecot
logpath = /var/log/mail.log
[ssh-blocklist]
enabled = false
filter = sshd
action = iptables[name=SSH, port=ssh, protocol=tcp]
sendmail-whois[name=SSH, dest="%(destemail)s",\
sender="%(sender)s", sendername="%(sendername)s"]
blocklist_de[email="%(sender)s", apikey="xxxxxx",\
service="%(filter)s"]
logpath = /var/log/sshd.log
maxretry = 20
[nginx-404]
enabled = true
filter = nginx-404
action = iptables-multiport[name=nginx-404, port="http,https", protocol=tcp]
logpath = /var/log/nginx*/*error*.log
maxretry = 2
findtime = 6
bantime = 1200
[nginx-auth]
enabled = true
filter = nginx-auth
action = iptables-multiport[name=NoAuthFailures, port="http,https"]
logpath = /var/log/nginx*/*error*.log
bantime = 630
maxretry = 3
[nginx-login]
enabled = true
filter = nginx-login
action = iptables-multiport[name=NoLoginFailures, port="http,https"]
logpath = /var/log/nginx*/*error*.log
bantime = 630
maxretry = 3
[nginx-badbots]
enabled = true
filter = apache-badbots
action = iptables-multiport[name=BadBots, port="http,https"]
logpath = /var/log/nginx*/*error*.log
bantime = 87000
maxretry = 1
[nginx-noscript]
enabled = true
action = iptables-multiport[name=NoScript, port="http,https"]
filter = nginx-noscript
logpath = /var/log/nginx*/*error*.log
maxretry = 6
bantime = 87000
[nginx-proxy]
enabled = true
action = iptables-multiport[name=NoProxy, port="http,https"]
filter = nginx-proxy
logpath = /var/log/nginx*/*error*.log
maxretry = 0
bantime = 87000
```
La fin de cette configuration nécessite des filtres pour nginx qu’il
faut ajouter dans `/etc/fail2ban/filter.d`.
- Fichier `nginx-404.conf`
```
[Definition]
failregex = - - [.*?] ".*?" 4(0[0-9]|1[0-5])
ignoreregex =
```
- Fichier `nginx-proxy.conf`
```
# Proxy filter /etc/fail2ban/filter.d/nginx-proxy.conf:
#
# Block IPs trying to use server as proxy.
#
# Matches e.g.
# 192.168.1.1 - - "GET http://www.something.com/
#
[Definition]
failregex = ^ -.*GET http.*
ignoreregex =
```
- Fichier `nginx-noscript.conf`
```
# Noscript filter /etc/fail2ban/filter.d/nginx-noscript.conf:
#
# Block IPs trying to execute scripts such as .php, .pl, .exe and other funny scripts.
#
# Matches e.g.
# 192.168.1.1 - - "GET /something.php
#
[Definition]
failregex = ^ -.*GET.*(\.php|\.asp|\.exe|\.pl|\.cgi|\scgi)
ignoreregex =
```
- Fichier `nginx-auth.conf`
```
# Auth filter /etc/fail2ban/filter.d/nginx-auth.conf:
#
# Blocks IPs that fail to authenticate using basic authentication
#
[Definition]
failregex = no user/password was provided for basic \
authentication.*client:
user .* was not found in.*client:
user .* password mismatch.*client:
ignoreregex =
```
- Fichier `nginx-login.conf`
```
# Login filter /etc/fail2ban/filter.d/nginx-login.conf:
#
# Blocks IPs that fail to authenticate
# using web application's log in page
#
# Scan access log for HTTP 200 + POST /sessions => failed log in
[Definition]
failregex = ^ -.*POST /sessions HTTP/1\.." 200
ignoreregex =
```
À la fin de la configuration, il faut recharger fail2ban :
```
# service fail2ban restart
```
Portsentry
----------
Portsentry permet de se prémunir contre le scan des ports vulnérables sur
votre serveur.
Installez le paquet `portsentry`.
Ensuite, on va procéder à la configuration. Au lieu de coller ci-dessous
une grande quantité de texte, vérifier simplement que le contenu écrit
est bien présent dans les fichiers donnés :
- Fichier `/etc/portsentry/portsentry.conf`
```
TCP_PORTS="1,11,15,79,111,119,143,540,635,1080,1524,2000,5742,6667,\
12345,12346,20034,27665,31337,32771,\
32772,32773,32774,40421,49724,54320"
UDP_PORTS="1,7,9,69,161,162,513,635,640,641,700,37444,34555,\
31335,32770,32771,32772,32773,32774,31337,54321"
ADVANCED_PORTS_TCP="1024"
ADVANCED_PORTS_UDP="1024"
ADVANCED_EXCLUDE_TCP="113,139"
ADVANCED_EXCLUDE_UDP="520,138,137,67"
IGNORE_FILE="/etc/portsentry/portsentry.ignore"
HISTORY_FILE="/var/lib/portsentry/portsentry.history"
BLOCKED_FILE="/var/lib/portsentry/portsentry.blocked"
RESOLVE_HOST = "0"
BLOCK_UDP="1"
BLOCK_TCP="1"
KILL_ROUTE="/sbin/route add -host $TARGET$ reject"
KILL_HOSTS_DENY="ALL: $TARGET$ : DENY"
KILL_RUN_CMD="/sbin/iptables -I INPUT -s $TARGET$ -j DROP && \
/sbin/iptables -I INPUT -s $TARGET$ -m limit \
--limit 3/minute --limit-burst 5 -j LOG \
--log-level debub --log-prefix 'Portsentry: dropping: '"
SCAN_TRIGGER="0"
```
- Fichier `/etc/default/portsentry` :
```
TCP_MODE="atcp"
UDP_MODE="audp"
```
Et pour finir, on recharge portsentry :
```
# service portsentry restart
```
Redémarrages nécessaires
------------------------
Il est parfois nécessaire de redémarrer certains services, voire le
serveur après des mises à jours.
Si vous ne savez pas trop ce qui doit être redémarré, sachez qu’il
existe le paquet `needrestart`.
Il ne vous restera plus qu’à lancer la commande `needrestart -kl`, pour
voir apparaître des messages indiquant ce qui doit être relancé.
Ce qui est génial, c’est que vous verrez ce message après une mise à
jour, car needrestart sera automatiquement lancé.
De façon générale, vous pouvez relancer un service avec la commande
suivante :
```
# /etc/init.d/nom_du_service restart
```
Chasseur de rootkit
-------------------
Un rootkit est un petit programme qui peut permettre à un attaquant
d’obtenir les droits super-utilisateur sur votre serveur.
Il existe heureusement quelques outils pour vérifier si votre système
contient un rootkit, comme par exemple *rkhunter*
Pour l’installer, il faut juste ajouter le paquet du même nom :
```
# apt-get install rkhunter
```
Son fichier de configuration est `/etc/rkhunter.conf`. Pour qu’il
fonctionne bien, je vous propose de décommenter, modifier ou ajouter les
lignes suivantes :
```
ALLOWHIDDENDIR="/dev/.udev";
ALLOWHIDDENDIR="/dev/.static";
MAIL-ON-WARNING="root@localhost"
SCRIPTWHITELIST=/usr/bin/unhide
```
De cette façon vous serez averti par mail si un rootkit est détecté.
Lancez ensuite ces commandes pour préparer rkhunter
```
rkhunter --update
rkhunter --propupdate
```
Pour tester votre système, il faut lancer la commande :
```
rkhunter --check
```
Notez que le système est vérifié une fois par jour grâce à une tâche
cron par défaut.
Pour que les informations pour rkhunter soient mises à jour après chaque
exécution de apt, vous pouvez créer le fichier
`/etc/apt/apt.conf/98-rkhunter` et mettre dedans :
```
DPkg::Post-Invoke {
"rkhunter --update;"
"rkhunter --propupdate";
};
```
Sécurisation minimale de MySQL
------------------------------
Si vous avez choisi d’installer la base de données MySQL, il est
conseillé de lancer la commande `mysql_secure_installation`. Il vous
sera posé une série de questions afin de sécuriser la base de
données.[^1]
Cela ressemblera à ça :
```
Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation.
You already have a root password set, so you can safely answer 'n'.
Change the root password? [Y/n] n
... skipping.
By default, a MySQL installation has an anonymous user, allowing anyone
to log into MySQL without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.
Remove anonymous users? [Y/n] Y
... Success!
Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] Y
... Success!
By default, MySQL comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.
Remove test database and access to it? [Y/n] Y
- Dropping test database...
ERROR 1008 (HY000) at line 1: Can't drop database 'test'; database doesn't exist
... Failed! Not critical, keep moving...
- Removing privileges on test database...
... Success!
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] Y
... Success!
Cleaning up...
All done! If you've completed all of the above steps, your MySQL
installation should now be secure.
Thanks for using MySQL!
```
Suggestions d’améliorations avec lynis
--------------------------------------
Lynis est un petit programme qui peut scanner votre serveur et vous
suggérer des améliorations. Il vous suffit d’installer le paquet `lynis`
(eh oui quelle surprise!)
Ensuite, lancez simplement la commande
```
lynis -c
```
Vous verrez alors plusieurs scans et conseils à l’écran. L’ensemble peut
être retrouvé dans `/var/log/lynis.log`. Cherchez les lignes contenant
*Suggestion* pour voir des propositions afin d’améliorer la sécurité de
votre serveur.
[^1]: Merci PengouinPdt pour l’info