Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Next Door
    Posts
    2,664
    Rep Power
    171

    How to detect if uploaded file is image or not with php


    1 - Would this be a good idea to validate and make sure that uploaded file is an image:

    PHP Code:
    if(getimagesize($_FILES['file']['tmp_name']))
        {
            echo 
    "Image";
        } 
    2 - Do I have to check an element of the array (width for example)?

    3 - Do I have to wait for file to be uploaded to the server then check the uploaded file and not on "temp"?

    Thanks
  2. #2
  3. Wiser? Not exactly.
    Devshed God 1st Plane (5500 - 5999 posts)

    Join Date
    May 2001
    Location
    Bonita Springs, FL
    Posts
    5,947
    Rep Power
    4033
    Read through this thread on PHPFreaks from a few days ago: Only allowin images to be uploaded
    Recycle your old CD's, don't just trash them



    If I helped you out, show some love with some reputation, or tip with Bitcoins to 1N645HfYf63UbcvxajLKiSKpYHAq2Zxud
  4. #3
  5. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,959
    Rep Power
    1014
    Contrary to popular belief, you cannot make sure that a file is an image. It's impossible.

    What the getimagesize() function does is check the first few bytes of the file for a magic number. This allows it to make an educated guess about the file type. However, that doesn't tell you anything about what the file actually contains. It could just contain random garbage. It could contain malicious code. Nobody knows.

    What's important is how the reader treats the file. If your webserver thinks it's a PHP script (due to the file extension, for example), then all your byte sniffing won't help you, because the webserver will simply ignore those bytes and execute any PHP code included in the file.

    So you must make sure that the files are treated as images. This is usually done like this:

    • Collect the user-defined information about the file (file name, MIME type, dimensions etc.) and store it in the database. Reject obvious garbage.
    • Store the files outside of the document root so that they cannot be accessed directly through HTTP.
    • Use random file names, not the ones provided by the user (to prevent collisions, malicious file names etc.). Use good random numbers, not stuff like time() or rand() something.
    • Create an access script which takes the file name, reads the file and serves the content with the MIME type from the database.
    • Make sure that the files are never ever executed or included in one of your PHP scripts. Be aware that letting people upload files to your server is inherently risky, not matter what you do.
    Last edited by Jacques1; September 19th, 2013 at 07:56 PM.
    The 6 worst sins of security ē How to (properly) access a MySQL database with PHP

    Why canít I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  6. #4
  7. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Next Door
    Posts
    2,664
    Rep Power
    171
    Does everyone (Requnix, Kicken, Dan, E-oreo, Northie, Jesus,...) really do all that (or something like that) when making an image upload?
    Originally Posted by Jacques1
    • Collect the user-defined information about the file (file name, MIME type, dimensions etc.) and store it in the database. Reject obvious garbage.
    • Store the files outside of the document root so that they cannot be accessed directly through HTTP.
    • Use random file names, not the ones provided by the user (to prevent collisions, malicious file names etc.). Use good random numbers, not stuff like time() or rand() something.
    • Create an access script which takes the file name, reads the file and serves the content with the MIME type from the database.
    • Make sure that the files are never ever executed or included in one of your PHP scripts. Be aware that letting people upload files to your server is inherently risky, not matter what you do.


    Jacques1, there are 2 things you should do:

    1 - You really should write and officially publish your knowledge organised in one place and call it https://www.Jacques1.org. Or make it a book and call it Php By Jaques1. I'll buy it and Kicken will too.

    2 - Make your own open source php framework. You can call it J1PFW. That stands for Jaques1 Php Framework.


    This is how CodeIgniter seems to do it, you may not like it:
    PHP Code:
    /**
         * Verify that the filetype is allowed
         *
         * @return    bool
         */
        
    public function is_allowed_filetype($ignore_mime FALSE)
        {
            if (
    $this->allowed_types == '*')
            {
                return 
    TRUE;
            }

            if (
    count($this->allowed_types) == OR ! is_array($this->allowed_types))
            {
                
    $this->set_error('upload_no_file_types');
                return 
    FALSE;
            }

            
    $ext strtolower(ltrim($this->file_ext'.'));

            if ( ! 
    in_array($ext$this->allowed_types))
            {
                return 
    FALSE;
            }

            
    // Images get some additional checks
            
    $image_types = array('gif''jpg''jpeg''png''jpe');

            if (
    in_array($ext$image_types))
            {
                if (
    getimagesize($this->file_temp) === FALSE)
                {
                    return 
    FALSE;
                }
            }

            if (
    $ignore_mime === TRUE)
            {
                return 
    TRUE;
            }

            
    $mime $this->mimes_types($ext);

            if (
    is_array($mime))
            {
                if (
    in_array($this->file_type$mimeTRUE))
                {
                    return 
    TRUE;
                }
            }
            elseif (
    $mime == $this->file_type)
            {
                    return 
    TRUE;
            }

            return 
    FALSE;
        }

        
    // -------------------------------------------------------------------- 



    And how reliable is MIME type returned by getimagesize? How could this go wrong?
    PHP Code:
    $file_data getimagesize($_FILES['file']['tmp_name']);        
    if(
    is_array($file_data) && strpos($file_data['mime'],'image') !== false)
        {
            echo 
    "Image";
        } 
  8. #5
  9. Did you steal it?
    Devshed Supreme Being (6500+ posts)

    Join Date
    Mar 2007
    Location
    Washington, USA
    Posts
    14,066
    Rep Power
    9398
    Originally Posted by Jacques1
    What the getimagesize() function does is check the first few bytes of the file for a magic number. This allows it to make an educated guess about the file type. However, that doesn't tell you anything about what the file actually contains. It could just contain random garbage. It could contain malicious code. Nobody knows.
    Or it could be something that looks like a valid image, considering how getimagesize() also gets
    • Image width
    • Image height
    • Number of channels
    • Number of bits per color

    If it can manage to get all that then you can be pretty confident you have something that will be interpreted as an image.
  10. #6
  11. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,959
    Rep Power
    1014
    Originally Posted by requinix
    If it can manage to get all that then you can be pretty confident you have something that will be interpreted as an image.
    If the webserver thinks it's a PHP script, then it will be interpreted as a PHP script, no matter how many formal validations you've done. Nothing prevents me from creating a perfectly valid image structure with PHP code as the payload.

    The point I'm trying to make is that it's not about "validating" the supposed image file. You need to make sure that it's treated as an image.

    Of course you can "validate" the picture as an additional service for the users. If somebody accidentally uploads a text file, then this will notify them. But formal validation doesn't make the application secure at all, and it doesn't prevent people from uploading garbage if they want to. It's like validating email addresses: gates@microsoft.com is perfectly valid (and it may even exist), but if I enter it into your form, I'm probably lying.
    The 6 worst sins of security ē How to (properly) access a MySQL database with PHP

    Why canít I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  12. #7
  13. Did you steal it?
    Devshed Supreme Being (6500+ posts)

    Join Date
    Mar 2007
    Location
    Washington, USA
    Posts
    14,066
    Rep Power
    9398
    Originally Posted by Jacques1
    The point I'm trying to make is that it's not about "validating" the supposed image file. You need to make sure that it's treated as an image.

    Of course you can "validate" the picture as an additional service for the users. If somebody accidentally uploads a text file, then this will notify them. But formal validation doesn't make the application secure at all, and it doesn't prevent people from uploading garbage if they want to. It's like validating email addresses: gates@microsoft.com is perfectly valid (and it may even exist), but if I enter it into your form, I'm probably lying.
    Then I guess I misinterpreted "you cannot make sure that a file is an image. It's impossible." to mean that it is not possible to tell if a file is an image.
  14. #8
  15. No Profile Picture
    Dazed&Confused
    Devshed Novice (500 - 999 posts)

    Join Date
    Jun 2002
    Location
    Tempe, AZ
    Posts
    506
    Rep Power
    128
    Originally Posted by Jacques1
    Contrary to popular belief, you cannot make sure that a file is an image. It's impossible.
    You can't be sure an uploaded file is an image, but you can certainly protect yourself by breaking down and rebuilding the file contents into a new image via PHP's image functions. With the proper libraries you can even rebuild animated GIFs.

    It's a bit more overhead but then it's only at upload-time. And if the context has you creating thumbnails, you're already half way there.

    If someone tries to exploit the site by providing an invalid image file, either the image building functions will fail or you'll end up with a harmless blank image in the file.

    Originally Posted by Jacques1
    • Create an access script which takes the file name, reads the file and serves the content with the MIME type from the database.
    Agreed, just be mindful of caching. Typically you won't want browsers caching PHP output, but in this case you probably will. Headers will need to be provided explicitly to handle this.

    Originally Posted by Jacques1
    If the webserver thinks it's a PHP script, then it will be interpreted as a PHP script, no matter how many formal validations you've done. Nothing prevents me from creating a perfectly valid image structure with PHP code as the payload.
    Unless I'm mistaken, however, the webserver will only ever think that if you've associated the extension with PHP.

    If someone uploads a .jpg file that has the structure of an image but with PHP within it, even if someone hits it directly through HTTP, Apache isn't going to try to execute it as PHP. In fact doesn't the webserver itself send the mime-type based on the extension mapping you've provided?

    If the above is true then all you need is an extension check to prevent the webserver from interpreting something incorrectly.

    Comments on this post

    • requinix agrees : reprocessing the image is a good idea
    LinkedIn: Dave Mittner
  16. #9
  17. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,959
    Rep Power
    1014
    Again: You can embed PHP code in a perfectly valid image. The file will pass any formal validation or processing you may come up with. If the attacker embeds the code as a comment, you won't even see the problem. There are tools for this, so anybody can do it.

    A perfectly valid image.
    The same image interpreted as PHP.

    Characters and image data are just bits and bytes. They don't have stickers on them saying "I'm text!" or "I'm an image!". Nothing prevents you from embedding ASCII code points in the payload of an image. Some image formats even allow text data explicitly.

    So formal validation does not protect you at all. Just like validating form fields doesn't prevent people from lying, no matter how big your regex is.

    The only reason why you would put so much effort into validating the image is to prevent ugly error messages when the end user opens the image in the browser. If that's your goal, you may do it. But don't do it for security reasons.



    Originally Posted by dmittner
    If the above is true then all you need is an extension check to prevent the webserver from interpreting something incorrectly.
    In theory: yes. But I wouldn't wanna make the security of my whole webserver dependent on the type recognition of some potentially misconfigured Apache setup.

    With an access script, you don't have that risk.
    The 6 worst sins of security ē How to (properly) access a MySQL database with PHP

    Why canít I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  18. #10
  19. No Profile Picture
    Dazed&Confused
    Devshed Novice (500 - 999 posts)

    Join Date
    Jun 2002
    Location
    Tempe, AZ
    Posts
    506
    Rep Power
    128
    Originally Posted by Jacques1
    There are tools for this, so anybody can do it.

    A perfectly valid image.
    The same image interpreted as PHP.
    Heh. I took that PHP-image to run it through my image rebuilding routines to see if the the risk would remain, but that one didn't even make it past the preliminary getimagesize() validation check.

    That isn't to say there aren't ways to get past that check, but now I'm on a mission to see if any can withstand being rebuilt via imagecreate, et al.
    LinkedIn: Dave Mittner
  20. #11
  21. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,959
    Rep Power
    1014
    Not sure what you did, but I can parse the image, resize it etc. just fine.

    Anyway, I don't really understand why this is so hard to believe. The JPEG structure explicitly allows text comments, so you don't even have to mess with the actual image data. You can put any text into the comment: A love letter, your favorite haiku -- or PHP code. The image parser doesn't understand the text.

    If some day the parser rejects the text based on the fact that it's PHP code, than I'll start worrying about computers getting a bit too intelligent. We've all watched Terminator.
    The 6 worst sins of security ē How to (properly) access a MySQL database with PHP

    Why canít I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  22. #12
  23. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2013
    Posts
    11
    Rep Power
    0
    So... Can we remove all comments from every jpg (possibly while we're de-constructing and re-constructing the image), and then save it to our image directory?
    Would that help to negate threats of bad code sneaking in from (at least the) image comments?
    I'd like to hear opinions from all.

    You can't be sure an uploaded file is an image, but you can certainly protect yourself by breaking down and rebuilding the file contents into a new image via PHP's image functions. With the proper libraries you can even rebuild animated GIFs.
    Just to be clear... You said, "uploaded".
    Does the file have to be completely uploaded to our server in order to be de-constructed and re-constructed by PHP's image functions or, like text, can it be modified before it is uploaded and saved to the server?
    I'm assuming that bad things that are hidden in uploaded images can only hurt us if and when the file is opened (by something other than PHP's image functions or the like) while it's on our server.
    Is that correct or am I wrong on that one?

    Great thread, great responses folks.
    I'm gratefully saving this one to favorites for future reference.
    Thank!
  24. #13
  25. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,959
    Rep Power
    1014
    OK, I think there's still a lot of confusion about what the underlying problem is and how to deal with it.

    This is not an input problem. This is not about filtering the file content in order to remove "evil bytes" or something. The risk we're facing is that our webserver could misinterpret the image as a script.

    As long as the webserver interprets the images as images, there's no problem at all. Nobody will get hurt. But if an evil person tricks our webserver into interpreting the image as a PHP script (or any other script), then we have a problem. Because now our harmless image gets treated as an executable file containing commands.

    This is the exact same problem we face when we insert user input into queries or HTML documents: There's no problem as long as the input gets treated correctly (as data). But if it's misinterpreted as a part of the SQL query or the HTML document, then all hell breaks loose.

    We fix this problem by making sure that the user input does not get misinterpreted. We use prepared statements and escape the user input so that it always gets treated as pure data. We do not fix the risk by trying to remove all "dangerous content". That's insane. If this forum worked like this, we wouldn't even be allowed to use the words "DROP TABLE" or "SELECT", because those would be considered "dangerous".

    OK? We do not mangle the images. We do not mess with the comments, we do not remove all bytes that look like code (then we might as well delete the whole image). What we do is make sure that the image actually gets treated as an image and not code. The most foolproof and secure way of doing this is the one I described above. Theoretically, you may skip the fourth step (the access script), but then you have to absolutely definitely make sure that the file is getting a random name and an image extension.
    The 6 worst sins of security ē How to (properly) access a MySQL database with PHP

    Why canít I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
  26. #14
  27. A Change of Season
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2004
    Location
    Next Door
    Posts
    2,664
    Rep Power
    171
    Jaques1

    Have you ever made a website that is currently on line? Would you please post the link here so we could learn by watching what you have done.

    Thanks
  28. #15
  29. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,959
    Rep Power
    1014
    Sorry, but I'd like to keep a little bit of privacy, so I won't post anything related to my name.
    The 6 worst sins of security ē How to (properly) access a MySQL database with PHP

    Why canít I use certain words like "drop" as part of my Security Question answers?
    There are certain words used by hackers to try to gain access to systems and manipulate data; therefore, the following words are restricted: "select," "delete," "update," "insert," "drop" and "null".
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo