2012-09-30 39 views
17

Tôi đang tạo ứng dụng cho phép người dùng POST dữ liệu canvas HTML5 sau đó được mã hóa trong base64 và được hiển thị cho tất cả người dùng. Tôi đang xem xét phân tích cú pháp dữ liệu thành tệp .png thực tế và lưu trữ trên máy chủ, nhưng tuyến đường cơ sở cho phép tôi lưu trữ hình ảnh trong cơ sở dữ liệu và giảm thiểu yêu cầu. Các hình ảnh là duy nhất, ít và trang sẽ không được làm mới thường xuyên.Xác thực hình ảnh được mã hóa base64

Một chút jQuery sẽ mất dữ liệu canvas, data:image/png;base64,iVBORw... và vượt qua nó cùng với một kịch bản PHP mà kết thúc tốt đẹp nó như vậy: <img src="$data"></img>

Tuy nhiên, an ninh là nền tảng và cần phải xác nhận các dữ liệu base64 vải để ngăn chặn qua dữ liệu độc hại trong yêu cầu POST. Mối quan tâm chính của tôi là ngăn các URL bên ngoài được tiêm vào thẻ <img> và được yêu cầu khi tải trang.

Tôi hiện đang có một thiết lập như thế này:

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

Tôi muốn chắc chắn thiết lập hiện tại của tôi là đủ an toàn để ngăn chặn các URL bên ngoài không bị chèn vào thẻ <img>, và nếu không, những gì có thể được thực hiện để xác nhận thêm dữ liệu hình ảnh?

Trả lời

18

Một cách để thực hiện việc này là tạo một tệp hình ảnh từ dữ liệu base64, sau đó xác minh chính hình ảnh bằng PHP. Có thể có một cách đơn giản hơn để làm điều này, nhưng cách này chắc chắn sẽ hoạt động.

Hãy nhớ rằng điều này chỉ thực sự hoạt động đối với PNG, bạn sẽ cần phải thêm một số logic nếu bạn dự định cho phép nhiều loại tệp hơn (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; 
} 

?> 
+0

này làm việc tuyệt vời! Đã chấp nhận. 'imagepng' sẽ ném' đối số được cung cấp không phải là tài nguyên hình ảnh hợp lệ' nếu dữ liệu hình ảnh không hợp lệ, vì vậy tôi đã bọc hàm đó trong câu lệnh 'if' để nắm bắt nó nếu nó không thành công. – ssh2ksh

+0

Bạn có thể sử dụng 'imagecreatefrompng ($ base64)' nếu trả về false, có nghĩa là không phải hình ảnh – mghhgm

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

Vì tôi không có đủ điểm để bình luận, tôi đăng một phiên bản cập nhật của mã thewebguy của. Điều này dành cho những người lưu trữ các dịch vụ như Heroku, nơi bạn không thể lưu trữ hình ảnh.

Tín dụng để chỉ ra dòng wrapper để Pekka (Pekka's answer)

Mã này giả định bạn thực hiện các lớp và dòng wrapper từ: PHP Example on 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; 
} 

?> 

Tôi hy vọng điều này sẽ giúp một ai đó.

3

Nếu bạn đang sử dụng php 5.4+, tôi đã sửa đổi phần trên để ngắn gọn hơn một chút.

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

Giống như nó. Vài ghi chú ... A) '$ valid_mime'argument dường như thừa, và B) điều này yêu cầu thư viện GD được cài đặt - trên Ubuntu:' sudo apt-get install php5-gd && sudo service apache2 restart' –

0
$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'; 
} 
+4

Hãy giải thích giải pháp của bạn và giải thích nó, đặc biệt là vì câu hỏi là 5 tuổi – Sentry

Các vấn đề liên quan