IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Comment vérifier la véritable extension d'un fichier (type mime) ?


Sujet :

Langage PHP

  1. #1
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Juillet 2015
    Messages
    518
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Juillet 2015
    Messages : 518
    Points : 184
    Points
    184
    Par défaut Comment vérifier la véritable extension d'un fichier (type mime) ?
    Salut à tous,

    J'ai lu le tuto de Antoine Hérault, l'Upload de fichiers en PHP.

    dont voici le code final :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    <?php
    $dossier = 'upload/';
    $fichier = basename($_FILES['avatar']['name']);
    $taille_maxi = 100000;
    $taille = filesize($_FILES['avatar']['tmp_name']);
    $extensions = array('.png', '.gif', '.jpg', '.jpeg');
    $extension = strrchr($_FILES['avatar']['name'], '.'); 
    //Début des vérifications de sécurité...
    if(!in_array($extension, $extensions)) //Si l'extension n'est pas dans le tableau
    {
         $erreur = 'Vous devez uploader un fichier de type png, gif, jpg, jpeg, txt ou doc...';
    }
    if($taille>$taille_maxi)
    {
         $erreur = 'Le fichier est trop gros...';
    }
    if(!isset($erreur)) //S'il n'y a pas d'erreur, on upload
    {
         //On formate le nom du fichier ici...
         $fichier = strtr($fichier, 
              'ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöùúûüýÿ', 
              'AAAAAACEEEEIIIIOOOOOUUUUYaaaaaaceeeeiiiioooooouuuuyy');
         $fichier = preg_replace('/([^.a-z0-9]+)/i', '-', $fichier);
         if(move_uploaded_file($_FILES['avatar']['tmp_name'], $dossier . $fichier)) //Si la fonction renvoie TRUE, c'est que ça a fonctionné...
         {
              echo 'Upload effectué avec succès !';
         }
         else //Sinon (la fonction renvoie FALSE).
         {
              echo 'Echec de l\'upload !';
         }
    }
    else
    {
         echo $erreur;
    }
    ?>
    Bien-sur le code fonctionne, mais il ne sécurise pas (pas assez) l'extension de fichier.. d'ailleurs dans le tuto il (Antoine Hérault) le dit lui même :
    Cette méthode est une première approche qui nous suffit pour le moment mais, en réalité, il faudrait vérifier le type MIME des fichiers uploadés.
    Donc, vous devinez déjà ma question.. Comment faire pour obtenir un formulaire d'envoi de fichier (image) qui contrôle/vérifie le type mime ?

    Je ne comprends pas trop la différence entre extension et type mime.. faut-t'il vérifier les deux ? Je sais qu'il est possible de modifier l'extension d'un fichier et de faire croire au serveur qu'il s'agit d'une image alors qu'en réalité il s'agit d'un fichier php de hack.. Si le type mime est plus sûre que l'extension, pourquoi vérifier aussi ce dernier ?

    Merci pour votre aide car la je suis perdu.

  2. #2

  3. #3
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Juillet 2015
    Messages
    518
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Juillet 2015
    Messages : 518
    Points : 184
    Points
    184
    Par défaut
    Salut Jérôme

    Je viens de passer l’après midi sur ton tuto de news, oui oui l’après midi entière !! J'ai décortiqué ton code pratiquement de A a Z.

    bon... au final j'ai 2 erreurs :

    erreurs :
    Warning: finfo::file(): Empty filename or path in C:\wamp64\www\site5\upload.php on line 29
    Warning: finfo_close() expects parameter 1 to be resource, object given in C:\wamp64\www\site5\upload.php on line 30

    Mon code avec des portions de ton tuto :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    <?php
     
    require_once 'inc/functions.php';
    require_once 'inc/db.php';
     
    session_start();
     
    define("NEWS_REP_PHOTOS", "upload/");
    define("NEWS_SIZEMAX_PHOTO", 200000);
    define("NEWS_EXTENSION_PHOTO", "jpg,jpeg,png,gif");
    define("NEWS_MIMETYPE_PHOTO", "image/jpeg,image/png,image/gif");
     
    if (!empty($_POST)) {
     
        $errors = array();
     
        // extension du fichier uploadé (en minuscule)
        $file_Extension = strtolower(pathinfo($_FILES['avatar']['name'], PATHINFO_EXTENSION));
     
        // GESTION DES ERREURS
        // -------------------------------------
        // on vérifie les RESTRICTIONS sur les fichiers
        if (UPLOAD_ERR_OK<>0 && UPLOAD_ERR_FORM_SIZE==2) {
            $errors['errformsize'] = 'Taille de fichier trop important ('.NEWS_SIZEMAX_PHOTO.' octets)';
        }
     
        // Type MIME réel du fichier (important : évite les fichiers NON valides, dont l'extension a été renommée)
        $finfo = new finfo(FILEINFO_MIME_TYPE, NULL); // Retourne le type mime
        $file_MimeType = $finfo->file($_FILES['avatar']['tmp_name']); // LIGNE 29
        finfo_close($finfo); // LIGNE 30
     
        // on vérifie la TAILLE MAXI
        if ($_FILES['avatar']['size'] > NEWS_SIZEMAX_PHOTO) {
            $errors['size'] = 'Taille de fichier supérieure à la taille maxi autorisée';
        }
     
        // on vérifie l'EXTENSION
        if (!in_array($file_Extension, explode(',', constant('NEWS_EXTENSION_PHOTO')))) {
            $errors['ext'] = 'L\'extension ne correspond pas (Extensions acceptées  : <b>'.constant('NEWS_EXTENSION_PHOTO').'</b>)';
            if(in_array($file_MimeType, explode(',', constant('NEWS_MIMETYPE_PHOTO')))) {
                $errors['ext'] = '<b>Attention</b> : Ce fichier est peut-être corrompu ! L\'extension ne correspond pas au type MIME !';
            }
        }
     
        // on vérifie le TYPE MIME
        if (!in_array($file_MimeType, explode(',', constant('NEWS_MIMETYPE_PHOTO')))) {
            $errors['typemime'] = 'Le type MIME ne correspond pas (Extensions acceptées  : <b>'.constant('NEWS_EXTENSION_PHOTO').'</b>)';
            if(in_array($file_Extension, explode(',', constant('NEWS_EXTENSION_PHOTO')))) {
                $errors['typemime'] = '<b>Attention</b> : Ce fichier est peut-être corrompu ! L\'extension ne correspond pas au type MIME !';
            }
        }
     
        if (empty($errors)) // S'il n'y a pas d'erreur, on upload
        {
            $nouveau_nom = md5(uniqid());
     
            if (move_uploaded_file($_FILES['avatar']['tmp_name'], NEWS_REP_PHOTOS . $nouveau_nom .'.'. $file_Extension))
            {
                $_SESSION['flash']['success'] = 'Upload effectué avec succès !';
            }
            else // Sinon (la fonction renvoie FALSE).
            {
                $errors['echecup'] = 'Echec de l\'upload !';
            }
        }
     
        debug($_FILES);
    }
     
    require 'inc/header.php';
     
    ?>
     
    <h1>Formulaire de chargement de fichier</h1>
     
    <?php if(!empty($errors)): ?>
        <div class="alert alert-danger">
            <p>Vous n'avez pas rempli le formulaire correctement</p>
            <ul>
                <?php foreach($errors as $error): ?>
                    <li><?= $error; ?></li>
                <?php endforeach; ?>
            </ul>
        </div>
    <?php endif; ?>
     
    <!-- Le type d'encodage des données, enctype, DOIT être spécifié comme ce qui suit -->
    <form enctype="multipart/form-data" action="" method="post">
        <!-- MAX_FILE_SIZE doit précéder le champ input de type file -->
        <input type="hidden" name="MAX_FILE_SIZE" value="<?= NEWS_SIZEMAX_PHOTO ?>" />
        <!-- Le nom de l'élément input détermine le nom dans le tableau $_FILES -->
        Envoyez ce fichier : <input name="avatar" type="file" />
        <input type="submit" value="Envoyer le fichier" />
    </form>
     
    <?php require 'inc/footer.php'; ?>

  4. #4
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Juillet 2015
    Messages
    518
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Juillet 2015
    Messages : 518
    Points : 184
    Points
    184
    Par défaut
    bon.. J'ai terminé ! aucune erreur et le script fonctionne parfaitement ! Mon code est très propre et facile à comprendre. enfin je crois^^

    Je reviens vers vous pour "valider" mon code et prendre quelques conseils (si matière il y a à en donner).

    voici mon code :

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    define("UPLOAD_REP_PHOTO", "upload/");
    define("UPLOAD_SIZEMAX_PHOTO", 200000); // La taille, en octets.
    define("UPLOAD_EXTENSION_PHOTO", "jpg,jpeg,png,gif");
    define("UPLOAD_MIMETYPE_PHOTO", "image/jpeg,image/png,image/gif");
     
    if (!empty($_POST)) {
     
        // Messages d'erreurs de chargement de fichiers
        $array_upload_err = [
            // UPLOAD_ERR_OK => "Valeur : 0. Aucune erreur, le téléchargement est correct.",
            UPLOAD_ERR_INI_SIZE => "Valeur : 1. La taille du fichier téléchargé excède la valeur de upload_max_filesize, configurée dans le php.ini.",
            UPLOAD_ERR_FORM_SIZE => "Valeur : 2. La taille du fichier téléchargé excède la valeur de MAX_FILE_SIZE, qui a été spécifiée dans le formulaire HTML.",
            UPLOAD_ERR_PARTIAL => "Valeur : 3. Le fichier n'a été que partiellement téléchargé.",
            UPLOAD_ERR_NO_FILE => "Valeur : 4. Aucun fichier n'a été téléchargé.",
            UPLOAD_ERR_NO_TMP_DIR => "Valeur : 6. Un dossier temporaire est manquant. Introduit en PHP 5.0.3.",
            UPLOAD_ERR_CANT_WRITE => "Valeur : 7. Échec de l'écriture du fichier sur le disque. Introduit en PHP 5.1.0.",
            UPLOAD_ERR_EXTENSION => "Une extension PHP a arrêté l'envoi de fichier. PHP ne propose aucun moyen de déterminer quelle extension est en cause.",
        ];
     
        $errors = array();
     
        if ($_FILES['avatar']['error'] != 0)
        {
            $errors['upload_err'] = $array_upload_err[$_FILES['avatar']['error']];
        } else {
            // Récupère l'extension d'un fichier
            $spl_file_info = new SplFileInfo($_FILES['avatar']['name']);
            $file_Extension = strtolower($spl_file_info->getExtension());
     
            // Retourne le type mime à l'extension mimetype
            $finfo = new finfo(FILEINFO_MIME_TYPE);
            /* Récupère le mime-type d'un fichier spécifique */
            $file_MimeType = $finfo->file($_FILES['avatar']['tmp_name']);
     
            // Retourne la taille d'une image
            list($width, $height, $type, $attr) = getimagesize($_FILES['avatar']['tmp_name']);
     
            // On vérifie la taille, en octets, du fichier téléchargé
            if ($_FILES['avatar']['size'] > UPLOAD_SIZEMAX_PHOTO) {
                $errors['size'] = 'Taille de fichier supérieure à la taille maxi autorisée';
            }
     
            // On vérifie l'extension
            if (!in_array($file_Extension, explode(',', constant('UPLOAD_EXTENSION_PHOTO'))))
            {
                $errors['ext'] = 'L\'extension ne correspond pas aux extensions acceptées';
            }
     
            // On vérifie le type mime
            if (!in_array($file_MimeType, explode(',', constant('UPLOAD_MIMETYPE_PHOTO'))))
            {
                $errors['ext'] = 'L\'extension ne correspond pas aux extensions acceptées';
            }
     
            if (empty($errors))
            {
                $key = sha1($user_id . $username) . '.' . $file_Extension; // Je génère un nom pour l'upload grâce à l'id et pseudo du membre connecté.
                if (move_uploaded_file($_FILES['avatar']['tmp_name'], UPLOAD_REP_PHOTO . $key)) {
                    $_SESSION['flash']['success'] = 'Upload effectué avec succès !';
                } else {
                    $errors['echec'] = 'Echec de l\'upload !';
                }
            }
        }
    }

    J'attends vos retours.

    Merci à vous!

  5. #5
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    A part la ligne 36 qui ne sert pas, ca a l'air bon.

  6. #6
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 691
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 691
    Points : 20 222
    Points
    20 222
    Par défaut
    Pour de l'upload d'image comme tu cherches à faire , la seule solution pour se protéger est de retraiter l'image avec GD ou imagemagick.
    La vérification d'extension et de type mime c'est une chose mais c'est spoofable assez facilement. C'est juste un frein pour un hacker qui devra se forcer un peu plus que la normale.

    Les points importants :

    - Vérifier le retour de getimagesize() , si c'es false => tu as un problème.
    - Retraiter l'image avec GD par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $im = imagecreatefromjpeg($cheminupload); 
    if($im == false)
        //PROBLEME
    if(!imagejpeg($im,'monfichier.jpeg')
        //PROBLEME
    - Ne jamais uploader dans un dossier accessible depuis le web, toujours en dehors de la racine web.
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Juillet 2015
    Messages
    518
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Juillet 2015
    Messages : 518
    Points : 184
    Points
    184
    Par défaut
    jreaux62 :

    Oui pour le moment la ligne 36 ne sert à rien (bonne remarque) mais je vais bientôt l'utiliser pour redimensionner mon image.

    grunk :

    ah ok je ne savais pas merci pour l'info. Dans le cas où je redimensionne mon image normalement plus de problème ?..

  8. #8
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 691
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 691
    Points : 20 222
    Points
    20 222
    Par défaut
    Oui , si tu applique un redimensionnement systématique plus de problème :
    - Soit le redimensionnement réussi => c'était bien une image
    - Soit il échoue => ce n'était probablement pas une image.
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  9. #9
    Membre habitué
    Homme Profil pro
    Webmaster
    Inscrit en
    Juillet 2015
    Messages
    518
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Juillet 2015
    Messages : 518
    Points : 184
    Points
    184
    Par défaut
    hum d'accord je vois

    sinon concernant le dossier d'upload :
    Ne jamais uploader dans un dossier accessible depuis le web, toujours en dehors de la racine web.
    Je n'ai pas accès à la partie au dessus de la racine. est-t'il possible de mettre un htaccess dans le dossier de l'upload qui interdit le traitement de script dans le dossier d'upload ? d’après quelques tuto que j'ai lu c'est la chose à faire.

    + interdire l'affichage des images et également l'index du répertoire, grâce au htaccess.

Discussions similaires

  1. Comment vérifier qu'un fichier est déjà ouvert ?
    Par n@n¤u dans le forum Entrée/Sortie
    Réponses: 14
    Dernier message: 04/08/2011, 12h23
  2. Réponses: 4
    Dernier message: 15/12/2009, 14h54
  3. Réponses: 1
    Dernier message: 18/02/2007, 20h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo