bonecone Posted January 11, 2016 Share Posted January 11, 2016 I'm building an image board and I want to make sure there's no malicious php code inside of uploaded images before they get written to disc, and I want to use IMagick instead of GD because its writeImages method preserves gif animation. I've been testing my code on the example image on this page: (it's just php_info()) http://php.webtutor.pl/en/2011/05/13/php-code-injection-a-simple-virus-written-in-php-and-carried-in-a-jpeg-image/ I've been able to remove the php using GD: $im = imagecreatefromjpeg($_FILES['image_upload']['tmp_name'][index]); imagejpeg($im, $file_path); I just use call_user_func in order to adapt it to different image formats: call_user_func("imagecreatefrom" . $mime_type, $_FILES['image_upload']['tmp_name'][index]) call_user_func("image" . $mime_type, $im, $file_path); But like I said, animated gifs get turned into static gifs this way. So how do I do the same thing with IMagick? Quote Link to comment https://forums.phpfreaks.com/topic/300275-remove-malicious-php-from-image-uploads-with-imagick/ Share on other sites More sharing options...
Jacques1 Posted January 11, 2016 Share Posted January 11, 2016 (edited) Trying to remove “malicious” content from a file is naive, because there are potentially infinite ways of how a file might become harmful in a certain context. The example attack above uses EXIF tags which can easily be removed, but what if the image data itself gets misinterpreted as code? Removing this data would damage the image (regardless of whether the user actually has bad intentions), and even then you cannot be sure that you haven't missed anything. A much more effective method is to not put the files into any executable context: The uploaded files should not be placed in the document root and not be accessible directly. Instead, you'd write a PHP script which reveives the filename (or some identifier), reads the corresponding image from an isolated folder outside of the document root and send the data to the client. To the client, this is just like a plain image file. But for you, it's much more secure, because the files won't ever be executed by the PHP interpreter. Choose a random filename and pick the extension from a predefined whitelist of permitted image extensions (or omit the extension altogether). The filename provided by the client should be treated as metadata and not actually used. Make sure the webserver only executes specific scripts from specific folders (as opposed to the usual “everything that ends with .php” policy). Also make sure to keep permissions at a minimum to limit the possible damage. Note that files may also contain client-side code, so you need to protect your users as well: Serve the files from a separate domain like uploads.yoursite.com. This will prevent many attacks due to the same-origin policy. Use modern security mechanisms like Content Security Policy to prevent execution of code. Edited January 11, 2016 by Jacques1 Quote Link to comment https://forums.phpfreaks.com/topic/300275-remove-malicious-php-from-image-uploads-with-imagick/#findComment-1529447 Share on other sites More sharing options...
bonecone Posted January 12, 2016 Author Share Posted January 12, 2016 The uploaded files should not be placed in the document root and not be accessible directly. Instead, you'd write a PHP script which reveives the filename (or some identifier), reads the corresponding image from an isolated folder outside of the document root and send the data to the client. To the client, this is just like a plain image file. But for you, it's much more secure, because the files won't ever be executed by the PHP interpreter. What do you mean by "sending the data to the client"? I want to be able to display images on the webpage itself, not just open up a save-as dialog-box when the user clicks on a link, or print it straight to the page in the same sort of view as you get when you right-click a picture and select "View Image". What sort of context do you mean? Quote Link to comment https://forums.phpfreaks.com/topic/300275-remove-malicious-php-from-image-uploads-with-imagick/#findComment-1529476 Share on other sites More sharing options...
requinix Posted January 12, 2016 Share Posted January 12, 2016 I want to be able to display images on the webpage itself, not... print it straight to the page in the same sort of view as you get when you right-click a picture and select "View Image".Those are the same thing. Unless you have a weird definition of "display images". Quote Link to comment https://forums.phpfreaks.com/topic/300275-remove-malicious-php-from-image-uploads-with-imagick/#findComment-1529477 Share on other sites More sharing options...
Jacques1 Posted January 12, 2016 Share Posted January 12, 2016 As long as the PHP script serves the image data with the right content type like image/png, it behaves exactly like a physical image. From the client's perspective, there's no difference. You could even use the same URLs by rewriting https://uploads.yoursite.com/images/<ID> to https://uploads.yoursite.com/image.php?id=<ID>. Quote Link to comment https://forums.phpfreaks.com/topic/300275-remove-malicious-php-from-image-uploads-with-imagick/#findComment-1529486 Share on other sites More sharing options...
bonecone Posted January 12, 2016 Author Share Posted January 12, 2016 As long as the PHP script serves the image data with the right content type like image/png, it behaves exactly like a physical image. From the client's perspective, there's no difference. You could even use the same URLs by rewriting https://uploads.yoursite.com/images/<ID> to https://uploads.yoursite.com/image.php?id=<ID>. This would work as an src attribute of an <img>? Those are the same thing. Unless you have a weird definition of "display images". I was talking about the difference between showing the image within the src attribute of an img like so: http://i.imgur.com/DB7MmeW.png or going straight to the images own url like this: http://i.imgur.com/j4HL68G.png The only example I've ever seen of using PHP to directly print an image resource to the screen has been the second one, but I want to do the first. I don't understand how to so this without also making it directly accessible. ie: you can right-click on it and select "View Image" and go straight to its URL. Quote Link to comment https://forums.phpfreaks.com/topic/300275-remove-malicious-php-from-image-uploads-with-imagick/#findComment-1529500 Share on other sites More sharing options...
Muddy_Funster Posted January 12, 2016 Share Posted January 12, 2016 I'm really not understanding what you want to happen here. You want to upload images and then present them to the browser as images, but not have the browser recognise them as images so that it doesn't present the "view image" option in the context menu? Is that right? The "view image" is a function of the browser, it's there as a feature, if you want to block that then just use some JS to rewrite the right click function on the page or, if you are concerned about people disabling JS then make a transparent overlay div to block the mouse from interacting with the image in the browser's viewport. Maybe if you explained what you're actually trying to do here it would help us understand what you are saying? Quote Link to comment https://forums.phpfreaks.com/topic/300275-remove-malicious-php-from-image-uploads-with-imagick/#findComment-1529504 Share on other sites More sharing options...
Solution Jacques1 Posted January 13, 2016 Solution Share Posted January 13, 2016 This would work as an src attribute of an <img>? Yes. Again: A PHP script which serves image data with the right content type behaves exactly like a physical image in every aspect. It's the exact same thing. In the HTTP context, an “image” is really just a URL pointing to image data. Where this data comes from is irrelevant. It might be an actual file served by the webserver, it might be a PHP script reading files from outside of the document root, it might be dynamically generated with no files involved. The client neither knows nor cares. I was talking about the difference between showing the image within the src attribute of an img like so: http://i.imgur.com/DB7MmeW.png or going straight to the images own url like this: http://i.imgur.com/j4HL68G.png As requinix already told you, there is no difference. There cannot be a difference. In both cases, the browser makes a request to the server (unless the image is already in the cache), fetches the image data and displays it. There is no magical “View Image” request in the HTTP protocol. It is possible to suggest to the client that a file should be downloaded, but that's an entirely different feature which none of us has suggested. If you don't believe us, try it yourself. Quote Link to comment https://forums.phpfreaks.com/topic/300275-remove-malicious-php-from-image-uploads-with-imagick/#findComment-1529552 Share on other sites More sharing options...
bonecone Posted January 14, 2016 Author Share Posted January 14, 2016 Yes. Again: A PHP script which serves image data with the right content type behaves exactly like a physical image in every aspect. It's the exact same thing. In the HTTP context, an “image” is really just a URL pointing to image data. Where this data comes from is irrelevant. It might be an actual file served by the webserver, it might be a PHP script reading files from outside of the document root, it might be dynamically generated with no files involved. The client neither knows nor cares. Aaaah, gotcha. Okay thx. I'd already seen code like this before: header('Content-type: image/jpeg'); $image = new Imagick('test.jpg'); echo $image; But I just didn't know it could be placed inside an SRC attribute. I thought it could only be used in order to print something straight to the browser window, just like when you right-click an image and select View Image. Okay cool! Quote Link to comment https://forums.phpfreaks.com/topic/300275-remove-malicious-php-from-image-uploads-with-imagick/#findComment-1529655 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.