Formulaire d'upload pas sécurisé

Fermé
loki33 - 30 sept. 2013 à 15:55
Colbi97 Messages postés 564 Date d'inscription mardi 3 mars 2009 Statut Membre Dernière intervention 25 novembre 2015 - 1 oct. 2013 à 10:02
Bonjour, malgré les sécurité que j'ai mise en place sur mon formulaire d'upload j'arrive quand même a y télécharger des fichier php (renommer en jpg). les fichiers ne rentre pas dans ma BDD mais ils vont quand même dans mon dossier "image". comment les bloquer?

voici le code


if(!empty($_FILES))
{
$avatar = $_FILES['avatar'];
$avatar_name = $avatar['name'];
$ext = strtolower(substr(strrchr($avatar_name,'.'),1));
$ext_aut = array('jpg','jpeg','png');

function check_extension($ext,$ext_aut)
{
if(in_array($ext,$ext_aut))
{
return true;
}
}

$valid = (!check_extension($ext,$ext_aut)) ? false : true;
$erreur = (!check_extension($ext,$ext_aut)) ? 'Veuillez charger une image' : '';

if($valid)
{
$max_size = 2000000;
if($avatar['size']>$max_size)
{
$valid = false;
$erreur = 'Fichier trop gros';
}
}

if($valid)
{
if($avatar['error']>0)
{
$valid = false;
$erreur = 'Erreur lors du transfert';
}
}

if($valid)
{
$path_to_image = 'image/image';
$path_to_min = 'image/miniature';

$filename = rand (10000,50000);


$source = $avatar['tmp_name'];
$target = $path_to_image . $filename. '.'. $ext;
$mintarget = $path_to_min . $filename. '.'. $ext;


move_uploaded_file($source,$target);

if($ext == 'jpg' || $ext == 'jpeg') {$im = imagecreatefromjpeg($path_to_image.$filename.'.'.$ext);}
if($ext == 'png') {$im = imagecreatefrompng($path_to_image.$filename.'.'.$ext);}


$ox = imagesx($im);
$oy = imagesy($im);

$nx = 300;
$ny = floor($oy *($nx/$ox));

$nm = imagecreatetruecolor($nx,$ny);

imagecopyresized($nm, $im, 0,0,0,0, $nx,$ny,$ox,$oy);

imagejpeg($nm, $path_to_min.$filename.'.'.$ext);

$nom_image = $target.'' ;
$min = $mintarget.'' ;


$data= array(

'image'=>$nom_image,
'min'=>$min

);

$nb= $DB->insert("INSERT INTO images (image,min) VALUES (:image,:min)",$data);

header('Location:upload.php');
exit;


}
}

merci

6 réponses

Pitet Messages postés 2826 Date d'inscription lundi 11 février 2013 Statut Membre Dernière intervention 21 juillet 2022 524
30 sept. 2013 à 16:09
Salut,

Une solution est de vérifier en plus le type MIME du fichier envoyé.
Pour cela tu peux utiliser une des fonctions suivantes :
- https://www.php.net/manual/fr/function.getimagesize.php
- https://www.php.net/manual/en/ref.fileinfo.php
- http://us3.php.net/manual/en/function.mime-content-type.php (deprecated)

Bonne journée
0
Utilisateur anonyme
30 sept. 2013 à 16:12
Bonjour

Tu vérifies bien le type de fichier, mais tu le recopies AVANT la vérification !
Sois logique, ne le recopie qu'après, s'il est bien d'un des types acceptés !
0
Colbi97 Messages postés 564 Date d'inscription mardi 3 mars 2009 Statut Membre Dernière intervention 25 novembre 2015 12
30 sept. 2013 à 17:44
Bonjour,

Des fichiers php renommés en jpg ?

Là, effectivement, çà va passer ton test sur l'extension sans problème, la vérification du type MIME ne bloquera pas non plus ce fichier (basée sur l'extension aussi, en fait donc quand on change l'extension le type MIME change avec).

La seule solution serait d'ouvrir en lecture avec PHP chaque fichier reçu puis de chercher dedans la présence de balises de début de code (version "normale" <?php comme version "courte <?).

Mais pourquoi vérifier ? Sauf erreur de ma part, sans accès en modification au serveur, le fichier ne pourra pas être renommer pour remettre la bonne extension et donc le serveur web n'interprètera jamais le code contenu. Il y aura juste une image non lisible de stockée.
0
Pitet Messages postés 2826 Date d'inscription lundi 11 février 2013 Statut Membre Dernière intervention 21 juillet 2022 524
Modifié par Pitet le 30/09/2013 à 18:42
quand on change l'extension le type MIME change avec

C'est faux :

<?php
$finfo = finfo_open(FILEINFO_MIME);
var_dump(finfo_file($finfo, 'fichier_php.php'));
var_dump(finfo_file($finfo, 'fichier_php.jpg'));
var_dump(finfo_file($finfo, 'fichier_image.jpg'));
var_dump(finfo_file($finfo, 'fichier_image.php'));
finfo_close($finfo);
?>

affiche

string 'text/html; charset=us-ascii' (length=27)
string 'text/html; charset=us-ascii' (length=27)
string 'image/jpeg; charset=binary' (length=26)
string 'image/jpeg; charset=binary' (length=26)

L'extension Fileinfo de php ne se base pas sur l'extension du fichier pour déterminer le type mime.
0
Colbi97 Messages postés 564 Date d'inscription mardi 3 mars 2009 Statut Membre Dernière intervention 25 novembre 2015 12
Modifié par Colbi97 le 1/10/2013 à 09:12
Ah, OK, erreur de ma part, hier je n'avais pas mon poste de dev sous la main et j'ai répondu après test sous windows (oui, oui, shame on me) et là, sous windows, le fait de changer l'extension fait que l'OS détermine un nouveau type MIME.

Mais c'est vrai qu'avec PHP, il ne se trompe pas...
Et après test sous Linux, il n'y a pas d'erreur non plus, encore une fois windows prouve sa grande supériorité (humour inside)
0
Pitet->Bonjour et merci pour vos liens je vais lire ça! Quel fonction tu me conseille des 3? (la plus utile)

le père-> Bonjour avant de recopier l'image je mets bien la condition if(valid) (qui vérifie que l'extension est ok) donc je comprends pas trop votre remarque?

Colbi97 ->Bonjour , oui c'est ce qu'il me semblait il n'y a aucun moyen pour l'utilisateur malveillant d'activer son script a distance sans accès au serveur mais j'aurais aimé en être sur. donc du coup si je copie le code actuel sur mon site je suis bon niveau sécurité ? sachant que pratiquement tout mon site sera basé sur le partage d'image j'aurais l'air vraiment con si y a des failles!

bonne soirée a vous!!
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Utilisateur anonyme
30 sept. 2013 à 23:35
Toutes mes excuses, j'avais lu trop vite et ma remarque n'est pas justifiée.

Par contre, en lisant plus attentivement cette fois, je vois que tu ne testes pas la valeur de $im. Si le fichier n'est pas une bonne image, ou s'il y a un quelconque problème, $im sera FALSE et il suffit de faire le imagecreatefromxxx à partir du fichier temporaire, et de ne faire le move_uploaded_file qu'après si tout va bien.

Petite remarque :
$valid = (!check_extension($ext,$ext_aut)) ? false : true;
est un façon bien compliquée d'écrire
$valid = check_extension($ext,$ext_aut);


et ce serait bien de ne pas omettre le "return false;" dans check_extension
0
Bonjour, j'ai donc rajouté une sécurité en plus avec getimagesize comme vous me l'avez conseillé au début

         

if($valid){
if(isset ($_FILES['image']) && ($_FILES['image']['error']==0)):
list ($width,$height,$type,$attr)= getimagesize ($_FILES['image']['tmp_name']);

if (is_null($type) && $width==0 && $height==0):
$erreur = 'Votre image est un php petit malin';
$validate = false;

endif;

endif;
}

Et hop miracle mon php renommé en jpg ne passe plus !

Par contre j'ai entendu dire que ce n'était pas efficace contre les gifs avec du code php a l'intérieur?

dans tout les cas les .gif ne font pas partit des extensions que j'autorise au début donc je devrais être ok non?

bonne journée.
0
Colbi97 Messages postés 564 Date d'inscription mardi 3 mars 2009 Statut Membre Dernière intervention 25 novembre 2015 12
Modifié par Colbi97 le 1/10/2013 à 10:07
À priori, oui, l'upload d'image est maintenant sûr, par contre, tu dis : sachant que pratiquement tout mon site sera basé sur le partage d'image.

Dans ce cas, l'utilisation de imagecreatefromjpeg sans contrôle de l'orientation EXIF de l'image n'est pas judicieux car cette fonction ne prend pas en compte l'orientation EXIF des fichiers et par conséquent, une image qui serait tournée en utilisant les infos EXIF (méthode de rotation principale pour les appareils photos) apparaîtra systématiquement dans son orientation originelle.
Pour corriger ce défaut, tu peux utiliser une nouvelle fonction créée comme ceci :
<?php
function imagecreatefromjpegexif($filename)
{
$img = imagecreatefromjpeg($filename);
$exif = exif_read_data($filename);
if ($img && $exif && isset($exif['Orientation']))
{
$ort = $exif['Orientation'];

if ($ort == 6 || $ort == 5)
$img = imagerotate($img, 270, null);
if ($ort == 3 || $ort == 4)
$img = imagerotate($img, 180, null);
if ($ort == 8 || $ort == 7)
$img = imagerotate($img, 90, null);

if ($ort == 5 || $ort == 4 || $ort == 7)
imageflip($img, IMG_FLIP_HORIZONTAL);
}
return $img;
}
?>
Source du script : doc imagecreatefromjpeg sur php.net

Edit : je vois dans ton code
$filename =  rand (10000,50000);
mais tu ne gère pas le cas où ton nombre aléatoire serait le même qu'un nombre déjà sorti (et çà peux arriver plus souvent qu'on le crois...), par conséquent tu risque d'écraser accidentellement des images précédemment uploadées.
0