web-dev-qa-db-fra.com

Validation des images encodées en base64

Je suis en train de construire une application qui permet à l'utilisateur de POSTdonner des données de canevas HTML5, qui sont ensuite codées en base64 et affichées à tous les utilisateurs. J'envisage d'analyser les données dans un fichier .png réel et de les stocker sur le serveur, mais la route base64 me permet de stocker les images dans une base de données et de minimiser les demandes. Les images sont uniques, peu nombreuses et la page ne sera pas souvent actualisée.

Un peu de jQuery prendra les données de la toile, data:image/png;base64,iVBORw... et les transmettra à un script PHP qui l'encapsule comme suit: <img src="$data"></img>

Cependant, la sécurité est la pierre angulaire et il est nécessaire de valider les données de canevas base64 pour empêcher le transfert de données malveillantes dans la demande POST. Ma principale préoccupation est d'empêcher que des URL externes soient injectées dans la balise <img> et sollicitées au chargement de la page.

J'ai actuellement une configuration comme celle-ci:

$data = (isset($_POST['canvas']) && is_string($_POST['canvas'])) ? $_POST['canvas'] : null;
$base = str_replace('data:image/png;base64,', '', $data);
$regx = '~^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$~'

if ((substr($data, 0, 22)) !== 'data:image/png;base64,')
{
  // Obviously fake, doesn't contain the expected first 22 characters.
  return false;
}

if ((base64_encode(base64_decode($base64, true))) !== $base64)
{
  // Decoding and re-encoding the data fails, something is wrong
  return false;
}

if ((preg_match($regx, $base64)) !== 1) 
{
  // The data doesn't match the regular expression, discard
  return false;
}

return true;

Je veux m'assurer que ma configuration actuelle est suffisamment sûre pour empêcher l'insertion d'URL externes dans la balise <img>. Sinon, que peut-on faire pour valider davantage les données d'image?

21
ssh2ksh

Une façon de procéder serait de créer un fichier image à partir des données base64, puis de vérifier l’image elle-même avec PHP. Il existe peut-être un moyen plus simple de procéder, mais cette méthode devrait certainement fonctionner.

Gardez à l'esprit que cela ne fonctionne vraiment que pour les PNG, vous devrez ajouter une logique si vous prévoyez d'autoriser davantage de types de fichiers (GIF, JPG).

<?

$base64 = "[insert base64 code here]";
if (check_base64_image($base64)) {
    print 'Image!';
} else {
    print 'Not an image!';
}

function check_base64_image($base64) {
    $img = imagecreatefromstring(base64_decode($base64));
    if (!$img) {
        return false;
    }

    imagepng($img, 'tmp.png');
    $info = getimagesize('tmp.png');

    unlink('tmp.png');

    if ($info[0] > 0 && $info[1] > 0 && $info['mime']) {
        return true;
    }

    return false;
}

?>
22
thewebguy

Si vous utilisez php 5.4+, j'ai révisé ce qui précède pour être un peu plus concis.

function check_base64_image($data, $valid_mime) {
    $img = imagecreatefromstring($data);

    if (!$img) {
        return false;
    }

    $size = getimagesizefromstring($data);

    if (!$size || $size[0] == 0 || $size[1] == 0 || !$size['mime']) {
        return false;
    }

    return true;
}
5
curiosity26
function RetrieveExtension($data){
    $imageContents = base64_decode($data);

    // If its not base64 end processing and return false
    if ($imageContents === false) {
        return false;
    }

    $validExtensions = ['png', 'jpeg', 'jpg', 'gif'];

    $tempFile = tmpfile();

    fwrite($tempFile, $imageContents);

    $contentType = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $tempFile);

    fclose($tempFile);

    if (substr($contentType, 0, 5) !== 'image') {
        return false;
    }

    $extension = ltrim($contentType, 'image/');

    if (!in_array(strtolower($extension), $validExtensions)) {
        return false;
    }

    return $extension;
}
3

Comme je n'ai pas assez de points à commenter, je publie une version mise à jour du code de thewebguy. Ceci est destiné aux personnes hébergeant des services tels que Heroku où vous ne pouvez pas stocker d'images.

Le crédit pour avoir signalé le wrapper de flux à Pekka ( La réponse de Pekka )

Ce code suppose que vous implémentiez le wrapper de classe et de flux à partir de: PHP Exemple sur Stream Wrapper

<?

$base64 = "[insert base64 code here]";
if (check_base64_image($base64)) {
    print 'Image!';
} else {
    print 'Not an image!';
}

function check_base64_image($base64) {
    $img = imagecreatefromstring(base64_decode($base64));
    if (!$img) {
        return false;
    }

    ob_start();
    if(!imagepng($img)) {

        return false;
    }
    $imageTemp = ob_get_contents(); 
    ob_end_clean();

    // Set a temporary global variable so it can be used as placeholder
    global $myImage; $myImage = "";

    $fp = fopen("var://myImage", "w");
    fwrite($fp, $imageTemp);
    fclose($fp);    

    $info = getimagesize("var://myImage");
    unset($myvar);
    unset($imageTemp);

    if ($info[0] > 0 && $info[1] > 0 && $info['mime']) {
        return true;
    }

    return false;
}

?>

J'espère que ça aidera quelqu'un.

3
user3376563

bonjour les gars, vous pouvez valider le code de l'image encodée en base64 en utilisant la fonction getimagesize (), utilisez simplement le code ci-dessous:

<?php
$array=getimagesize("data:image/gif; base64 , '.base64_encode('any file').'");
$e=explode("/",$array['mime']);
if($e[0]=="image")
{
echo "file is image file" ;
}
?>

* remplacer n'importe quel fichier avec n'importe quelle source de fichier que vous voulez code base64_encode

1
yashpal singh
$str = 'your  base64 code' ;

if (base64_encode(base64_decode($str, true)) === $str && imagecreatefromstring(base64_decode($img))) {
    echo 'Success! The String entered match base64_decode and is Image';
}
0
Mahdi Bashirpour