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