La sécurité PHP pour les tout petits 1. Préambule Ce ...

flippantmewlingSecurity

Jun 19, 2012 (4 years and 10 months ago)

431 views

La sécurité PHP pour les tout petits
1.
Préambule
Ce document est un livre de recettes pour protéger une architecture LAMP (Linux, Apache, MySQL,

PHP), mais elle peut aussi aider, pour peu qu'on l'adapte correctement, à protéger toute architecture Web. La

démarche ne garantit absolument pas l'inviolabilité, le 100% ne faisant pas partie de ce monde, mais va rendre la

tâche du pirate plus compliquée, et plus longue.
1.1.
Pré-requis
Nous supposerons que PHP est installé en tant que module dans Apache. Le cas de PHP utilisé comme

CGI ne devrait recouvrir que le cas des particuliers chez leur FAI favori. Nous supposerons aussi que le lecteur

est au moins habitué à la programmation, même sans être un expert. Nous supposerons enfin que les

développeurs web ne sont pas hostiles, tout au plus inconscients.
1.2.
But des scripts
Les scripts, PHP par exemple, ont pour but d’interagir avec l’utilisateur, ce qui signifie que celui-ci doit

envoyer, d’une manière ou d’une autre, des données qui seront utilisées par le programme. Ces données seront,

après transformation, stockées par le programme, soit dans des fichiers, soit dans des bases de données, MySQL

par exemple, pour être ensuite renvoyées d'une manière ou d'une autre à un utilisateur. La difficulté va donc

porter sur la protection de l'ensemble de cette chaine en évitant ou limitant les attaques informatiques.
Version du
vendredi 28 novembre 2008
Fabrice Prigent
1
/
15
2.
Linux
Plusieurs choses peuvent être faites au niveau du Linux pour renforcer la sécurité. Parmi les plus

simples, mettre en place le pare-feu pour interdire les connexions extérieures sur autre chose que les ports

spécifiquement ouverts:
iptables –A INPUT –m state –-state RELATED,ESTABLISHED –j ACCEPT
iptables –A INPUT –i lo –j ACCEPT
iptables –A INPUT –p tcp –-dport 80 –j ACCEPT
iptables –A INPUT –p tcp –-dport 443 –j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables –A INPUT –j LOG
iptables –A INPUT –j DROP
Reste ensuite à interdire aux processus apache et MySQL à sortir de la machine : qu'auraient-ils donc à

faire à l'extérieur (sauf cas du mod_proxy) ?
iptables –A OUTPUT –o lo –j ACCEPT
iptables –A OUTPUT –m state –-state RELATED,ESTABLISHED –j ACCEPT
iptables –A OUTPUT –d mysql.site.fr –p tcp –-dport 3306 –j ACCEPT # Serveur MySQL distant
iptables –A OUTPUT –d smtp.site.fr –p tcp –-dport 25 –j ACCEPT # Serveur SMTP du site
iptables –A OUTPUT –d dns.site.fr –p udp –-dport 53 –j ACCEPT # Serveur DNS du site
iptables -A OUTPUT -m owner --uid-owner 48 –j LOG # Utilisateur Apache
iptables -A OUTPUT -m owner --uid-owner 27 –j LOG # Utilisateur MySQL
iptables -A OUTPUT -m owner --uid-owner 48 –j DROP # Utilisateur Apache
iptables -A OUTPUT -m owner --uid-owner 27 –j DROP # Utilisateur MySQL
iptables –A OUTPUT –j ACCEPT
Dans les solutions plus ardues, on trouvera tous les processus de durcissement d'OS, au rang desquels

on trouvera SELinux, GrSecurity, Pax.
Dans les solutions générales et assez longues, on se reportera sur les excellents guides de la N.S.A. qui

parle, entre autres, de Linux, Cisco, Windows, etc.
3.
Apache
3.1.
Le logiciel lui-même
Plusieurs méthodes existent pour sécuriser apache. La première idée est de le mettre en chroot. Cela

impose de nombreuses contraintes, difficiles à respecter en production. Heureusement, la NSA pense à nous

grâce à son SELinux qui permet de contraindre un processus, même root, dans un environnement sécurisé. Ceci

est disponible, en particulier dans les RedHat 4.x ou +, Mandrake 10.x ou +, Debian et CentOS 4.x ou +.
3.2.
Le paramétrage
Il est important de vérifier quelques paramètres, et de limiter leur action suivant vos utilisateurs (les

options allowOverride sont là pour cela).
<Directory />
AllowOverride None
</Directory>
Désactivez la signature de l'apache:
ServerSignature Off
ServerTokens Prod
Désactiver le mode trace
TraceEnable off
Pensez aussi à journaliser correctement :
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog logs/access_log combined
Evitez les log DNS qui sont une mauvaise idée, car ils prennent du temps pour une information inutile,

voire dangereuse : l'information DNS peut changer entre le problème et sa détection.
Idem pour les IdentityCheck, hormis cas particulier.
HostnameLookups Off
IdentityCheck off
Version du
vendredi 28 novembre 2008
Fabrice Prigent
2
/
15
Mettez en place les .htaccess et empêchez leur rapatriement.
AccessFileName .htaccess
<Files ~ "^\.ht">
Order allow,deny
Deny from all
</Files>
On peut aussi limiter les requêtes en taille et réduire le timeout.
LimitRequestBody 1048576
LimitXMLRequestBody 10485760
Timeout 45
Refusez les indexations automatiques de répertoires, tous vos fichiers seraient visibles (hormis cas

précis). Cela peut-être fait en créant systématiquement un index.html, mais aussi au niveau du serveur ou des

répertoires grâce à la directive.
Options -Indexes
3.3.
Les VirtualHosts
Pensez à faire des journaux individuels pour chaque virtualhost, ainsi qu'un fichier de configuration par

virtualhost (le répertoire
conf.d
est fait pour cela). Choisissez bien leur nom, surtout si vous souhaitez utiliser les

certificats qui vont se baser sur ce nom.
Créer un serveur par défaut, sans la moindre information.
3.4.
L'arborescence
3.4.1.
Fichiers à rendre inaccessibles
Prévoyez une routine d'effacement de vos fichiers temporaires ou de sauvegarde (*.bak, *.old, *.$$$,

*.tmp, ficher~ ou *.2), éventuellement, vous pouvez aussi les rendre illisibles par le daemon apache.
chown root:root *.bak
chmod 400 *.bak
3.4.2.
Répertoires et fichiers
Il faut aussi faire sortir de l'arborescence, tant que faire se peut, les fichiers qui n'ont pas vocation à être

directement visibles. En particulier tout ce qui concerne les include et les fichiers de données.
3.4.3.
Le fichier robots.txt
Le fichier /robots.txt doit contenir l'ensemble des répertoires à ne pas laisser explorer par des robots tels

GOOGLEBOT ou autre. Cela pourrait effectivement donner beaucoup trop d'informations aux pirates, en

particulier doivent être exclus : les répertoires de statistiques, les répertoires privés, plus tout répertoire "piégé"

que vous pourriez créer. Exemple d'un tel fichier
:
User-agent: *
# Répertoires standard
Disallow: /cgi-bin
# Quelques fichiers
Disallow: admin.php
Disallow: test.php
# Statistiques
Disallow: /usage/
Disallow: /mrtg/
Disallow: /webalizer/
Disallow: /private/mrtg/
# Répertoires prives
Disallow: /install_redhat/
Disallow: /noaccess/
Rappel : une règle est faite pour être contournée, et les pirates ne s'en priveront pas, le robots.txt n'ayant

qu'une vocation d'indication.
Ce fichier peut être validé grâce à cet outil
http://www.searchengineworld.com/cgi-bin/robotcheck.cgi
.
Version du
vendredi 28 novembre 2008
Fabrice Prigent
3
/
15
Attention, seul gooblebot à l'heure actuelle est capable de prendre en compte des ordres du type
Disallow: *.cgi
3.4.4.
Les journaux sont vos amis
Il est important de suivre la vie de vos journaux, et de collecter le plus d'information possible sur votre

serveur. Journaliser, c'est bien, mais il est aussi souhaitable de repérer les anomalies.
On regardera donc avec attention (ou plutôt, on fera regarder par un programme) les tentatives étranges,

répétitives. Un bon analyseur de journaux peut souvent (s'il n'est pas lui-même piratable) donner un bon aperçu

de choses "étonnantes". On regardera du côté de webstats, awstats ou autres.
3.5.
Les modules de sécurité
Afin de renforcer la sécurité d'apache, plusieurs modules ont été développés. On trouvera aussi des

routines intéressantes en PHP.
3.5.1.
Mod_chroot
Mod_chroot qui se trouve sur
http://core.segfault.pl/~hobbit/mod_chroot/
permet de mettre Apache dans

un chroot, sans avoir à copier les innombrables fichiers nécessaires à son fonctionnement. Rapide et efficace, il

n'atteint pas, malgré tout, la précision d'une installation manuelle. De plus, il sera nécessaire de garder à l'esprit

que tous les programmes lancés par apache seront cantonnés au répertoire chrooté.
SecChrootDir /chroot/apache
3.5.2.
Mod_security
Mod_security se trouve sur
http://www.modsecurity.org
. Il permet de normaliser les urls avant l'envoi

aux divers modules, et surtout de repérer les chaînes de caractères, ou plutôt les expressions régulières

dangereuses dans les variables envoyées, ainsi que repérer, dans les pages de retour, les informations qui sont

signes d'une attaque réussie. Il est de plus capable de chrooter apache de la même manière que mod_chroot.
Son emploi est plus adapté à un Apache 2.x.
yum install httpd-devel
#
Installation des libraires de développements apache
cd /usr/local/src
wget http://www.modsecurity.org/download/mod_security-2.5.7.tar.gz
tar zxvf mod_security-2.5.7.tar.gz
cd mod_security-2.5.7/apache2
apxs -cia mod_security.c
Puis configuration pour une instance donnée
#
#
# Définition du comportement mod_security
#
SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess On
SecResponseBodyMimeType (null) text/html text/plain text/xml
SecResponseBodyLimit 4194304
SecDefaultAction

"phase:2,log,deny,status:501,t:lowercase,t:replaceNulls,t:compressWhitespace"
SecServerSignature "IIS 5.9 (Fedora 19.0.0)"
SecAuditEngine RelevantOnly
SecAuditLog logs/audit_notes_log # attention au nom du log
SecFilterDebugLevel 0
SecFilterDebugLog logs/modsec_debug_notes_log # attention au nom du log
SecFilterDefaultAction "deny,log,status:500"
#
# Passage en chroot
#
SecChrootDir /chroot/apache
#
Version du
vendredi 28 novembre 2008
Fabrice Prigent
4
/
15
# Définition des chaines interdites
#
# Command execution attacks
SecRule REQUEST_URI /etc/passwd
SecRule REQUEST_URI /etc/shadow
SecRule REQUEST_URI /bin/ls
# Directory traversal attacks
# SecFilter "\.\./" # C'est un peu excessif comme solution
# XSS attacks
SecRule REQUEST_URI "<(.|\n)+>"
SecRule REQUEST_URI "<[[:space:]]*script"
# SQL injection attacks
SecRule REQUEST_URI "delete[[:space:]]+from"
SecRule REQUEST_URI "insert[[:space:]]+into"
SecRule REQUEST_URI "select.+from"
# MS SQL specific SQL injection attacks
SecRule REQUEST_URI xp_enumdsn
SecRule REQUEST_URI xp_filelist
SecRule REQUEST_URI xp_availablemedia
SecRule REQUEST_URI xp_cmdshell
SecRule REQUEST_URI xp_regread
SecRule REQUEST_URI xp_regwrite
SecRule REQUEST_URI xp_regdeletekey
# Attaques systeme
SecRule REQUEST_URI "[^a-zA-Z]system\("
SecRule REQUEST_URI "[^a-zA-Z]chr\("
#
Attaques référencées : phpBB avec un chainage des détections.
SecRule SCRIPT_FILENAME "viewtopic\.php$" chain
SecRule ARG_highlight "%27"
SecRule REQUEST_FILENAME "export\.php$" chain
SecRule ARG_what "\.\."
#
# Repérage de chaines spécifiques dans le retour de la part du serveur
#
SecRule RESPONSE_BODY "Volume Serial Number"
SecRule RESPONSE_BODY "Command completed"
SecRule RESPONSE_BODY "Bad command or filename"
SecRule RESPONSE_BODY "file(s) copied"
SecRule RESPONSE_BODY "Index of /cgi-bin/"
SecRule RESPONSE_BODY ".*uid\=\("
SecRule RESPONSE_BODY "http://jakarta.apache.org/"
On pourra trouver sur le site
http://www.modsecurity.org/projects/rules/index.html
des règles de

filtrage, qui seront, bien évidemment, à adapter : on ne sécurise pas une application simple comme le logiciel

phpmyadmin.
3.5.3.
Mod_profiler
Pendant de mod_security (il travaille en combinaison avec lui), il permet d'apprendre ce qui est normal

pour ensuite empêcher ce qui ne l'est pas. Il est encore en phase bêta, mais l'approche est prometteuse.
3.5.4.
Suhosin
Ceci est un module pour PHP, qui va en combler les trous les plus flagrants. Il se compose de deux

parties indépendantes : un patch et une extension. On peut le trouver sur
http://www.hardened-
php.net/suhosin.127.html
.
Le patch va nécessiter de recompiler php (et tous ses modules). L'extension, quant à elle, peut s'utiliser

seule sans modification. Mais elle ne donne sa pleine puissance qu'avec le patch.
Version du
vendredi 28 novembre 2008
Fabrice Prigent
5
/
15
3.5.5.
Mod_evasive
Ce module, disponible sur
http://www.nuclearelephant.com/projects/mod_evasive/
, permet de mettre en

liste noire des machines qui tentent de saturer un serveur web, par des requêtes trop rapides. Voici un exemple de

configuration pour apache 2.x. A mettre dans le httpd.conf. Une option supplémentaire permet aussi de lancer

une commande système.
<IfModule mod_evasive20.c>

DOSHashTableSize 3097
DOSPageCount 2
DOSSiteCount 50
DOSPageInterval 1

DOSSiteInterval 1
DOSBlockingPeriod 10
DOSEmailNotify
webmaster@site.fr
DOSLogDir
"/var/lock/mod_evasive"
DOSWhitelist
127.0.0.1
DOSWhitelist
193.49.*.*
</IfModule>
3.6.
La sécurisation par chiffrement
Saint Graal de la sécurité il y a quelques années, on s'aperçoit que le chiffrement n'est pas plus sûr que

les entrées du "tunnel" qu'il crée. Il s'agit toutefois d'un pré requis pour permettre de faire transiter des données

sans risquer l'observation et l'interception des communications.
3.6.1.
L'installation du chiffrement
En apache, le chiffrement se fait de manière relativement simple : l'écoute se fera sur le port dédié 443.

Le reste dépendra des certificats obtenus, plus quelques options si l'on souhaite récupérer des variables dans les

certificats (le nom de l'utilisateur en particulier). Nous ne nous attarderons pas ici sur la génération des

certificats, qui relèverait d'un chapitre complet.
<VirtualHost webmail.site.fr:443>

ServerAdmin reseau@site.fr
DocumentRoot /var/www/html_webmail/

ServerName webmail.site.fr
SSLEngine on
SSLCertificateFile /etc/httpd/conf/ssl.crt/webmail.site.fr.crt
SSLCertificateKeyFile /etc/httpd/conf/ssl.key/webmail.site.fr.key

SSLCertificateChainFile /etc/httpd/conf/ssl.crt/cachain.txt
<Files ~ "\.(cgi|shtml|phtml|php3?)$">
SSLOptions +StdEnvVars
</Files>
ErrorDocument 402 https://webmail.site.fr/

<Directory "/var/www/cgi-bin">
SSLOptions +StdEnvVars
</Directory>
ErrorLog logs/error_webmail_log
CustomLog logs/access_webmail_log combined
</VirtualHost>
3.6.2.
Les contournements du chiffrement
Ils sont nombreux, malgré les apparences, et sont généralement liés à l'utilisateur qui fait trop confiance,

ou trop peu attention à ce qu'il voit.
3.6.2.1.
Problème du domaine "valide" à l'orthographe similaire
Un pirate peut acheter un certificat auprès d'une société (Verisign par exemple) pour le domaine

bnppariba.com. L'utilisateur recevra un certificat, valide, qu'il acceptera.
3.6.2.2.
L'attaque Man in the Middle
Un pirate peut, en se plaçant de manière réelle ou virtuelle entre la victime et le site sécurisé, intercepter

les communications. Il va présenter un pseudo certificat à l'utilisateur, qui va l'accepter. Le pirate va

Version du
vendredi 28 novembre 2008
Fabrice Prigent
6
/
15
retransmettre les données de la session au vrai site en les chiffrant réellement, mais tout sera visible pour lui. De

nombreux outils permettent de faire cela de manière très simple.
3.7.
Les processus d'authentification
Il faut regarder avec attention les processus d'authentification, qui ne doivent en aucun cas être une

source supplémentaire d'intrusion. Il est par exemple très dangereux de faire circuler les mots de passe en clair

sur le réseau, ce qui implique le chiffrement des échanges d'authentification. Mais cela ne suffit pas : si la

personne croit parler au serveur d'authentification, alors qu'il s'agit d'un pirate (notion de «

rogue

» tel que les

rogue AP en WiFi), il faut absolument que la personne le sache, et qu'elle n'ait pas pris l'habitude d'accepter

n'importe quel certificat ! Ce qui signifie utiliser une VRAIE notion de certificat et donc d'IGC (Infrastructure de

Gestion de Clés), aussi appelée PKI (Public Key Infrastructure).
3.7.1.
Le cookie d'authentification
Après une authentification, plus ou moins sérieuse, l'idée est souvent de stocker l'authentification dans

un cookie et de l'utiliser dans des applications non chiffrées. Le but pour le pirate consiste alors à récupérer le

cookie d'authentification pour le rejouer immédiatement. C'est une action tout à faire faisable grâce aux attaques

dites XSS (Cross Site Scripting).
A minima, il faudra, pour limiter les conséquences de ce vol, stocker dans le cookie, ou dans les

variables de sessions dont il dépend, l'IP d'origine de la session, puis de refuser les connexions qui viennent

d'une autre IP. Cela se passera certainement moins bien si la victime et l'attaquant ont la même adresse IP

extérieure (NAT, proxy-cache, etc.), ou si l'IP est "changeante" (voir le protocole dhcp).
3.7.2.
Le SSO
Acronyme de Single Sign On, il décrit un mécanisme d'authentification unique permettant à l'utilisateur

de ne rentrer qu'une seule fois son mot de passe pour plusieurs applications (souvent web). Cela recouvre

plusieurs techniques basées quasiment toutes sur un serveur d'authentification.
Dans un cas le serveur connait tous les mots de passe et les fournit à l'application qui le demande. Ceci

est particulièrement dangereux : l'application va être au courant du login et du mot de passe. Si elle est pirate ou

piratée, ceux-ci vont être diffusés.
Dans le second, le serveur fournit l'identité du client et confirme son authentification à l'application

demandeuse (voir par exemple le projet CAS). L'application ne connait donc pas le mot de passe.
3.7.3.
Les fédérations d'identité
Les fédérations d'identité ont pour but de permettre à un individu, faisant partie d'un organisme A d'être

reconnu par un autre organisme B pour accéder à certains de ses services. B (appelé fournisseur de services),

lorsque l'individu le contacte, va demander à A de confirmer son identité, par exemple grâce à un SSO. B ne

connaîtra ni le login, ni le mot de passe de l'individu, mais, parce qu'il fait confiance à A, lui accordera des

droits. Deux projets sont en lice :
http://shibboleth.internet2.edu
(shibboleth)
http://www.projectliberty.org
(liberty alliance)
3.8.
Les reverse-proxy
3.8.1.
Le mod_proxy
Le mod_proxy va permettre de placer un apache en frontal d'un autre serveur HTTP, de type apache ou

non. Cela va décharger le serveur protégé d'un certain nombre d'actions de sécurité (voir le module

mod_security), et éventuellement du chiffrement des communications.
Le serveur frontal n'ayant qu'un rôle de relais, on va pouvoir lui faire subir une cure d'amaigrissement,

toujours profitable, et lui restreindre ses possibilités de communications. Il deviendra alors moins vulnérable, et

moins capable d'actions néfastes.
Version du
vendredi 28 novembre 2008
Fabrice Prigent
7
/
15
Afin de pouvoir faire du reverse-proxying en toute circonstance, on regardera du coté de mod_ext_filter

pour faire une réécriture des urls, même dans les javascript.
La configuration d'un reverse-proxy pouvant être assez longue, nous laisserons le lecteur faire ses

propres recherches.
3.8.2.
Un reverse-proxy de sécurité : Vulture
Il existe un reverse-proxy de sécurité complet qui existe en GPL : il s'agit de Vulture, disponible sur

http://vulture.open-source.fr. Il combine les fonctionnalités de l'ensemble des outils précédents, puisqu'il les

intègre. Il est aussi capable de faire du SSO.
3.8.3.
Un reverse-proxy SSO : LemonLDAP
Lemonldap est un reverse-proxy qui permet de créer un serveur apte à gérer une authentification unique

pour un ensemble d'applications web. Il est disponible sur
http://LemonLDAP.sourceforge.net
.
4.
Paramétrer PHP
4.1.
Le safe-mode
4.1.1.
But
Le safe-mode est une configuration particulière du module PHP qui permet de limiter les actions

possibles pour le pirate, mais aussi celles du programmeur par la même occasion.
4.1.2.
Activation
On l’active simplement en mettant dans le php.ini la variable safe_mode à on. Suivra ensuite une liste

de variables que l’on positionnera suivant les besoins de restriction

:

safe_mode

safe_mode_gid

safe_mode_include_dir

safe_mode_exec_dir

safe_mode_allowed_env_vars

safe_mode_protected_env_vars
Le fonctionnement par défaut de safe-mode sera le suivant

:

Le script ne peut lire que les fichiers qui appartiennent au propriétaire du processus php (on peut limiter

ce fait grâce à safe_mode_gid) ou ceux qui sont dans les répertoires donnés par safe_mode_include_dir

Le script ne peut exécuter que les commandes qui se trouvent dans safe_mode_exec_dir (attention à bien

les terminer par /)

Un certain nombre de fonctions seront limitées, en général par une vérification du propriétaire, et du

répertoire d’exécution

Un certain nombre de fonctions seront indisponibles (dl, shell_exec,set_limit_time,max_execution_time)

La fonction mail ne peut modifier le 5
ème
paramètre (paramètres additionnels).
Des variables ne seront plus accessibles :

Les variables PHP_AUTH_USER (mais REMOTE_USER, oui) et PHP_AUTH_PW

Les en-tête commençant par AUTHORIZATION
safe_mode on
4.2.
Les autres paramétrages
D’autres variables permettent de limiter encore les droits des scripts PHP.
4.2.1.
open_basedir
Permet de limiter l’ouverture des fichiers à un répertoire donné. Attention à bien le terminer par /. Ceci

est plus ou moins redondant avec le safe_mode.
Version du
vendredi 28 novembre 2008
Fabrice Prigent
8
/
15
4.2.2.
disable_functions
On peut désactiver des fonctions. Est-il indispensable de laisser les commandes system et readfile

actives

?
disable_functions readfile,system
4.2.3.
disable_classes
Idem, mais avec les classes.
4.2.4.
register_globals
Permet d’éviter que des variables «internes

» aux scripts ne soient directement affectées d’une valeur

par l’utilisateur distant. Facilité offerte par PHP à ses début, elle est devenue la principale cause de failles des

scripts PHP pendant une longue période. Désormais, depuis la version 4.2.0, elle est à OFF par défaut. Ce

changement a occasionné le mauvais fonctionnement de plusieurs milliers de scripts dans le monde.
register_globals off
Ce nouveau comportement implique que les variables seront désormais récupérées par les tableaux

$_GET

$_POST

$_COOKIE

$_REQUEST (équivalent aux 3 premiers)

$_FILES

$_SESSION

et $_SERVER
ainsi la variable $login devra être récupérée par
$login=$_GET['login']
4.2.5.
Limiter les informations pour le pirate
On empêche l'affichage d'informations trop précises sur la version de php, les erreurs qui ne doivent pas

s'afficher dans le navigateur mais dans les logs.
expose_php off
display_errors off
error_log syslog
4.2.6.
magic_quotes_gpc
Les variables peuvent être utilisées pour bloquer ou modifier le système. magic_quotes_gpc est un

moyen efficace de protéger le système (particulièrement les accès aux bases de données) d’un comportement

imprévu. Magic_quotes_gpc va ainsi protéger le système des caractères NULL, \, quotes ‘ et guillemet "

.
magic_quotes_gpc on
L'inconvénient de cette méthode est qu'elle alourdit les scripts, et rend toutes les variables sous forme

protégé. Il faut alors, lors de l'affichage, toutes les déprotéger par la fonction
strip_slashes().
On peut ,

parfois, remplacer ce procédé très "dégât collatéral" par une utilisation judicieuse de la fonction

add_slashes().
Il est d'ailleurs fortement question de remettre le magic_quotes_gpc à off dans les futures

versions de PHP.
4.2.7.
Paramètres de limitation divers
Afin de limiter les dégâts d'un déni de service (D.O.S.) on peut mettre des contraintes sur les ressources.

En voici quelques unes :
max_execution_time = 30 ; Temps maximum d'éxecution en secondes
memory_limit = 8M ; taille mémoire maximale par script
4.2.8.
Les modules de protection
Quelques modules d’aide au filtrage des variables ont été développés pour PHP, on pourra se reporter

en particulier à
http://www.phpclasses.org/browse/class/78.html
qui les recense. En voici un.
Version du
vendredi 28 novembre 2008
Fabrice Prigent
9
/
15
4.2.8.1.
INPUTFILTER
C’est un ensemble de classes php, disponible ici,
http://cyberai.com/inputfilter/
et qui permet de filtrer

les URLs et les variables des codes javascript, SQL injection ou autres.
4.2.8.2.
PHP-IDS
Disponible sur
http://php-ids.org
, il permet de détecter des utilisations potentiellement dangereuses en

donnant une valeur d'impact (de dangerosité). L'intégration dans le code source est relativement simple :
set_include_path(
get_include_path()
. PATH_SEPARATOR
. 'chemin/vers/la/bibliotheque/phpids'
);
require_once 'IDS/Init.php';
$request = array('GET' => $_GET, 'POST' => $_POST, 'COOKIE' => $_COOKIE);
$init = IDS_Init::init('IDS/Config/Config.ini');
$ids = new IDS_Monitor($request, $init);
$result = $ids->run();
if (!$result->isEmpty()) {
// On regarde le résultat
echo $result;
}
4.2.9.
La version 6.0 de PHP
Elle va grandement modifier le fonctionnement sécuritaire de PHP. Voici quelques informations

disponibles au moment de la rédaction de ce vade mecum:

Suppression des
register globals

Suppression des
magicquotes

Suppression du
safe_mode

Suppression des super-globales
$HTTP_*_VARS
5.
MySQL
5.1.
Installer MySQL
MySQL peut très facilement se placer en chroot, afin de limiter ses actions en cas d'intrusion :
mkdir -p /chrooted/chrooted-mysqld
cd /chrooted/chrooted-mysqld/
mkdir -p var/lib var/run lib etc tmp
grep "mysql:" /etc/passwd >etc/passwd
chmod 1777 tmp
cp -rp /var/lib/mysql var/lib/
cp -rp /var/run/mysqld var/run
ldd /usr/libexec/mysqld
#Créer les répertoires repérés
#copier les fichiers repérés dans les répertoires
mkdir -p lib/i686 usr/lib
cp -rp /lib/…..
cp -rp /lib/libnss* lib/
# ajouter dans /etc/my.cnf
chroot=/chrooted/chrooted-mysqld
5.2.
Configurer MySQL
MySQL est le support de beaucoup d'applications web. Les questions qui se posent :
Le MySQL doit-il être accessible hors de la machine qui l'héberge ? Non à 90%, donc on n'attache le

processus qu'à l'interface localhost, ou, au pire, on utilise les iptables, ou tout autre procédé de pare-feu local

pour limiter l'accès aux seules machines autorisées.
Version du
vendredi 28 novembre 2008
Fabrice Prigent
10
/
15
Est-il normal que l'accès administrateur se fasse sans mot de passe ou avec un mot de passe par défaut ?

Mettez en un nouveau. On peut utiliser pour cela la commande mysql_secure_installation, qui vous permettra

d'enlever les bases et les comptes inutiles.
Désactiver les fonctions trop dangereuses en ajoutant dans /etc/my.cnf
set-variable=local-infile=0
5.3.
Utiliser MySQL
Lors de la création de compte MySQL, séparez les comptes suivants les applications. Profitez-en pour

ne donnez que les droits nécessaires, et en les divisant :

un compte d'administration (création des tables),

un compte en écriture

un compte en lecture.
5.4.
Piéger MySQL
Créer des données "honeytokens" afin de faciliter le repérage de vol de données (pour un I.D.S. ou pour

des preuves devant un tribunal). Cela peut-être un compte, un enregistrement, etc.
6.
Programmer en PHP
Une fois que l’on a pris en compte l’environnement de travail, mis en place les protections nécessaires

sur les scripts PHP et autres fichiers de configuration, un grand nombre de choses restent à regarder.
6.1.
Bien programmer
Cela semble évident, mais certains réflexes s’oublient en programmation web. Les principes doivent

être les suivants :

Une variable doit toujours être affectée.

Vérifiez toujours le résultat des actions que vous effectuez

La connexion à la base s'est-elle bien passée ?

Y a-t-il un résultat dans votre requête ?

La valeur est-elle définie ?
6.2.
Contrôler les variables
La grande majorité des failles actuelles proviennent des variables qui nous sont fournies par

l’utilisateur. Nous avons déjà, grâce à
register_globals
, limiter le problème aux vraies variables qu’est

sensé nous envoyer l’utilisateur. Mais cela ne suffit pas. Le contenu des variables peut être dangereux. Voici

quelques méthodes pour vérifier les variables.

Utilisez le moins possible les variables directement.

Si une variable $variable est sensée être numérique, confirmez le :
$variable=intval($variable);

Si une variable ne doit pas dépasser une certaine taille, en minuscule, confirmez le :
$login = preg_replace(".*([a-z]{3,8}).*", "\$1", $login);

Si une variable est sensée avoir un format particulier, vérifiez le grâce aux expressions régulières :
if (preg_match('/^[A-Z0-9._%-]+@[A-Z0-9._%-]+\.[A-Z]{2,6}$/', $email))
{suite_du_traitement();}
else
{die "erreur dans la variable email\n";}; // Remarquez que l'on n'utilise pas la

valeur de $email.

Dans le cas de variables énumératives, qui ne peuvent prendre leurs valeurs que dans un intervalle, on

utilise soit les "elseif", soit un tableau intermédiaire :
$valeur=$_GET['valeur'];
if ($tab_valeurs_autorisees[$valeur])
{$valeur=$tab_valeurs_autorisees[$valeur]);}
else
{die "valeur est incorrecte"}

Tente-t-on d'utiliser la variable pour envoyer du javascript ? Il faut enlever les caractères "
<
" et "
>
";
Version du
vendredi 28 novembre 2008
Fabrice Prigent
11
/
15

Vous utilisez une variable qui contient nom de fichier, ou dont on dérive un nom de fichier, répertoire,

ou commande ? Effacez les
..

/

; *
et autre

?


Une base de données est impliquée ? Attention aux séquences dangereuses

--
ou # (qui sont des commentaires)

;
(qui est un séparateur de commande)

l'espace
(très utilisé si vous n'avez pas "quoté" la variable)

les mots clés
SQL
(
UNION
étant le plus prisé).
6.3.
Les pièges à éviter
Doit-on stocker les mots de passe en clair ? A 99% c'est non, car on ne veut que comparer un mot de

passe, pas le lire. Donc, il faut utiliser les commandes de hashage telles que MD5, crypt, et autre SHA1. Donc,

ne stocker que le haché d'un mot de passe dans les bases de données.
Les fichiers de données doivent-ils être dans un répertoire accessible par le web ? à 99% non, donc

déplacez les.
La tentation, si l’on fait des tests de variables est de signaler exactement le problème à l’utilisateur.

Erreur

!

!

! Le programme doit stopper le traitement, proprement, mais sans réutiliser la variable. Un pirate

pourrait utiliser cette protection pour entrer dans le système. Un comble !
6.4.
Contre les XSS : htmlentities()
Pour se protéger des XSS, une idée simple est d'encoder les caractères particulier en leur équivalent

web. Cela empêche leur interprétation par les navigateurs.
6.5.
Contre le SQL-Injection:
mysql_real_escape()
Afin d'éviter l'exécution de champs variable, il peut être utile "d'échapper", c'est à dire rendre

inoffensifs les caractères dangereux pour MySQL. C'est le rôle de cette commande. Une version postgresql

existe.
6.6.
Utilisation des prepare/execute
Pour la même raison, on peut aussi utiliser les commandes paramétrées, qui ont de plus l'avantage

d'accélérer les traitements :
require_once("DB.php");
$db = &DB::connect("mysql://user:pass@host/database1");
$p = $db->prepare("SELECT * FROM users WHERE username = ?");
$db->execute( $p, array($_GET['username']) );
et
$db->query( "SELECT * FROM users WHERE username = ?", array($_GET['username']) );
ou encore, avec l'extension mysqli (php5).
$db = new mysqli("localhost", "user", "pass", "database");
$stmt = $db -> prepare("SELECT priv FROM testUsers WHERE username=? AND password=?");
$stmt -> bind_param("ss", $user, $pass);
$stmt -> execute();
7.
Les expressions régulières
Les expressions régulières sont un formidable moyen de contrôle des données. Elles travaillent sur la

notion de schéma suite de caractères, et non de chiffres ou de mots.
Il existe, pour simplifier, deux types d'expressions régulières : les posix et les expressions perl. Celles-
ci, plus complètes et puissantes sont de plus en plus utilisées. En php on vérifiera la présence d'une chaine grâce

à la fonction
preg_match
. Nous ne voyons ici qu'une toute petite partie des expressions régulières.
7.1.
Les caractères
Un caractère représente généralement son propre caractère a représente la lettre a.
Version du
vendredi 28 novembre 2008
Fabrice Prigent
12
/
15
[a-z]
représente tout caractère entre a et z
[B-E]
représente tout caractère entre B et E
[0-9]
représente tout caractère entre 0 et 9
.
(le point) représente n'importe quel caractère
7.2.
Les opérateurs
Les opérateurs permettent de préciser le nombre de fois où un caractère apparaît ou bien de faire des

opérations de concaténation ou de choix
AB
représente la séquence des caractères A et B
A*
représente n'importe quelle chaine de caractères contenant des A (de 0 à autant que l'on veut)
A+
représente n'importe quelle chaine ayant au moins un A
A?
représente le fait d'avoir zéro ou un A.
A{3}
signifie trois A de suite
A{2,5}
signifie que l'on peut avoir de deux à cinq A.
A|B
signifie que l'on peut avoir A ou B
7.3.
Les autres éléments
^
représente le début de la chaine de caractères
$
représente la fin de la chaine de caractères
( )

les parenthèses permettent d'appliquer un opérateur à un ensemble de caractères.
\

permet de faire perdre à un opérateur ou à un caractère son "caractère" spécial.
\.
représente le

caractère point.
7.4.
Les commutateurs
Certaines options dans la sélection permettent de préciser les traitements lors de la recherche
i
pour ne pas faire de distinction entre majuscule et minuscule
o
pour ne "compiler" la règle de détection qu'une fois (ce qui est plus rapide)
7.5.
Quelques exemples
If preg_match("/Fabrice/",$chaine)
le prénom Fabrice est-il présent dans $chaine (fabrice ne sera par repéré car le f n'est pas majuscule)
If preg_match("/h(ab)*/i",$chaine)
Toute chaine composée de h suivi de 0 à x fois de ab sera repérée. Les lettres pouvant être en minuscule

ou en majuscule.
If preg_match("/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/",$chaine)
Toute chaine de caractère contenant une adresse IP (ou du moins qui y ressemble).
If preg_match("/[0-9]{1,4}((bis)|(ter))?/",$chaine)
Toute chaine qui contient un numéro de rue (avec éventuellement le bis ou le ter)
If preg_match("/^[0-9]{5}$/",$chaine)
La chaine est égale à un code postal (ni plus ni moins).
Version du
vendredi 28 novembre 2008
Fabrice Prigent
13
/
15
8.
Les outils de tests
8.1.
Les tests externes
Ils se comportent comme les pirates en essayant d'obtenir des informations en étant sans droits

particuliers.
8.1.1.
Nmap
Grand classique. Il permet de repérer les ports ouverts, la version du logiciel qui tourne (en se basant sur

les bannières). Il est disponible sur
http://insecure.org
8.1.2.
Wapiti
Scanneur de vulnérabilités inconnues, principalement pour XSS. Il est disponible sur

http://wapiti.sourceforge.net/
.
8.1.3.
Autres outils
NIKTO
http://www.cirt.net/code/nikto.shtml
(vulnérabilités web connues)
Nessus
http://www.nessus.org
(vulnérabilités connues)
Springenwerk
http://www.springenwerk.org
(failles XSS)
sqlmap
http://sqlmap.sourceforge.net/
(SQL injection)
8.2.
Les tests internes
Ce sont les valideurs de code. Ils essaient de repérer dans les codes sources les fonctions et méthodes de

programmation dangereuses.
8.2.1.
PHPsecAudit
Il est disponible sur
http://developer.spikesource.com/projects/phpsecaudit
8.2.2.
Pixy
Auditeur de code PHP en java pour faille SQL et XSS
http://pixybox.seclab.tuwien.ac.at/pixy/
8.2.3.
RATS
http://www.securesoftware.com/resources/download_rats.html
9.
URLographie
Voici quelques URLs sur la bonne protection des scripts en PHP
http://fr2.php.net/features.safe-mode
http://fr2.php.net/manual/fr/security.php
http://phpsec.org/
http://www.phpsecure.info/
http://shiflett.org/php-security.pdf
http://regexlib.com/
http://www.owasp.org/
http://www.securityfocus.com/infocus/1694
Version du
vendredi 28 novembre 2008
Fabrice Prigent
14
/
15
http://dev.mysql.com/doc/mysql/en/Security.html
http://www.securityfocus.com/infocus/1726
http://www.kitebird.com/articles/ins-sec.html
http://www.certa.ssi.gouv.fr/site/CERTA-2007-INF-002.pdf
http://www.certa.ssi.gouv.fr/site/CERTA-2004-INF-001/index.html
http://www.apachesecurity.net/
(horse book de chez O'Reilly)
http://en.wikibooks.org/wiki/Programming:PHP:SQL_Injection
10.
Autres informations
Ce document est largement perfectible. n'hésitez pas à me signaler les erreurs et les améliorations à

l'adresse fabrice.prigent@laposte.net.
Il est disponible sous licence creative commons
http://creativecommons.org/licenses/by-nc-sa/2.0/fr/
Version du
vendredi 28 novembre 2008
Fabrice Prigent
15
/
15