web-dev-qa-db-fra.com

PHP liste de contrôle de sécurité de téléchargement d'image

Je programme un script pour télécharger des images sur mon application. Les étapes de sécurité suivantes sont-elles suffisantes pour sécuriser l’application du côté du script?

  • Désactiver PHP pour s’exécuter dans le dossier de téléchargement en utilisant .httaccess.
  • Ne pas autoriser le téléchargement si le nom du fichier contient la chaîne "php".
  • Autoriser uniquement les extensions: jpg, jpeg, gif et png.
  • Autoriser uniquement le type de fichier image.
  • Interdit les images avec deux types de fichiers.
  • Changer le nom de l'image.
  • Télécharger dans un sous-répertoire, pas le répertoire racine.

Ceci est mon script:

 $filename=$_FILES['my_files']['name'];
 $filetype=$_FILES['my_files']['type'];
 $filename = strtolower($filename);
 $filetype = strtolower($filetype);

 //check if contain php and kill it 
 $pos = strpos($filename,'php');
 if(!($pos === false)) {
  die('error');
 }




 //get the file ext

 $file_ext = strrchr($filename, '.');


 //check if its allowed or not
 $whitelist = array(".jpg",".jpeg",".gif",".png"); 
 if (!(in_array($file_ext, $whitelist))) {
    die('not allowed extension,please upload images only');
 }


 //check upload type
 $pos = strpos($filetype,'image');
 if($pos === false) {
  die('error 1');
 }
 $imageinfo = getimagesize($_FILES['my_files']['tmp_name']);
 if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg'&& $imageinfo['mime']      != 'image/jpg'&& $imageinfo['mime'] != 'image/png') {
   die('error 2');
 }
//check double file type (image with comment)
if(substr_count($filetype, '/')>1){
die('error 3')
}

 // upload to upload direcory 
 $uploaddir = 'upload/'.date("Y-m-d").'/' ;

if (file_exists($uploaddir)) {  
} else {  
    mkdir( $uploaddir, 0777);  
}  
  //change the image name
 $uploadfile = $uploaddir . md5(basename($_FILES['my_files']['name'])).$file_ext;



  if (move_uploaded_file($_FILES['my_files']['tmp_name'], $uploadfile)) {
 echo "<img id=\"upload_id\" src=\"".$uploadfile."\"><br />";
  } else {
   echo "error";
  }

Tous les nouveaux conseils sont les bienvenus :)

60
usef_ksa

Retraitez l'image avec Gd (ou Imagick) et enregistrez l'image traitée. Tous les autres sont juste amusement ennuyeux pour les pirates.

Edit: Et comme rr l’a fait remarquer, utilisez move_uploaded_file() pour tout téléchargement.

Édition tardive: En passant, vous voudriez être très restrictif concernant votre dossier de téléchargement. Ces endroits sont l’un des coins sombres où de nombreux exploits ont lieu. Ceci est valable pour tout type de téléchargement et tout langage/serveur de programmation. Vérifier https://www.owasp.org/index.php/Unrestricted_File_Upload

33
Halil Özgür

Pour tester la sécurité des fichiers image, je peux penser à 4 niveaux de sécurité. Ils seraient:

  • Niveau 1: Vérifier l'extension (le fichier d'extension se termine par)
  • Niveau 2: Vérifiez le type MIME ($file_info = getimagesize($_FILES['image_file']; $file_mime = $file_info['mime'];)
  • Niveau 3: lit les 100 premiers octets et vérifie s'ils ont des octets dans la plage suivante: ASCII 0-8, 12-31 (décimal).
  • Niveau 4: Recherchez des nombres magiques dans l'en-tête (10 à 20 premiers octets du fichier). Vous pouvez trouver ici quelques-uns des octets d'en-tête des fichiers: http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Examples

Remarque: le chargement de l'image entière serait lent. 

12
tanjir

Avertissement XSS

Encore une remarque très importante. Ne pas servir/télécharger quelque chose qui pourrait être interprété comme HTML dans le navigateur.

Comme les fichiers se trouvent sur votre domaine, le javascript contenu dans ce document HTML aura accès à tous vos cookies, permettant ainsi une sorte d'attaque XSS.

Scénario d'attaque:

  1. L'attaquant met en ligne un fichier HTML avec le code JS qui envoie tous les cookies à son serveur.

  2. L’attaquant envoie le lien à vos utilisateurs par courrier électronique, par messagerie instantanée ou simplement via iframe sur son site ou sur un autre.

Solution la plus sécurisée:

Rendre le contenu téléchargé disponible uniquement sur le sous-domaine ou sur un autre domaine. De cette façon, les cookies ne seront pas accessibles. C'est également l'un des conseils de performance de Google:

https://developers.google.com/speed/docs/best-practices/request#ServeFromCookielessDomain

7
Rok Kralj

Vous voudrez peut-être aussi exécuter "is_uploaded_file" sur le $ _FILES ['mes_fichiers'] ['nom_mpT'] Voir http://php.net/manual/en/function.is-uploaded-file.php

6
rr.

Créez un nouveau fichier .htaccess dans le répertoire uploads et collez ce code:

php_flag engine 0
RemoveHandler .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml
AddType application/x-httpd-php-source .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml

Veillez simplement à renommer les fichiers que vous téléchargez et oubliez de vérifier les types, le contenu, etc.

6
jloa

Je vais répéter quelque chose que j'ai posté dans la question connexe.

Vous pouvez détecter le type de contenu en utilisant Fonctions Fileinfo (mime_content_type () dans les versions précédentes de PHP).

Un extrait du manuel PHP sur l'ancienne extension Mimetype, qui est maintenant remplacé par Fileinfo:

Les fonctions de ce module tentent de deviner le type de contenu et encodage d'un fichier en recherchant certaines séquences d'octets magiques à positions spécifiques dans le fichier. Bien que ce ne soit pas une épreuve de balle approche les heuristiques utilisées font un très bon travail.

getimagesize() peut également faire du bon travail, mais la plupart des autres vérifications que vous effectuez sont absurdes. Par exemple, pourquoi la chaîne php n'est pas autorisée dans le nom du fichier. Vous n'allez pas inclure le fichier image dans le script PHP, simplement parce que son nom contient la chaîne php, êtes-vous?


Lorsqu'il s'agit de recréer des images, dans la plupart des cas, la sécurité sera améliorée ... jusqu'à ce que la bibliothèque que vous utilisez ne soit plus vulnérable.

Alors quelle extension PHP convient le mieux à la re-création sécurisée d'images? J'ai vérifié Détails CVE site web. Je pense que le trio applicable sont ces extensions:

  1. Gd (6 vulnérabilités)
  2. ImageMagick (44 vulnérabilités)
  3. Gmagick (12 vulnérabilités)

De la comparaison, je pense que D.ieu convient le mieux, car il a le plus petit nombre de problèmes de sécurité et ils sont assez vieux. Trois d’entre elles sont critiques, mais ImagMagick et Gmagick ne fonctionnent pas mieux… ImageMagick semble être très bogué (du moins en ce qui concerne la sécurité), j’ai donc choisi Gmagick comme deuxième option.

5
doc

si la sécurité est très importante, utilisez la base de données pour le nom de fichier de sauvegarde et le nom renommé. Vous pouvez ici modifier l'extension du fichier en fichier .myfile et créer un fichier php pour envoyer une image avec des en-têtes. php peut être plus sécurisé et vous pouvez l'utiliser dans la balise img comme blow: 

<img src="send_img.php?id=555" alt="">

vérifiez également l'extension de fichier avec EXIF ​​avant le téléchargement. 

2
Mohamad Rostami

Le meilleur moyen de protéger votre site Web lorsque l’utilisateur charge l’image est de procéder comme suit:

  • vérifier l'extension de l'image
  • vérifier la taille de l'image avec cette fonction "getimagesize ()"
  • après cela, vous pouvez utiliser la fonction "file_get_contents ()"
  • En fin de compte, vous devriez insérer file_Content dans votre base de données nd quelle est votre opinion?
2
Hamza Ouha

La réponse la plus simple à permet aux utilisateurs de télécharger des fichiers en toute sécurité dans PHP est: Enregistrez toujours les fichiers en dehors de la racine de votre document.

Par exemple: Si la racine de votre document est /home/example/public_html, enregistrez les fichiers dans /home/example/uploaded.

Lorsque vos fichiers sont en sécurité hors de portée directe de votre serveur Web, vous pouvez toujours les rendre accessibles à vos visiteurs:

  1. Configurez un hôte virtuel distinct pour le service de contenu statique qui n'exécute jamais les scripts PHP, Perl, etc.
  2. Téléchargez les fichiers sur un autre serveur (par exemple, un serveur virtuel virtuel bon marché, Amazon S3, etc.).
  3. Conservez-les sur le même serveur et utilisez un script PHP pour les requêtes proxy afin de vous assurer que le fichier est uniquement lisible, et non exécutable.

Toutefois, si vous utilisez les options 1 ou 3 de cette liste et que votre application présente une vulnérabilité d’inclusion de fichier locale, votre formulaire d’envoi de fichier peut reste un vecteur d’attaque .

2
Scott Arciszewski

J'utilise un script de téléchargement php qui crée un nouveau nombre aléatoire de 4 octets pour chaque fichier téléchargé, puis XOR le contenu du fichier avec ces 4 octets (en les répétant aussi souvent que nécessaire), et attache enfin les 4 octets dans le fichier avant de l’enregistrer.

Pour le téléchargement, les 4 octets doivent être à nouveau coupés du fichier, le contenu sera de nouveau traité avec eux et le résultat sera envoyé au client.

De cette façon, je peux être sûr que les fichiers que je sauvegarde sur le serveur ne seront ni exécutables ni potentiellement significatifs pour n’importe quelle application. De plus, je n'ai besoin d'aucune base de données supplémentaire pour stocker les noms de fichiers.

Voici le code que j'utilise pour cela:

Télécharger:

        <?php
            $outputfilename = $_POST['filename'];
            $inputfile = $_FILES["myblob"]["tmp_name"];
            $tempfilename="temp.tmp";

            if( move_uploaded_file($inputfile, $tempfilename) ) {
                $XORstring = random_bytes(4);

                $tempfile=fopen($tempfilename, "r");
                $outputfile=fopen($outputfilename, "w+");
                flock($outputfilename, LOCK_EX);

                fwrite($outputfilename, $XORbytes1);

                while ( $buffer = fread($tempfile, 4) ) {
                    $buffer = $buffer ^ $XORstring;
                    fwrite($outputfilename, $buffer);
                }

                flock($outputfilename, LOCK_UN);

                fclose($tempfile);
                fclose($outputfile);

                unlink($tempfilename);
            }

            exit(0);
        ?>

Télécharger:

        <?php
            $inputfilename = $_POST['filename'];
            $tempfilename = "temp.tmp";

            $inputfile=fopen($inputfilename, "r");
            $tempfile=fopen($tempfilename, "w+");
            flock($tempfile, LOCK_EX);

            $XORstring = fread($inputfile, 4);

            while ( $buffer = fread($inputfile, 4) ) {
                $buffer = $buffer ^ $XORstring;
                fwrite($tempfile, $buffer);
            }

            flock($tempfile, LOCK_UN);

            fclose($inputfile);
            fclose($tempfile);

            readfile($tempfile);
            unlink($tempfile);

            exit(0);
        ?>
0
Max M.

Pour un fichier image, vous pouvez également modifier l'autorisation du fichier après l'avoir renommé pour vous assurer qu'il ne s'exécutera jamais (rw-r - r--).

0
Jesus