Sécuriser un script php de téléchargement de fichiers

Nouveau WRInaute
Bonjour tout le monde,

Je viens de me rendre compte qu'un script php de mon site comporte une énorme faille. Le script en question permet de lancer le téléchargement de fichiers images (.jpg et .png), mais à ma grande stupeur je viens de voir qu'il peut lancer n'importe quel fichier qui se trouve sur le site (fichiers php html même le htaccess 8O ) enfin bref, la brèche du siècle quoi :) j'ai bien entendu retiré ce script en attendant de le sécuriser.

Ce script utilise une variable avec la fonction GET pour récupérer les chemins de fichiers à télécharger. Je souhaite donc interdire à la variable qui utilise la fonction GET, de ne pas traverser tous les répertoires, sauf celui qui contient les images. Comment je pourrais faire pour cela ?

Voici le code ce script :

Code:
<?PHP
foreach ($_REQUEST as $key => $val) 
{
  $val = preg_replace("/[^_A-Za-z0-9-\.&=]/i",'', $val);
  $_REQUEST[$key] = $val;
}

$fichier = $_GET['jpg_png'];

$nom = basename($fichier);
 header("Content-disposition: attachment; filename=$nom" );
 header("Content-Type: image/jpeg" );
 header("Content-Transfer-Encoding: binary" );
 header("Pragma: no-cache" );
 header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0" );
 header("Expires: 0" );
 readfile($fichier); 
?>

Merci pour tout.
 
WRInaute passionné
je te conseille déjà d'utiliser la fonction realpath pour récupérer le vrai chemin du fichier (sans ../). après tu utilises un preg_match pour vérifier que c'est dans le bon répertoire avec la bonne extension.
 
Nouveau WRInaute
forty a dit:
je te conseille déjà d'utiliser la fonction realpath pour récupérer le vrai chemin du fichier (sans ../). après tu utilises un preg_match pour vérifier que c'est dans le bon répertoire avec la bonne extension.

Merci pour ta réponse,

Je suis un débutant en php, tu pourras m'expliquer comment mettre ces fonctions en place ?
 
WRInaute passionné
tu peux déjà essayer de comprendre comment elles marchent : -http://fr.php.net/realpath
et -http://fr.php.net/preg_match

pour vérifier que le fichier est dans le bon répertoire avec la bonne extension tu peux utiliser :
Code:
if (preg_match('/^' . preg_quote('/home/tonsite/le_bon_repertoire/', '/') . '[a-zA-Z0-9]+\.jpg$/', $fichier)) {
...
}
ce code va vérifier que le nom du fichier est de la forme /home/tonsite/le_bon_repertoire/unnom.jpg avec "unnom" qui ne peut contenir que des lettres ou des chiffres.
 
Nouveau WRInaute
Merci pour ces explications, j'ai essayé la condition "if", elle ne marche pas si je met le répertoire, en revanche si je ne met pas de répertoire ça marche, c'est bizarre non ?

Ce code marche :
Code:
if (preg_match('/^' . preg_quote('', '/') . '[_a-zA-Z0-9-]+\.jpg$/', $fichier)) {
$bla = $bla2;
}

Le code qui ne marche pas :

Code:
if (preg_match('/^' . preg_quote('/home/tonsite/le_bon_repertoire/', '/') . '[_a-zA-Z0-9-]+\.jpg$/', $fichier)) {
$bla = $bla2;
}

J'ai vérifié à plusieurs reprises le chemin et le nom du fichier, tout est bon, mais ça ne marche pas :(
 
WRInaute passionné
tu peux aussi passer en paramètre que le nom de fichier et ajouter toi même le répertoire. C'est plus simple et plus sécurisé.
dans ce cas tu vérifies qu'il n'y a que des caractères autorisés dans le nom de fichier et la bonne extension :
Code:
if (preg_match('/^[_a-zA-Z0-9-]+\.jpg$/', $parametre_image_sans_répertoire)) {
    $fichier = '/chemin/du/repertoire/image/' . $parametre_image_sans_répertoire;
    //ton traitement
}
tu peux aussi baser le chemin par rapport au répertoire du script courant avec dirname(__FILE__) :
Code:
$fichier = dirname(__FILE__) . '/image/' . $parametre_image_sans_répertoire;
 
Nouveau WRInaute
Bonsoir,

Merci beaucoup ça marche super bien, et pour sécuriser encore un peu les choses et cacher les variables sans pas par GET ou POST, j'ai opté pour la fonction $_SESSION pour véhiculer mes variables :).
 
Discussions similaires
Haut