Sécuriser son blog WordPress #2

Date: 4/01/2011 | Catégories: Blog,Open-source,Planet-libre,Reseau,Systeme | Tags: ,,,,,

Dans ce deuxième billet, nous allons aborder la pierre angulaire de la sécurisation de votre site/blog: la sécurisation du couple infernal Apache/PHP.

Bien qu'il existe d'autres serveurs Web (par exemple le très rapide NGinx ou le très simple Cherokee), Apache reste, à ce jour, le plus répandu. Un des reproche que l'on peut lui faire est sa lourdeur de configuration. Cette lourdeur et l'utilisation de fonctions pas forcement utiles à votre site peut rapidement entraîner des failles de sécurité. Nous allons donc détailler la sécurisation du serveur Web ainsi que celle du moteur de langage PHP qui est utilisé par WordPress.

Je vous rappelle que cet article est découpé en plusieurs billets (vous êtes en train de lire le #2):

Cette série de billets a été co-écrite avec Jérémie Marguerie étudiant à EPITA (merci à lui !).

Serveur Web Apache

Sécuriser l'installation par défaut d'Apache2

Apache est développé en tenant compte de la sécurité mais dévoile, dans le header HTTP, son identité (son nom et son numéro de version) à chaque client qui se connecte. Ne pas divulguer ces informations permet d’éviter aux scripts kiddies de connaitre directement les failles connues pour la version d’Apache utilisée et peut compliquer le travail des crackers.

Pour cacher ces informations aux clients HTTP, il suffit d'éditer le fichier /etc/apache2/conf.d/security et d'y ajouter/modifier les variables suivantes:

ServerTokens Prod
ServerSignature Off
TraceEnable On

Module de securité IDS pour Apache

Il existe dans Apache un module optionnel nommé ModSecurity2 qui permet de détecter et de protéger son serveur contre des attaques touchant vos applications Web (notamment les "SQL injections", "cross-site scripting", "path traversal attacks"...).

On commence par l'installation de mod-secure:

sudo aptitude install libapache2-mod-security2

Par défaut, aucune règle n'est appliquée. Il faut donc partir du fichier de configuration qui est donné en exemple:

sudo cp /usr/share/doc/mod-security-common/examples/modsecurity.conf-minimal /etc/apache2/conf.d/mod-security.conf

On édite ensuite le fichier /etc/apache2/conf.d/mod-security.conf:

# Basic configuration options
SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess Off

# Handling of file uploads
# TODO Choose a folder private to Apache.
SecUploadDir /tmp/
SecUploadKeepFiles Off

# Debug log
SecDebugLog /var/log/apache2/modsec_debug.log
SecDebugLogLevel 0

# Serial audit log
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus ^5
SecAuditLogParts ABIFHZ
SecAuditLogType Serial
SecAuditLog /var/log/apache2/modsec_audit.log

# Maximum request body size we will
# accept for buffering
#SecRequestBodyLimit 131072
SecRequestBodyLimit 8192000

# Store up to 128 KB in memory
SecRequestBodyInMemoryLimit 131072

# Buffer response bodies of up to
# 512 KB in length
SecResponseBodyLimit 524288

# Verify that we've correctly processed the request body.
# As a rule of thumb, when failing to process a request body
# you should reject the request (when deployed in blocking mode)
# or log a high-severity alert (when deployed in detection-only mode).
SecRule REQBODY_PROCESSOR_ERROR "!@eq 0" \
"phase:2,t:none,log,deny,msg:'Failed to parse request body.',severity:2"

# By default be strict with what we accept in the multipart/form-data
# request body. If the rule below proves to be too strict for your
# environment consider changing it to detection-only. You are encouraged
# _not_ to remove it altogether.
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
"phase:2,t:none,log,deny,msg:'Multipart request body \
failed strict validation: \
PE %{REQBODY_PROCESSOR_ERROR}, \
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
DB %{MULTIPART_DATA_BEFORE}, \
DA %{MULTIPART_DATA_AFTER}, \
HF %{MULTIPART_HEADER_FOLDING}, \
LF %{MULTIPART_LF_LINE}, \
SM %{MULTIPART_SEMICOLON_MISSING}, \
IQ %{MULTIPART_INVALID_QUOTING}'"

# Did we see anything that might be a boundary?
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
"phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"

On relance ensuite Apache pour prendre en compte le plugin:

sudo /etc/init.d/apache2 restart

Ce module contient un ensemble d’expressions rationnelles dont l'objectif est de bloquer les requêtes jugées dangereuses. Il bloquera une partie des tentatives de piratage. C’est  tout de même une barrière de protection faillible mais qui peut empêcher l’exploitation de certaines failles. Dans tout les cas, cela n’empêche pas le développeur de coder correctement, en prenant en compte la sécurité au moment du développement des sites.

Module anti DOS

Nous allons installer le module Apache mod_evasive qui permet d’atténuer les attaques DOS faite en utilisant le protocole HTTP en bloquant les adresses IP des clients trop gourmand, c’est à dire ceux qui demandent trop rapidement des pages webs.

Contrairement à ce que l’on peut lire sur certains sites, ce module ne protège pas des DDOS, seulement des DOS (lire ici une explication des attaques DOS et DDOS). Autrement dit, il bloque les reqêtes venant d’une adresse IP (DOS).

Si un très grand nombre d’IPs font une seule requête : votre serveur sera saturé et le mod_evasive n’aura pas servi (DDOS). Bloquer les DDOS est très difficile car les requêtes sont difficilement reconnaissables des requêtes autorisées.

On commence par installer le module:

sudo aptitude install libapache2-mod-evasive

On édite le fichier /etc/apache2/conf.d/mod-evasive:

<IfModule mod_evasive20.c>
DOSHashTableSize 3097
DOSPageCount 2
DOSSiteCount 50
DOSPageInterval 1
DOSSiteInterval 1
DOSBlockingPeriod 10
</IfModule>

C'est la configuration par défaut qui va bloquer pendant 10 secondes (DOSBlockingPeriod) les requêtes HTTP venant de l'adresse IP source si une des assertions suivantes est vérifiée:

  • il y a plus de 2 requêtes (DOSPageCount) sur la même page dans un intervalle de 1 seconde (DOSPageInterval)
  • il y a plus de 50 requêtes (DOSSiteCount) sur l'ensemble du site dans un intervalle de 1 seconde (DOSSiteInterval)

On relance ensuite Apache pour prendre en compte le plugin:

sudo /etc/init.d/apache2 restart

Sécurisation du moteur PHP

PHP est un langage interprété, largement utilisé pour générer dynamiquement des pages HTML. C’est le langage utilisé par le moteur de CMS WordPress. La génération des pages de votre blog se faisant directement sur votre serveur, il est important de protéger l’environnement d’exécution des scripts PHP.

Il est donc conseillé d’utiliser suphp. Il est relativement facile à installer et permet d’exécuter vos scripts PHP sous un utilisateur autre que www-data et donc protéger votre système.

Cela permet aussi de servir plusieurs sites internet sur un même serveur. Si un pirate atteint un site, il ne pourra pas toucher aux autres.

Ce module fournit aussi la possibilité de disposer d’un fichier PHP.ini par site web, et offre donc plus de flexibilité que l’installation standard de PHP.

La sécurité a néanmoins un coup: la performance. Attendez vous à des pertes de performances sur vos applications. Dans le cas d’une application codée correctement et d’un serveur non surchargé, cette perte devrait cependant être minime.

Il est également possible de désactiver certaines fonctions sensible de PHP (system, exec...) en éditant le fichier php.ini (voir exemple dans l'étape n°3 de ce billet).

Pour installer  suPhp sur votre serveur je vous conseille la lecture de cet article. (si vous voulez/devez faire cohabiter deux versions de PHP, par exemple la 4 et la 5, vous pouvez également consulter ce billet).

Conclusion (temporaire)

On dispose donc maintenant d'un système et d'un serveur Web sécurisé. Il ne reste plus qu'à attendre la suite de cette série de billets pour s'attaquer à la sécurisation du moteur de blogging WordPress.