70 votes

L'option PHP 'cgi.fix_pathinfo' est-elle vraiment dangereuse avec Nginx + PHP-FPM ?

Il y a eu a lot de parler sur une question de sécurité relative au cgi.fix_pathinfo Option PHP utilisée avec Nginx (généralement PHP-FPM, CGI rapide).

En conséquence, le fichier de configuration par défaut de nginx disait :

# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

Cependant, maintenant, le wiki "officiel" de Nginx déclare que PATH_INFO peut être géré correctement sans désactiver l'option PHP ci-dessus. Et alors ?

Questions

  • Pouvez-vous expliquer clairement ce que fait cgi.fix_pathinfo faire ? ( Le document officiel dit juste : "Pour plus d'informations sur PATH_INFO, voir les spécifications des CGI")
  • Que fera réellement PHP avec ces PATH_INFO y SCRIPT_FILENAME des variables ?
  • Pourquoi et comment cela peut-il être dangereux avec Nginx ? ( détaillé exemples)
  • Le problème existe-t-il toujours dans les versions récentes de ces programmes ?
  • Apache est-il vulnérable ?

J'essaie de comprendre le problème à chaque étape. Par exemple, je ne comprends pas pourquoi l'utilisation de la socket Unix de php-fpm pourrait éviter ce problème.

99voto

user109322 Points 1241

TL;DR - la solution (dont vous n'avez peut-être même pas besoin) est TRÈS SIMPLE et se trouve à la fin de cette réponse.

Je vais essayer de répondre à vos questions spécifiques, mais votre mauvaise compréhension de ce qu'est PATH_INFO rend les questions elles-mêmes un peu fausses.

  • La première question à se poser est la suivante : "Quelle est cette entreprise d'information sur les chemins ?"

  • Votre prochaine question aurait dû être : "Comment PHP détermine-t-il PATH_INFO y SCRIPT_FILENAME sont ?"

    • Les versions antérieures de PHP étaient naïves et ne supportaient même pas techniquement PATH_INFO donc ce qui était censé être PATH_INFO a été transformé en SCRIPT_FILENAME qui, oui, est cassé dans de nombreux cas. Je n'ai pas une version assez ancienne de PHP pour la tester, mais je pense qu'elle a vu SCRIPT_FILENAME comme tout le tralala : "/path/to/script.php/THIS/IS/PATH/INFO" dans l'exemple ci-dessus (préfixé avec le docroot comme d'habitude).
    • Avec l'activation de cgi.fix_pathinfo, PHP trouve maintenant correctement "/THIS/IS/PATH/INFO" pour l'exemple ci-dessus et le place dans le fichier PATH_INFO y SCRIPT_FILENAME récupère juste la partie qui pointe vers le script demandé (préfixé avec le docroot bien sûr).
    • Note : quand PHP a commencé à supporter PATH_INFO ils ont dû ajouter un paramètre de configuration pour la nouvelle fonctionnalité afin que les personnes exécutant des scripts qui dépendaient de l'ancien comportement puissent exécuter les nouvelles versions de PHP. C'est pourquoi il y a même un commutateur de configuration pour cela. Il aurait dû être intégré (avec le comportement "dangereux") dès le début.
  • Mais comment PHP sait-il quelle partie est le script et quelle est l'information sur le chemin ? Et si l'URI est quelque chose comme :

    http://example.com/path/to/script.php/THIS/IS/PATH/INFO.php?q=foo

    • Cela peut être une question complexe dans certains environnements. Ce qui se passe en PHP, c'est qu'il trouve la première partie du chemin de l'URI qui ne correspond à rien dans le docroot du serveur. Dans cet exemple, il voit que sur votre serveur vous n'avez pas "/docroot/path/to/script.php/THIS" mais que vous avez certainement "/docroot/path/to/script.php". SCRIPT_FILENAME a été déterminé et PATH_INFO obtient le reste.
    • Voici maintenant le bon exemple du danger qui est joliment détaillé dans la documentation de Nginx et dans La réponse de Hrvoje Špoljar (on ne peut pas être pointilleux sur un exemple aussi clair) devient encore plus clair : étant donné l'exemple de Hrvoje (" http://example.com/foo.jpg/nonexistent.php "), PHP voit un fichier sur votre docroot "/foo.jpg" mais il ne voit rien appelé "/foo.jpg/nonexistent.php" donc SCRIPT_FILENAME obtient "/foo.jpg" (encore une fois, préfixé avec docroot) et PATH_INFO obtient "/nonexistent.php".
  • Le pourquoi et le comment de ce danger devraient maintenant être clairs :

    • Le serveur web n'est pas vraiment en faute - il transmet simplement l'URI à PHP, qui trouve innocemment que "foo.jpg" contient en fait du contenu PHP, et l'exécute (vous êtes maintenant punis !). Ceci est PAS particulier à Nginx en soi.
  • En REAL Le problème est que vous laissez du contenu non fiable être téléchargé quelque part sans le nettoyer et vous autorisez d'autres requêtes arbitraires au même endroit, que PHP exécute joyeusement quand il le peut.

  • Nginx et Apache pourraient être construits ou configurés pour empêcher les requêtes utilisant cette astuce, et il y a beaucoup d'exemples sur la façon de le faire, y compris dans le document suivant La réponse de l'utilisateur2372674 . Cet article de blog explique bien le problème, mais il manque la bonne solution.

  • Cependant, la meilleure solution est de s'assurer que PHP-FPM est configuré correctement afin qu'il n'exécute jamais un fichier à moins qu'il ne se termine par ".php". Il est à noter que les versions récentes de PHP-FPM (~5.3.9+ ?) ont cette configuration par défaut, donc ce danger n'est plus un problème.

La solution

Si vous avez une version récente de PHP-FPM (~5.3.9+ ?), alors vous n'avez rien à faire, car le comportement sûr ci-dessous est déjà par défaut.

Sinon, trouvez le fichier de php-fpm www.conf (peut-être /etc/php-fpm.d/www.conf (cela dépend de votre système). Assurez-vous que vous avez ceci :

security.limit_extensions = .php

Encore une fois, c'est le défaut dans de nombreux endroits de nos jours.

Notez que cela n'empêche pas un attaquant de télécharger un fichier ".php" dans un dossier de téléchargement de WordPress et de l'exécuter en utilisant la même technique. Vous devez toujours assurer une bonne sécurité pour vos applications.

17voto

Hrvoje Špoljar Points 5116

En fait, sans cela, vous pouvez télécharger un fichier avec un code php nommé 'foo.jpg' vers un serveur web ; puis le demander comme suit http://domain.tld/foo.jpg/nonexistent.php et la pile du serveur web dira par erreur : "oh, c'est un PHP, je dois le traiter", elle ne trouvera pas foo.jpg/nonexistent.php, donc elle reviendra à foo.jpg et traitera foo.jpg comme du code php. C'est dangereux car cela ouvre le système à une intrusion très facile ; toute application web permettant le téléchargement d'images, par exemple, devient un outil pour télécharger une porte dérobée.

En ce qui concerne l'utilisation de php-fpm avec unix socket pour l'éviter ; IMO, cela ne résoudra pas le problème.

4voto

user2372674 Points 193

Dans le Wiki de Nginx comme mesure de sécurité

if (!-f $document_root$fastcgi_script_name) {
    return 404;
}

est inclus dans le bloc d'emplacement. Dans d'autres tutoriels

try_files $uri =404;

est utilisé, ce qui devrait faire la même chose, mais peut donner des problèmes selon le wiki de Nginx. Avec ces options, cgi.fix_pathinfo=1 ne devrait plus être un problème. Vous trouverez plus d'informations à ce sujet aquí .

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X