Я создаю приложение, которое позволяет пользователю POST
данные холста 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>
, а если нет, что можно сделать для дальнейшей проверки данных изображения?
Одним из способов сделать это было бы фактически создать файл изображения из данных 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; } ?>
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; }
Если вы используете 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; }
Поскольку у меня недостаточно комментариев, я публикую обновленную версию кода thewebguy. Это для людей, принимающих такие услуги, как Heroku, где вы не можете хранить изображения.
Кредит за указание обтекания потока на Пекку ( ответ Пекки )
Этот код предполагает, что вы реализуете оболочку класса и потока из: PHP-пример для 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; } ?>
с<? $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; } ?>
с<? $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; } ?>
Я надеюсь, что это помогает кому-то.
$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'; }