PHP Téléchargement de fichiers


Exemple

Si vous souhaitez que les utilisateurs téléchargent des fichiers sur votre serveur, vous devez effectuer quelques contrôles de sécurité avant de déplacer le fichier téléchargé dans votre répertoire Web.

Les données téléchargées:

Ce tableau contient des données soumises par l' utilisateur et non des informations sur le fichier lui-même. Bien que ces données soient généralement générées par le navigateur, il est facile de créer une demande de publication sur le même formulaire à l'aide d'un logiciel.

$_FILES['file']['name'];
$_FILES['file']['type'];
$_FILES['file']['size'];
$_FILES['file']['tmp_name'];
  • name - Vérifiez chaque aspect de celui-ci.
  • type - N'utilisez jamais ces données. Il peut être récupéré en utilisant les fonctions PHP à la place.
  • size - Coffre-fort à utiliser.
  • tmp_name - Coffre-fort à utiliser.

Exploiter le nom du fichier

Normalement, le système d'exploitation n'autorise pas les caractères spécifiques dans un nom de fichier, mais en usurpant la demande, vous pouvez les ajouter en autorisant des événements inattendus. Par exemple, nommons le fichier:

../script.php%00.png

Regardez bien ce nom de fichier et vous devriez remarquer quelques choses.

  1. Le premier à noter est le ../ , totalement illégal dans un nom de fichier et en même temps parfaitement bien si vous déplacez un fichier d'un répertoire vers un autre, ce que nous allons faire correctement?
  2. Maintenant , vous pourriez penser que vous étiez en train de vérifier les extensions de fichier correctement dans votre script , mais cet exploit repose sur le décodage d'URL, traduisant %00 à un null caractère, essentiellement dire au système d'exploitation, cette chaîne se termine ici, dépouillant .png hors le nom du fichier .

Alors maintenant, j'ai téléchargé script.php dans un autre répertoire, en passant des validations simples aux extensions de fichiers. Il contourne également .htaccess fichiers .htaccess interdisant les scripts à exécuter depuis votre répertoire de téléchargement.


Obtenir le nom de fichier et l'extension en toute sécurité

Vous pouvez utiliser pathinfo() pour extrapoler le nom et l'extension de manière sûre, mais nous devons d'abord remplacer les caractères indésirables dans le nom du fichier:

// This array contains a list of characters not allowed in a filename
$illegal   = array_merge(array_map('chr', range(0,31)), ["<", ">", ":", '"', "/", "\\", "|", "?", "*", " "]);
$filename  = str_replace($illegal, "-", $_FILES['file']['name']);

$pathinfo  = pathinfo($filename);
$extension = $pathinfo['extension'] ? $pathinfo['extension']:'';
$filename  = $pathinfo['filename']  ? $pathinfo['filename']:'';

if(!empty($extension) && !empty($filename)){
  echo $filename, $extension;
} else {
  die('file is missing an extension or name');
}

Alors que maintenant nous avons un nom de fichier et une extension qui peuvent être utilisés pour le stockage, je préfère quand même stocker ces informations dans une base de données et donner à ce fichier un nom généré par exemple, md5(uniqid().microtime())

+----+--------+-----------+------------+------+----------------------------------+---------------------+
| id | title  | extension | mime       | size | filename                         | time                |
+----+--------+-----------+------------+------+----------------------------------+---------------------+
| 1  | myfile | txt       | text/plain | 1020 | 5bcdaeddbfbd2810fa1b6f3118804d66 | 2017-03-11 00:38:54 |
+----+--------+-----------+------------+------+----------------------------------+---------------------+

Cela résoudrait le problème des noms de fichiers en double et des exploits imprévus dans le nom du fichier. L'attaquant pourrait également deviner où ce fichier a été stocké, car il ne peut pas le cibler spécifiquement pour exécution.


Validation de type MIME

Vérifier une extension de fichier pour déterminer quel fichier il est ne suffit pas, car un fichier peut s'appeler image.png mais peut très bien contenir un script php. En vérifiant le type MIME du fichier téléchargé par rapport à une extension de fichier, vous pouvez vérifier si le fichier contient le nom auquel il fait référence.

Vous pouvez même aller plus loin pour valider les images, et cela les ouvre en fait:

if($mime == 'image/jpeg' && $extension == 'jpeg' || $extension == 'jpg'){
  if($img = imagecreatefromjpeg($filename)){
    imagedestroy($img);
  } else {
    die('image failed to open, could be corrupt or the file contains something else.');
  }
}

Vous pouvez récupérer le type MIME en utilisant une fonction intégrée ou une classe .


Liste blanche de vos téléchargements

Plus important encore, vous devez inclure les extensions de fichiers et les types MIME dans chaque liste.

function isFiletypeAllowed($extension, $mime, array $allowed)
{
    return  isset($allowed[$mime]) &&
            is_array($allowed[$mime]) &&
            in_array($extension, $allowed[$mime]);
}

$allowedFiletypes = [
    'image/png'  => [ 'png' ],
    'image/gif'  => [ 'gif' ],
    'image/jpeg' => [ 'jpg', 'jpeg' ],
];

var_dump(isFiletypeAllowed('jpg', 'image/jpeg', $allowedFiletypes));