Table des matières
Durcissement de configuration PHP
Comme la grande majorité des logiciels, PHP est installé dans une configuration par défaut, qui est un compromis entre l'utilisabilité, la rétrocompatibilité et la sécurité. Pour un environnement de développement, cette configuration par défaut permet de faire fonctionner des applications (souvent Apache + module PHP) immédiatement sans agir sur sa configurationet aux développeurs de l'utiliser en ayant quelques infos de débogage.
Quelques points de vigilance sont à prendre enconsidération pour préparer son module PHP en production.
Fichier de configuration /etc/php/7.0/apache2/php.ini (Debian) ou /etc/php.ini (RH)
expose_php = Off display_errors = Off display_startup_errors = Off log_errors = On error_log = "/path/to/file" ; facultatif si les logs Apache suffisent session.use_only_cookies = 1 session.cookie_httponly = On session.cookie_secure = On session.use_strict_mode = 1 session.hash_function = 1 session.entropy_length = 128 allow_url_fopen = Off allow_url_include = Off disable_functions = system, exec, shell_exec, passthru, phpinfo, show_source, popen, proc_open disable_functions = fopen_with_path, dbmopen, dbase_open, putenv, move_uploaded_file disable_functions = chdir, mkdir, rmdir, chmod, rename disable_functions = filepro, filepro_rowcount, filepro_retrieve, posix_mkfifo variables_order = "GPCS" file_uploads = Off ;sauf si telechargement autorisés upload_max_filesize = xM open_basedir = "/path" ; chemin limite autorisé pour l'ouverture de fichier par PHP
Explications de chaque directive ci-dessous.
Supprimer l'entête de réponse PHP
L'entête HTTP X-Powered-By indiquant la version de PHP exécutée côté serveur est retournée par défaut. Cette information aide l'attaquant à collecter des informations techniques sur sa cible et peut lui permettre de déduire si les composants sont à jour ou ont des vulnérabilités connues. Pour supprimer cette entête via la configuration PHP :
expose_php = Off
Supprimer l'affichage des erreurs
Les messages d'erreurs retournés dans la réponse HTTP permettent à un attaquant de découvrir plus facilement des vulnérabilités. Par exemple, si lors de l'affichage d'une page (généralement en altérant un des paramètres), une erreur relative à l'exécution SQL est retournée, cela signifie que l'URL est vulnérable à une injection SQL.
Exemple d'affichage d'une erreur
MySQL sur un site PHP : Query SELECT name_tissue_type FROM perox, peroxtissue_type, tissue_type WHERE id= AND id=id_peroxtissue_type AND id_tissue_typeperoxtissue_type=id_tissue_type ORDER BY name_tissue_type error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AND id=id_peroxtissue_type AND id_tissue_typeperoxtissue_type=i' at line 6
L'affichage des erreurs peut aussi permettre de détecter des vulnérabilités de type inclusion de fichiers. D'une façon générale, y compris pour le confort de l'utilisateur, les messages d'erreurs techniques détaillés ne devraient jamais être exposés. Pour cela, il est nécessaire d'inclure ces 2 paramètres dans la configuration PHP :
display_errors = Off display_startup_errors = Off
Journaliser les erreurs
Les journaux sont essentiels pour diagnostiquer les erreurs mais peuvent aussi aider à analyser un incident de sécurité. C'est pourquoi, il est important de s'assurer que PHP journalise ses erreurs avec la directive log_errors = On (par défaut, elles ne le sont pas). Dans le cas d'exécution de PHP dans le module Apache, les erreurs seront écrites dans le fichier des erreurs Apache. Il est néanmoins possible également d'isoler les erreurs PHP dans un fichier dédié, ce qui permet également de journaliser les erreurs dans le cas d'exécution de scripts PHP en CLI hors module Apache.
log_errors = On error_log = "/path/to/file" ; Facultatif si les journaux Apache sont suffisant
Plus d'infos sur les logs en PHP : https://www.loggly.com/ultimate-guide/php-logging-basics/
Sécuriser les cookies
La sécurisation des cookies nécessite plusieurs modifications. Tout d'abord, la directive session.use_only_cookies = 1, spécifie que les identifiants de sessions ne peuvent transiter que par cookies, ce qui interdira le passage par URL (ex. : www.example.com/index.php?PHPSESSID=a43d678cb12adf08eb6). La directive session.cookie_httponly = On interdit la lecture du cookie depuis Javascript (objet document.cookie). Cette mesure prévient tout particulièrement des techniques de vol de session via XSS. La directive session.cookie_secure = On interdit le passage du cookie hors HTTPS. Cette mesure prévient d'un éventuel défaut de configuration du site et des attaques visant à voler les sessions après abaissement des requêtes de HTTPS à HTTP. La directive session.use_strict_mode = 1 permet de se prémunir contre les attaques par fixation de session. Le module Apache créera systématiquement un nouvel identifiant de session lors de la visite d'un utilisateur, il refusera tout identifiant envoyé par le navigateur. La directive session.cookie_lifetime = 7200 indique la durée de vie par défaut de la session. La valeur 7200 indique qu'après 2h d'inactivité (à adapter au contexte de l'application) la session sera détruite. La valeur par défaut 0 indique une session dépendante du redémarrage du navigateur. Enfin les directives session.hash_function = 1 et session.entropy_length = 128 indiquent à PHP d'utiliser des identifiants de session en SHA1 et l'entropie nécessaire pour les générer.
Note : la valeur par défaut est de 32 bits, l'OWASP recommande 64 bits, l'ANSSI recommande 128 bits.
session.use_only_cookies = 1 session.cookie_httponly = On session.cookie_secure = On session.use_strict_mode = 1 session.hash_function = 1 session.entropy_length = 128 session.cookie_lifetime = 7200
Désactiver l'inclusion de fichier distant
Les fonctions fopen et include permettent de lire ou d'inclure du contenu distant depuis le code PHP. L'inclusion de fichier distant mal utilisée peut autoriser un attaquant à charger un code arbitraire et prendre le contrôle du serveur. C'est pourquoi il est recommandé d'interdire l'inclusion de fichiers distants avec la directive allow_url_include = Off. En complément, si le site hébergé n'a pas besoin de récupérer du contenu tiers (appels de Web Services, API), il est possible d'interdire le chargement de contenu distant avec la directive allow_url_fopen = Off.
allow_url_fopen = Off allow_url_include = Off
Désactiver les fonctions vulnérables ou dangereuses
La configuration de PHP permet d'interdire l'usage de certaines fonctions. Cela peut permettre de réduire les possibilités d'un attaquant qui serait parvenu à obtenir une possibilité d'exécution de code en complexifiant la suite de son attaque. Typiquement, les fonctions permettant l'exécution de commandes systèmes (shell, shell_exec,…), si elle ne sont pas nécessaires pour l'application hébergée, peuvent être interdites. Aussi, les fonctions de bas niveau de PHP ou encore toute fonction contenant des vulnérabilités connues peuvent être désactivées. Cela se fait par la directive disable_functions. Il reste nécessaire de s'assurer de ne pas désactiver une fonction indispensable au fonctionnement de l'application hébergée. En cas d'effet de bord, privilégiez la désactivation des fonctions system, exec, shell_exec, passthru prioritairement.
; Liste extraite du guide OWASP disable_functions = system, exec, shell_exec, passthru, phpinfo, show_source, popen, proc_open disable_functions = fopen_with_path, dbmopen, dbase_open, putenv, move_uploaded_file disable_functions = chdir, mkdir, rmdir, chmod, rename disable_functions = filepro, filepro_rowcount, filepro_retrieve, posix_mkfifo
Sécuriser l'upload
Si l'application Web ne nécessite pas de fonctionnalités d'upload, alors il est préférable de la désactiver avec la directive file_uploads = Off. Dans le cas contraire, positionner un répertoire spécifique aux uploads et indiquer une taille limite desfichiers.
file_uploads = Off ;sauf si telechargement autorisés upload_max_filesize = xM
Limiter l'accès de PHP sur le système
Dans le cas où un attaquant aurait découvert une inclusion de fichier local (LFI) ou de traversée de répertoire (DirectoryTraversal), il pourra alors consulter d'autres fichiers sensibles du système (dans /etc par exemple). De la même manière, s'il parvient à faire exécuter un peu de code PHP arbitraire, il cherchera à sortir de l'arborescence du site. La directive open_basedir permet de spécifier un répertoire restreint à l'ouverture de fichier (par exemple /var/www/html). Ainsi, l'attaquant ne pourra pas utiliser PHP pour aller chercher d'autres fichiers à l'extérieur de ce répertoire. Il faut rester vigilantaux effets de bords. Classiquement, certains CMS ou applications Web vont stocker ou gérer les téléchargements dans /tmp. S'il n'est pas possible de modifier ce chemin dans le paramétrage du CMS, l'utilisation d'open_basedir va vraisemblablement impacter les fonctionnalités.
open_basedir = /path/
Plus d'infos
Les recommandations listées ci-dessus constituent un niveau minimal de durcissement de configuration. La configuration peut être différenciée entre la configuration PHP du module Apache et la configuration PHP en CLI. D'autres mesures telles que des spécifications plus fortes des chemins et domaines des cookies, l'affinage des logs pourraientêtre évoquées mais nécessite de s'intéresser aux spécificités des sites hébergés. Vous pouvez consulter la Cheat Sheet de l'OWASP sur PHP ou rechercher “Hardening PHP Configuration” dans un moteurde recherche.