web-dev-qa-db-fra.com

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

Il y a eu alotsuren train de parler à propos d'un problème de sécurité relatif au cgi.fix_pathinfo 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 indique que PATH_INFO peut être géré correctement sans désactiver l'option PHP PHP ci-dessus. Alors quoi?

Des questions

  • Pouvez-vous expliquer clairement ce que cgi.fix_pathinfo faire? ( le doc officiel dit juste : "Pour plus d'informations sur PATH_INFO, voir les spécifications CGI")
  • Que fera PHP vraiment faire avec ces PATH_INFO et SCRIPT_FILENAME variables?
  • Pourquoi et comment cela peut-il être dangereux avec Nginx? ( exemples détaillés )
  • 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 du socket Unix php-fpm pourrait éviter ce problème.

55
Totor

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

J'essaierai 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 erronées.

  • La première question devrait être "Quelle est cette entreprise d'informations sur le chemin?"

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

    • 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é intégré à SCRIPT_FILENAME qui, oui, est cassé dans de nombreux cas. Je n'ai pas une version assez ancienne de PHP pour tester, mais je crois qu'il a vu SCRIPT_FILENAME comme le Shebang entier: "/path/to/script.php/THIS/IS/PATH/INFO" dans l'exemple ci-dessus (préfixé avec le docroot comme d'habitude).
    • Avec cgi.fix_pathinfo activé, PHP trouve désormais correctement "/ THIS/IS/PATH/INFO" pour l'exemple ci-dessus et le place dans PATH_INFO Et SCRIPT_FILENAME obtient juste la partie qui pointe vers le script demandé (préfixé avec le docroot bien sûr).
    • Remarque: lorsque PHP a commencé à prendre en charge 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 new = PHP versions. 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 quelles informations sur son 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 dans PHP, c'est qu'il trouve la première partie du chemin URI qui ne correspond à rien sous le docroot du serveur. Pour cet exemple, il voit que sur votre serveur vous n'avez pas "/docroot/path/to/script.php/THIS" mais vous avez très certainement "/docroot/path/to/script.php" alors maintenant le SCRIPT_FILENAME a été déterminé et PATH_INFO obtient le reste.
    • Alors maintenant, le bon exemple du danger qui est bien détaillé dans les documents Nginx et dans réponse de Hrvoje Špoljar (vous ne pouvez 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" .
  • Pourquoi et comment cela peut être dangereux devrait maintenant être clair:

    • Le serveur Web n'est vraiment pas en faute - il s'agit simplement d'un proxy de l'URI vers PHP, qui trouve innocemment que "foo.jpg" contient réellement PHP contenu, donc il l'exécute (maintenant vous avez (Ceci est [~ # ~] pas [~ # ~] particulier à Nginx en soi.
  • Le problème [~ # ~] réel [~ # ~] est que vous laissez le contenu non approuvé être téléchargé quelque part sans nettoyage et que vous autorisez d'autres requêtes arbitraires à la même emplacement, qui PHP s'exécute avec bonheur quand il le peut.
  • Nginx et Apache pourraient être construits ou configurés pour empêcher les requêtes utilisant cette ruse, et il existe de nombreux exemples pour le faire, y compris dans réponse de user2372674 . Cet article de blog explique bien le problème, mais il manque la bonne solution.

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

La solution

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

Sinon, trouvez le fichier www.conf De php-fpm (peut-être que /etc/php-fpm.d/www.conf Dépend de votre système). Assurez-vous d'avoir 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 WordPress télécharge et exécute celui-ci en utilisant la même technique. Vous devez toujours avoir une bonne sécurité pour vos applications.

84
user109322

En substance, sans cela, vous pouvez télécharger un fichier avec un code php nommé comme 'foo.jpg' sur le serveur Web; puis demandez-le comme http: //domain.tld/foo.jpg/nonexistent.php et la pile du serveur Web dira par erreur oh; c'est un PHP; J'ai besoin de traiter cela, il ne trouvera pas foo.jpg/nonexistent.php donc il retombera sur foo.jpg et traitera foo.jpg en tant que 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.

Concernant l'utilisation de php-fpm avec un socket Unix pour l'éviter; OMI, il ne résoudra pas le problème.

14
Hrvoje Špoljar

Dans le wiki Nginx comme mesure de sécurité

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

est inclus dans le bloc de localisation. Dans d'autres tutoriels

try_files $uri =404;

est utilisé, ce qui devrait faire de même, mais peut poser des problèmes selon le wiki Nginx. Avec ces options, cgi.fix_pathinfo=1 ne devrait plus être un problème. Plus d'informations peuvent être trouvées ici .

3
user2372674