Comment sécuriser un minimum son serveur et son site.
Même si la pile TCP/IP du système d'exploitation GNU/Linux est reconnue comme étant une des plus stables, appliquer ce principe de précaution est bien loin d'être un mal, au contraire !
Ouvrir le fichier /etc/sysctl.conf, puis modifer tel que :
# Se protéger de l'IP Spoofing' (vol d'adresse IP) : net.ipv4.conf.all.rp_filter = 1 # Se protéger des attaques 'SYN Flood' : net.ipv4.tcp_syncookies = 1 # Ignorer les messages 'ICMP Redirects' : net.ipv4.conf.all.accept_redirects = 0 net.ipv6.conf.all.accept_redirects = 0 # Interdire 'Source Routing' : net.ipv4.conf.all.accept_source_route = 0 net.ipv6.conf.all.accept_source_route = 0Et ajouter :
# Surveiller 'martians' (adresse source falsifiée ou non routable) : net.ipv4.conf.all.log_martians = 1 # Ignorer les messages 'ICMP Echo Request' : net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.icmp_echo_ignore_all = 1 # Ignorer les messages 'ICMP Bogus Responses' : net.ipv4.icmp_ignore_bogus_error_responses = 1 # 1024 connexions non confirmées max, limite le SYN flood net.ipv4.tcp_max_syn_backlog = 1024
Redémarrer le service :
root@serveur # sysctl -p /etc/sysctl.conf
On va faire en sorte que l'authentification se fasse par un système de clés publique/privée pour contrer les futurs essais de force brute. De plus on ne sera plus obligé d'entrer un mot de passe à chaque fois.
utilisateur@machine % aptitude install ssh
utilisateur@machine % ssh-keygen -t rsa
Plusieurs informations seront demandées, dans l'ordre :
Note : par la suite, pour modifer la passephrase, il faudra utiliser la commande :
utilisateur@machine % ssh-keygen -p -t rsa
Copier la clef générée dans la liste des clefs autorisées :
utilisateur@machine % cat ~/.ssh/id_rsa.pub >~/.ssh/authorized_keys
Copier la clef vers le serveur :
utilisateur@machine % ssh utilisateur@ip
utilisateur@serveur % mkdir ~/.ssh
utilisateur@serveur % touch ~/.ssh/authorized_keys
utilisateur@serveur % exit
utilisateur@machine % ssh-copy-id -i ~/.ssh/id_rsa.pub utilisateur@ip
Modifier le fichier /etc/ssh/sshd_config tel que :
Interdire la connexion en tant que super utilisateur PermitRootLogin no Autoriser seulement l'authentification par clefs AuthorizedKeysFile %h/.ssh/authorized_keys Ainsi qu'interdire l'accès à l'aide de mot de passe PasswordAuthentication no
Redémarrer SSH :
root@serveur # service ssh restart
Ne donner l'accès à une console qu'aux seuls utilisateurs qui en ont besoin (root et utilisateur de travail) en modifiant le fichier /etc/passwd.
Par défaut, la console est définie tel quel à la fin de chaque ligne :
/bin/sh ou /bin/*sh (suivant le shell utilisé)
Pour interdire l'accès, il suffit de le modifier en :
/bin/false
Pour se tenir informé de ce qu'il se passe sur votre serveur et système tout entier, on va installer Syslog-ng :
root@serveur # aptitude install syslog-ng
logtarget = SYSLOG
ErrorLog syslog:local7
log_errors = On
error_log = syslog
Installer cet outil qui vérifiera régulièrement la présence de rootkit et autres programmes modifiés sans que vous ne le sachiez :
root@serveur # aptitude install rkhunter
Ouvrir le fichier /etc/rkhunter.conf.
Spécifier une ou plusieurs adresse(s) courriel :
MAIL-ON-WARNING=root@localhost btg@bobotig.fr
Envoyer les informations à Syslog-NG :
USE_SYSLOG=authpriv.warning (...) ALLOW_SYSLOG_REMOTE_LOGGING=1
root@serveur # rkhunter --updateLancer une analyse :
root@serveur # rkhunter -c --rwo --skAvec :
-c : vérifier le système entier --rwo (report-warnings-only) : n'afficher que les erreurs ou alertes --sk (skip-keypress) : ne pas attendre d'intervention de la part de l'utilisateur -l rkhunter.log : insérer un résumé dans un fichier log
Afin de bloquer les attaques de type force brute, on va installer fail2ban :
root@serveur # aptitude install fail2banIl va falloir activer certaines prisons qui ne le sont pas par défaut.
(...) # Temps de ban en secondes bantime = 600 # Nombre de tentatives avant ban maxretry = 3 (...) # Votre adresse courriel destemail = root@localhost (...) [ssh] enabled = true maxretry = 3 (...) [ssh-ddos] enabled = true maxretry = 3 (...) [apache] enabled = true maxretry = 3 (...) [apache-multiport] enabled = true maxretry = 3 (...) [apache-noscript] enabled = true maxretry = 3 (...) [apache-overflows] enabled = true maxretry = 2 (...) [named-refused-udp] enabled = true port = domain,953 protocol = udp filter = name_refused logpath = /var/log/named/security.log (...) [named-refused-tcp] enabled = trueDémarrer fail2ban :
root@serveur # service fail2ban restartVérifier que les prisons sont bien en place :
root@serveur # cat /var/log/fail2ban.logDevrait retourner :
fail2ban.filter : INFO Set findtime = 600 fail2ban.actions: INFO Set banTime = 600 fail2ban.jail : INFO Jail 'apache-noscript' started fail2ban.jail : INFO Jail 'named-refused-udp' started fail2ban.jail : INFO Jail 'ssh-ddos' started fail2ban.jail : INFO Jail 'apache-multiport' started fail2ban.jail : INFO Jail 'apache-overflows' started fail2ban.jail : INFO Jail 'ssh' started fail2ban.jail : INFO Jail 'apache' started fail2ban.jail : INFO Jail 'named-refused-tcp' started
Snort est un IDS qui vous permettra de détecter d'éventuelles intrusions, de gérer vos logs et sniffer votre réseau.
Il est possible d'obtenir de plus amples informations concernant ce logiciel sur Wikipédia.
root@serveur # aptitude install mysql-server snort-mysql
root@serveur # mysql -u root -p -h localhost
mysql > CREATE DATABASE `snort` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
mysql > CREATE USER `snortu`@`localhost`;
mysql > SET PASSWORD FOR `snortu`@`localhost`=PASSWORD('snortp');
mysql > GRANT CREATE, DELETE, INSERT, SELECT, UPDATE on `snort`.* to `snortu`@`localhost`;
mysql > quit
root@serveur # cd /usr/share/doc/snort-mysql/Copier le fichier de configuration de snort tel que :
root@serveur # zcat create_mysql.gz | mysql -u root -p -h localhost snort
root@serveur # cp /etc/snort/snort.conf /etc/snort/snort.interface.confNote : remplacer interface par votre interface réseau, chez moi eth0.
Modifier le réseau surveillé var HOME_NET 192.168.0.0/24 Commenter la ligne suivante : output log_tcpdump: tcpdump.log Appliquer les règles sur les SellCodes include $RULE_PATH/virus.rules include $RULE_PATH/shellcode.rulesOptionnel : commenter certaines règles qui, ici, ne sont d'aucune utilité :
#include $RULE_PATH/web-cgi.rules #include $RULE_PATH/web-coldfusion.rules #include $RULE_PATH/web-iis.rules #include $RULE_PATH/web-frontpage.rules #include $RULE_PATH/community-web-iis.rules #include $RULE_PATH/x11.rules #include $RULE_PATH/oracle.rules #include $RULE_PATH/community-oracle.rules #include $RULE_PATH/pop2.rules #include $RULE_PATH/nntp.rules #include $RULE_PATH/community-nntp.rules #include $RULE_PATH/community-sip.rulesOuvrir le fichier /etc/snort/database.conf et modifer la dernière ligne :
output database: alert, mysql, dbname=snort user=snortu password=snortp host=localhost
root@serveur # rm /etc/snort/db-pending-configEt enfin, lancer snort :
root@serveur # service snort start
root@serveur # snort -u utilisateur -c /etc/snort/snort.wlan1.conf -i wlan1 -D
ACID est un analyseur de log pour Snort, il permet de visualiser facilement les log par l'intermédiaire d'une interface web.
root@serveur # aptitude install acidbase
root@serveur # cp /etc/acidbase/apache.conf /etc/apache2/sites-available/acidbase
allow from 192.168.0.3Et commenter les 3 premières lignes :
#<IfModule mod_alias.c> # Alias /acidbase "/usr/share/acidbase" #</IfModule>Ouvrir le fichier /etc/acidbase/base_conf.php et modifier tel que :
$BASE_Language = 'french'; $colored_alerts = 1;Ouvrir le fichier /etc/acidbase/database.php et modifier tel que :
$alert_user='snortu'; $alert_password='snortp'; $basepath=''; $alert_dbname='snort'; $alert_host=''; $alert_port=''; $DBtype='mysql';
root@serveur # a2ensite acidbase
root@serveur # service apache2 reloadMaintenant, vous pouvez vous rendre à l'adresse www.test.sec/acidbase/ pour terminter l'installation d'ACID(BASE) et décortiquer les alertes.
Webmin est une interface web permettant de gérer son serveur. Il est d'autant plus utile qu'il permet de voir ses logs, notammement ceux de syslog-ng et fail2ban.
Créer le fichier /etc/apt/sources.list.d/webmin.list et y inscrire :
# Dépôt Webmin deb http://download.webmin.com/download/repository sarge contrib
root@serveur # wget -c "www.webmin.com/jcameron-key.asc" -O - | apt-key add -
root@serveur # aptitude update
root@serveur # aptitude install webminAccéder à Webmin par https://www.test.sec:10000, on va passer à la configuration.
Par perdus j'entends là les fichiers qui n'ont pas de propriétaires ou qui ne devraient pas avoir les droits qu'ils ont.
Deux choses, l'une concerne les fichier sans propriétaire, l'autre les fichiers qui contiennent un SUID alors qu'il n'en ont pas besoin.
root@serveur # find / -ignore_readdir_race -name "*~"Libre à vous d'en faire ce que vous voulez, je vous recommande de les supprimer :
for f in $(find / -ignore_readdir_race -name "*~"); do rm $f; done
root@serveur # find / -ignore_readdir_race -nouser -nogroupLibre à vous d'en faire ce que vous voulez, en théorie il ne devrait pas y en avoir.
root@serveur # find / -ignore_readdir_race -perm -4000Exemple de retour :
/bin/su /bin/umount /bin/mount /bin/ping /bin/ping6 /usr/bin/passwd /usr/bin/newgrp /usr/bin/at /usr/bin/chfn /usr/bin/chsh /usr/bin/gpasswd /usr/bin/procmail /usr/bin/X /usr/lib/eject/dmcrypt-get-device /usr/lib/pt_chown /usr/lib/openssh/ssh-keysign /usr/sbin/exim4 /sbin/mount.nfsLa plupart des administrateurs systèmes recommandent de désactiver les services comme ping ou traceroute (lorsque vous n'en avez pas besoin).
root@serveur # chmod -s /chemin/du/binaire
Système d'exploitation | : | Debian GNU/Linux Squeeze (6.0.6) |
Serveur | : | Apache 2.2.16 |
PHP | : | PHP 5.3.3 |
Site | : | www.test.sec |
Emplacement | : | /var/www/ |
ddclient est un utilitaire très pratique qui permet d'automatiser la mise à jour d'une adresse IP dynamique reliée à un nom de domaine.
root@serveur # aptitude install ddclientAprès la configuration, éditer le fichier /etc/ddclient.conf et ajouter cette ligne :
ssl=yes
root@serveur # cpan -i IO::Socket::SSL
On va installer mod-security2 (pare-feu web) pour Apache.
Créer le fichier /etc/apt/sources.list.d/mod-security2.list et y inscrire :
### Dépôt pour mod-security2 ### deb //etc.inittab.org/~agi/debian/libapache-mod-security2 ./
root@serveur # gpg --keyserver pgpkeys.mit.edu --recv-keys C514AF8E4BA401C3
root@serveur # gpg --export -a C514AF8E4BA401C3 | apt-key add -
root@serveur # aptitude update
root@serveur # aptitude install libapache-mod-security mod-security-common
<IfModule mod_security2.c> Include /etc/modsecurity/*.conf </IfModule>
root@serveur # mkdir /etc/modsecurity
root@serveur # cd /usr/share/doc/mod-security-common/examples/rules
root@serveur # cp *.conf base_rules/* /etc/modsecurity/
root@serveur # mkdir /etc/apache2/logsOptionnel : commenter la ligne contenant Host header is a numeric IP address du fichier /etc/modsecurity/modsecurity_crs_21_protocol_anomalies.conf pour autoriser l'accès au site par l'intermédiaire d'une adresse IP.
root@serveur # a2enmod mod-security
root@serveur # apache2ctl restartVérifier que le module est bien chargé :
root@serveur # cat /var/log/apache2/error.log | grep ModSecurityDevrait renvoyer :
[notice] ModSecurity for Apache/2.5.12 (http://www.modsecurity.org/) configured.Bien qu'il s'agisse là d'un excellent module et d'une protection fiable, il se peut qu'il soit un peu chiant lorsque vous développez en local, le comportement de PHPmyAdmin peut être altéré, certains scripts retournerons une erreur car jugés dangereux.
SecRuleEngine Off
On va désactiver diverses divulgations d'informations comme la signature du serveur, la méthode TRACE, et caetera.
Éditer le fichier /etc/apache2/apache2.conf et ajouter ces lignes :
ServerSignature Off ServerTokens Prod TraceEnable Off
# Empêcher les attaques par include de fichier externe RewriteEngine On RewriteCond %{QUERY_STRING} =// RewriteRule .* - [F,L]
# Bloquer l'accès au site pour libwww-perl RewriteEngine On RewriteCond %{HTTP_USER_AGENT} libwww [NC] RewriteRule .* - [F,L]
# Protection contre les attaques se servant de register global on SetEnv REGISTER_GLOBALS 0Redémarrer apache :
root@serveur # service apache2 restartDans les fichiers d'options des vhosts ou dans un fichier .htaccess il est possible de bloquer certaines actions.
Options -Indexes
Options -MultiViews
Options -FollowSymLinks
Options -Indexes -FollowSymLinks -MultiViewsAttention : il est déconseillé de sécuriser un répertoire par un accès à l'aide de la méthode d'authentification d'Apache.
Pour savoir de quoi il s'agit, c'est par là. Pour ne pas faire que pomper, je vous redirige simplement vers une page où tout est très bien expliqué, c'est sur le site www.webstrat.fr [au cas où, je garde une copie non visible, si le site tombe je recopierai les informations].
Modifier le fichier /etc/php5/apache2/php.ini.
Ne pas fournir la version de PHP : expose_php = Off Restreindre les emplacements du site : open_basedir = /var/www De ce fait, si je me place à la racine du site, il me sera impossible d'inclure le fichier ../../../../../../../etc/passwd par exemple. Désactiver certaines commandes : disable_functions = php_uname, getmyuid, getmypid, passthru, leak, listen, diskfreespace, tmpfile, link, ignore_user_abord, shell_exec, dl, set_time_limit, exec, system, highlight_file, source, show_source, fpaththru, virtual, posix_ctermid, posix_getcwd, posix_getegid, posix_geteuid, posix_getgid, posix_getgrgid, posix_getgrnam, posix_getgroups, posix_getlogin, posix_getpgid, posix_getpgrp, posix_getpid, posix, _getppid, posix_getpwnam, posix_getpwuid, posix_getrlimit, posix_getsid, posix_getuid, posix_isatty, posix_kill, posix_mkfifo, posix_setegid, posix_seteuid, posix_setgid, posix_setpgid, posix_setsid, posix_setuid, posix_times, posix_ttyname, posix_uname, proc_open, proc_close, proc_get_status, proc_nice, proc_terminate, phpinfo Interdire l'ouverture et l'inclusion de fichiers distants : allow_url_fopen = Off allow_url_include = Off Si vous n'utilisez pas de formulaires pour l'envoi de fichiers, il est bon de désactivé le système d'envoi : file_uploads = Off Par contre si vous avez ce genre de formulaire, il faut limiter un répertoire d'envoi et une taille maximale : upload_tmp_dir = /var/php_tmp upload_max_filezize = 2M
session.save_path = /var/lib/php
session.cookie_httponly = 1De ce fait, JavaScript ne pourra accéder qu'aux cookies.
ignore_repeated_errors = On
error_log = /var/log/php_errors.logOu bien configurer-le tel qu'il redirige les messages vers syslog-NG (voir section Syslog-NG).
Il faut bien veiller à ce que certains fichiers ne soient accessibles pour tout le monde qu'en lecteur seule.
Il s'agit de ce genre de fichiers :
AuthUserFile /var/www/admin/.drowssap AuthGroupFile /var/www/admin/.puorg
Avant d'ajouter une quelconque information de votre base de données, échaper les caractères spéciaux à l'aide de la commande mysql_real_escape_string() :
Code PHP :
$chaine = mysql_real_escape_string($chaine);Avant de vérifier une information sensible dans la BDD comme le nom d'un utilisateur et son mot de passe, il faut toujours s'assurer que l'on n'entre pas de caractères spéciaux qui pourraient corrompre la requête.
(string)$utilisateur = trim(htmlspecialchars(addslashes($utilisateur))); (string)$motDePasse = trim(htmlspecialchars(addslashes($motDePasse))); (array)$interdit = array( '/&/', '/#/', '/\[/', '/\]/', '/\//', '/\'/', '/%/', '/=/', '/\(/', '/\)/', '/;/', '/--/', '/=/', '/ /', '/,/', '/(\<|\>|;|UNION|ALL|SELECT|WHERE|AND|OR|FROM|COUNT)/', '/\*/'); foreach ( $interdit as $valeur ) { if ( preg_match($valeur, $utilisateur) || preg_match($valeur, $motDePasse) ) { die ('Caractère interdit : tentative d\'injection SQL ?!'); } }Dernier point, et non des moindres, créer un utilisateur ayant des droits restreints pour toutes transactions.
root@serveur # mysql -u root -p -h localhostTel que créé ci-dessus, votre utilisateur utilisateur_restreint pourra interroger, insérer et supprimer des données dans la/les table(s) de la base de données base mais n'aura absolument aucun accès aux autres bases.
mysql > CREATE USER `utilisateur_restreint`@`localhost`;
mysql > SET PASSWORD FOR `utilisateur_restreint`@`localhost`=PASSWORD('mdp_complexe');
mysql > GRANT INSERT, SELECT, UPDATE, DELETE on `base`.* to `utilisateur_restreint`@`localhost`;
mysql > quit
La façon le plus fiable est de passer la commande directement grace à system('commande'), mais si vous devez le faire par l'intermédiaire d'une variable tel que system('$cmd'), il faut bien faire attention à empêcher le caractère pipe (|) :
Code PHP :
if ( (strstr($cmd, '|')) || (strstr($cmd, '%7c')) ) { die ('Erreur : caractère interdit !'); }
Toujours vérifier les possibles fichiers à inclure, ne pas laisser un trop grand choix d'inclusions et vérifier l'extension du fichier inclu.
Note : si vous avez installer le module mod-security2 pour apache, vous ne risquez pas grand chose quant au type d'inclusion visant un fichier sortant du répertoire web.
Exemple de code si vos inclusions doivent être dynamiques (essayer d'entourer le fichier inclu par un préfixe et un suffixe).
Code PHP :
if ( isset($_GET['page']) && ! empty($_GET['page']) ) { if ( file_exists('page-'.$_GET['page'].'.html') ) { include 'page-'.$_GET['page'].'.html'; } }
(array)$pages_autorisees = array('accueil', 'bas'); if ( isset($_GET['page']) && in_array($_GET['page'], $pages_autorisees) ) { include $_GET['page']; }
Toujours vérifier les fichier envoyés, si vous demandez une image de type PNG, il est hors de question de laisser passer un fichier PHP ou je ne sais quoi d'autre. L'idéal serait de pouvoir filtrer l'extension en plus du type mime.
Si vous autorisez l'envoi de scripts, quelque soit le langage, faîtes une copie en fichier texte et n'autoriser personne à l'exécuter hormis root :
Code PHP :
copy($fichier, $fichier.'.txt'); chmod($fichier.'.txt', 400);Vérifier l'extension et le nom du fichier uploadé.
(array)$extensions = array('.jpeg', '.png', '.gif'); (string)$fichier = $_FILES['fichier']['name']; if ( preg_match('#[\x00-\x1F\x7F-x9F/\\\\]#', $fichier) ) { echo 'Le nom du fichier comporte des caratères interdits'; } (string)$extension = strrchr($fichier, '.'); if ( ! in_array($extension, $extensions) ) { echo 'Le format de fichier n\'est pas accepté. Seuls le jpeg, le png et le gif sont acceptés.'; }Vérifier la taille du fichier uploadé.
$taille_max = 10000; $taille_fichier = filesize($_FILES['fichier']['tmp_name']); if ( $taille_fichier > $taille_max ) { echo 'Le fichier est trop gros, envoi impossible, la taille maximale est de 10Mo.'; }
Certains des programmes décrits plus haut permettent l'envoi de courriel en cas d'erreur critique ou par simple avertissement régulier.
Pour donner la possibilité de sortir du local, éditer le fichier /etc/postfix/main.cf et si votre FAI est Orange :
relayhost = smtp.orange.frRedémarrer postfix :
root@serveur # service postfix restartMaintenant vous avez toutes les billes pour sécuriser votre système, surtout au niveau du serveur apache.
- coloration syntaxique pour le code PHP - amélioration des codes PHP
- MàJ de la documentation pour être en phase avec la version stable actuelle (Debian Squeeze) - ajout de la section "Contre-mesures DDOS" - suppression de la partie "Avant / Après"
- revue complète du système de gestion des pages (suite et fin) - ajout d'un lien vers une version plus "sobre", sans CSS
- revue complète du système de gestion des pages - correction de quelques commandes pour les sections rkhunter, Webmin et Inclusion - section Fichiers "perdus" étoffée
- section Les fichiers "perdus" ajoutée
- section Snort complétée
- section Peaufiner Apache complétée - ajout de la section ddclient - MAJ des sources
- section Syslog-NG complétée - section PHP complétée - section Peaufiner Apache complétée - information importante ajoutée à mod-security2
- section PHP complétée - MAJ des sources - modification de quelques propriétés CSS
- Envoi de fichiers en plus détaillé - Inclusions en plus détaillé
- rkhunter en version détaillée - snort couplé à ACIDbase - Webmin - une ptite partie Avant/Après juste histoire de dire qu'on n'a pas fait tout ça pour rien - MAJ des sources - possibilité d'avoir un affichage sur un ou plusieurs pages, pratique si vous voulez copier le tuto
- version initiale (avec une Debian Lenny)
Contenu modifié le 01/10/2013.
moc.liamg@gitobob -
Philosophie.