Подтвердить что ты не робот

Проверка изображений с кодировкой base64

Я создаю приложение, которое позволяет пользователю POST данные холста HTML5, которые затем закодированы в base64 и отображаются всем пользователям. Я рассматриваю разбор данных в реальном .png файле и хранении на сервере, но путь base64 позволяет мне сохранять изображения в базе данных и минимизировать запросы. Изображения уникальны, немногие, и страница не будет обновляться часто.

Немного jQuery возьмет данные холста data:image/png;base64,iVBORw... и передает его вместе с PHP скрипт, который обертывает его так: <img src="$data"></img>

Однако безопасность является краеугольным камнем и требует проверки данных canvas base64, чтобы предотвратить передачу вредоносных данных в запрос POST. Моя основная проблема заключается в том, чтобы запретить вставлять внешние URL-адреса в тег <img> и запрашиваться при загрузке страницы.

В настоящее время у меня есть такая настройка:

$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;

Я хочу убедиться, что моя текущая настройка достаточно безопасна, чтобы предотвратить добавление внешних URL-адресов в тег <img>, а если нет, что можно сделать для дальнейшей проверки данных изображения?

4b9b3361

Ответ 1

Одним из способов сделать это было бы фактически создать файл изображения из данных base64, а затем проверить само изображение с помощью PHP. Возможно, будет более простой способ сделать это, но этот путь, безусловно, должен работать.

Имейте в виду, что это действительно работает только для PNG, вам нужно добавить некоторую логику, если вы планируете разрешать больше типов файлов (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;
}

?>

Ответ 2

Если вы используете php 5.4+, я переработал выше, чтобы быть немного более кратким.

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;
}

Ответ 3

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;
}

Ответ 4

Так как у меня недостаточно комментариев для комментариев, я отправляю обновленную версию кода thewebguy. Это для людей, принимающих такие услуги, как Heroku, где вы не можете хранить изображения.

Кредит для указания обтекания потока на Pekka (Ответ Пекки)

Этот код предполагает, что вы реализуете оболочку класса и потока: Пример PHP для обтекателя потоков

<?

$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;
}

?>

Я надеюсь, что это поможет кому-то.

Ответ 5

$str = 'your  base64 code' ;

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

Ответ 6

привет, ребята, вы можете проверить кодировку base64 кода изображения с помощью функции getimagesize(), просто используйте приведенный ниже код:

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

* замените любой файл любым источником, который вам нужен код base64_encode