web-dev-qa-db-fra.com

Risques d'un formulaire de téléchargement d'image PHP

Mon client veut un site de photographie où les utilisateurs peuvent télécharger leurs photos en réponse à des concours de photographie. Bien que techniquement ce ne soit pas un problème, je veux connaître les risques associés à l'autorisation de tout utilisateur de télécharger une image sur mon serveur. J'ai le sentiment que les risques sont élevés ...

Je pensais utiliser quelque chose comme ça http://www.w3schools.com/php/php_file_upload.asp

Si je laisse des utilisateurs anonymes télécharger des fichiers, comment puis-je sécuriser le répertoire dans lequel les images (et les fichiers potentiellement malveillants) seront téléchargés?

45
Starkers

La plus grande préoccupation est évidemment que les utilisateurs malveillants téléchargeront des choses qui ne sont pas des images sur votre serveur. Plus précisément, ils peuvent télécharger des fichiers exécutables ou des scripts qu'ils tenteront d'inciter votre serveur à exécuter.

Une façon de vous protéger contre cela est de vous assurer que les fichiers ne sont pas exécutables après vous move_uploaded_file En PHP. C'est aussi simple que en utilisant chmod() pour définir 644 autorisations.

Notez qu'un utilisateur peut toujours télécharger PHP ou autres scripts et inciter Apache à les exécuter en fonction de votre configuration.

Pour éviter cela, appelez getimagesize() sur les fichiers après leur téléchargement et déterminez de quel type de fichier il s'agit. Renommez les fichiers en un nom de fichier unique et utilisez votre propre extension . De cette façon, si un utilisateur télécharge evil.jpg.php, Votre script l'enregistrera sous 12345.jpg Et il ne sera pas exécutable. Mieux encore, votre script ne le touchera même pas car il s'agira d'un JPEG non valide.

Personnellement, je renomme toujours les images téléchargées en horodatage actuel à partir de time() ou un UUID. Cela permet également d'éviter les noms de fichiers très malveillants (comme quelqu'un qui essaie de télécharger un fichier qu'ils ont nommé ../../../../../../../../etc/passwd)

Comme protection supplémentaire, vous pouvez utiliser ce que l'on appelle parfois un "pare-feu d'image". Fondamentalement, cela implique de sauvegarder les images téléchargées dans un répertoire qui est extérieur la racine du document et de les afficher via un script PHP qui appelle readfile() pour les afficher. Cela peut être beaucoup de travail mais c'est l'option la plus sûre.

Une préoccupation secondaire est que les utilisateurs téléchargent trop de fichiers ou des fichiers trop volumineux, consomment tout l'espace disque disponible ou remplissent le quota de l'utilisateur d'hébergement. Cela peut être géré dans votre logiciel, y compris en limitant la taille des fichiers individuels, la quantité de données qu'un utilisateur peut télécharger, la taille totale de tous les téléchargements, etc. Assurez-vous que l'utilisateur administrateur du site Web a un moyen de gérer et de supprimer ces fichiers.

Ne pas se fier à aucune des données de $_FILES. De nombreux sites vous demandent de vérifier le type MIME du fichier, à partir de $_FILES[0]['type'] Ou en vérifiant l'extension du nom de fichier. Ne faites pas cela . Tout sous $_FILES À l'exception de tmp_name peut être manipulé par un utilisateur malveillant. Si vous savez que vous voulez des images, appelez uniquement getimagesize car il lit réellement les données d'image et saura si le fichier est vraiment une image.

Ne comptez pas sur la vérification du référent HTTP pour toute sécurité. De nombreux sites vous conseillent de vérifier pour vous assurer que le référent est votre propre site pour vous assurer que le fichier est légitime. Cela peut facilement être truqué.

Pour plus d'informations, voici quelques bons articles:

77
Josh

Consultez https://www.owasp.org/index.php/PHP_Security_Cheat_Sheet#File_uploads pour quelques conseils importants.

getimagesize () peut être trompé en exécutant PHP code.

http://www.php.net/manual/en/features.file-upload.php a un commentaire utilisateur de CertaiN qui fournit une meilleure alternative avec finfo (FILEINFO_MIME_TYPE)

5
Rodney