Jump to content

Verifying an image IS an image


phppup
 Share

Recommended Posts

Secret doing some reading too educate myself, I am now more confused than before. LoL

Trying to understand the most effective method to verify that an image is truly what is claimed.

But the differences between using imagecreate, imagecreatefromjpeg, and is_uploaded_file are not easily noticed.

Likewise, I read that it is best to check the image BEFORE uploading. But isn't the image already uploaded when submitted (although not yet moved or renamed)?

Link to comment
Share on other sites

1 hour ago, phppup said:

But the differences between using imagecreate, imagecreatefromjpeg, and is_uploaded_file are not easily noticed.

imagecreate: Create a new image
imagecreatefromjpeg: Load a JPEG from a file
is_uploaded_file: Check that the file path given was truly from a file upload

Very, very different.

 

1 hour ago, phppup said:

Likewise, I read that it is best to check the image BEFORE uploading. But isn't the image already uploaded when submitted (although not yet moved or renamed)?

If you can, yes. Saves the user from uploading a file that is going to be rejected. But you still have to verify it in PHP.

For validation, examine with getimagesize.
For sanitization, load the image into memory and resave it to file.

Link to comment
Share on other sites

My confusion deepens.

It seems as if imagecreate and imagecreatefromjpeg would be cousins, with ...from jpeg being more appropriate for validation.  Am I correct in assuming that each extension needs is own ...createfromXYZ for accurate info?

is_uploaded_file seems as if it's çlosing the barn after the horse has escaped.  If it returns FALSE, but already has a tmpname, isn't the damage already underway? Does not working/moving the particular file "save the day"?

So we're talking non-PHP coding to validate BEFORE upload (if I choose to be ultra user-friendly?

I appreciate your help, but regarding getimagesuze, PHP.net has a CAUTIONARY note stating: 

Quote

Do not use getimagesize() to check that a given file is a valid image. Use a purpose-built solution 

Thus, my confusion escalates.

Link to comment
Share on other sites

37 minutes ago, phppup said:

It seems as if imagecreate and imagecreatefromjpeg would be cousins, with ...from jpeg being more appropriate for validation.

imagecreate creates a brand new image with nothing in it. I want you to spend the rest of the day thinking how that could help you validate an image file.

imagecreatefromjpeg is great for loading an image file, but only when you know it's a JPEG. A more versatile function is imagecreatefromstring because it can detect the image type, but you have to load the file's contents into a string.
Is there a "imagecreatefromfile" that's like imagecreatefromstring but works on files directly? No. Why not? :psychic:

 

37 minutes ago, phppup said:

Am I correct in assuming that each extension needs is own ...createfromXYZ for accurate info?

See above.

 

37 minutes ago, phppup said:

is_uploaded_file seems as if it's çlosing the barn after the horse has escaped.  If it returns FALSE, but already has a tmpname, isn't the damage already underway? Does not working/moving the particular file "save the day"?

That function is a safeguard to make sure you don't accidentally try to process a file somewhere on the server. If you throw in that check then you can be sure the filename is truly an uploaded file your script just received.

 

37 minutes ago, phppup said:

So we're talking non-PHP coding to validate BEFORE upload (if I choose to be ultra user-friendly?

Yes.

 

37 minutes ago, phppup said:

I appreciate your help, but regarding getimagesuze, PHP.net has a CAUTIONARY note stating: 

Thus, my confusion escalates.

It can guess at what type of image is contained in a file. It does not also then validate that the rest of the file is a valid image.

For sufficiently small images, getimagesize to detect image type + imagecreatefrom(format) to load into memory + image(format) to save to a new location.

Link to comment
Share on other sites

Quote

 

Quote

 

Is there a "imagecreatefromfile" that's like imagecreatefromstring but works on files directly?

No. Why not?

Because as long as you know the type of file your chasing, you can select the appropriate imagecreatefrom... command!

(Not gonna ask what happens if you use the wrong one... LoL)

Quote

For sufficiently small images...

I was planning to resize images AFTER the upload. So image size is an unknown.

With that in mind, I will try to maximize the allowable file size, but I'm guessing even that has limitations (regardless of my intentions for the new file)?

Link to comment
Share on other sites

1 hour ago, phppup said:

Because as long as you know the type of file your chasing, you can select the appropriate imagecreatefrom... command!

My point is that there is a function to load any supported image type from a string, so why not a function to load any supported image type from a file too?

 

1 hour ago, phppup said:

(Not gonna ask what happens if you use the wrong one... LoL)

Error message and no image.

 

1 hour ago, phppup said:

I was planning to resize images AFTER the upload. So image size is an unknown.

But there are still going to be guidelines. Or do you want to be able to support images up to many MBs in size?

 

1 hour ago, phppup said:

With that in mind, I will try to maximize the allowable file size, but I'm guessing even that has limitations (regardless of my intentions for the new file)?

The only limitations with limiting file size are the limitations on the file size. Not sure what you're getting at.

One thing to remember is that loading an image into memory with functions like imagecreatefromjpeg will use a lot of memory. A 1MB file does not mean 1MB of memory. It means quite a bit more than that. So if you aren't careful, someone could upload a 10MB image and have your PHP script crash with OOM errors because it tried to use, I dunno, 200MB of memory to hold the image. Because the size of an image file does not correlate with the size of the image it contains: I can create a <100KB GIF file that is 10000x10000px in size, and if each pixel required a mere 10 bytes of memory to represent then that's 1GB of memory needed to load it.

Link to comment
Share on other sites

Posted (edited)
Quote

My point is that there is a function to load any supported image type from a string, so why not a function to load any supported image type from a file too?

I'll take a stab at this and say that a string becomes somewhat universal, but a file has stricter parameters that dictate it's handling.

I would also suspect that while the average user accepts whatever file is afforded, there are probably pros and cons from an artistic/ photo/ graphic perspective and different image file types offer quality and access benefits.

Quote

Because the size of an image file does not correlate with the size of the image it contains

Would an enormous overload of memory generally be a maliciously inspired? Or simply a by-product of a particular image's content?

Will resizing an image to a smaller file size automatically reduce it's maximum display size? It's color quality? Pixel saturation?

I've not truly figured out what is being reduced and how the file is effected.

So if an image file is stored in a db (not my intention, but I've seen many examples) is the file stored or is it translated into a string?  Is the 'size' of a string generally smaller than the image file it supports?

Edited by phppup
Typos
Link to comment
Share on other sites

3 minutes ago, phppup said:

Would an enormous overload of memory generally be a maliciously inspired? Or simply a by-product of a particular image's content?

Yes.

 

3 minutes ago, phppup said:

Will resizing an image to a smaller file size automatically reduce it's maximum display size? It's color quality? Pixel saturation?

I don't know what "maximum display size" is supposed to be, but reducing an image will always have some effect on the image depending on the image.

 

3 minutes ago, phppup said:

So if an image file is stored in a db (not my intention, but I've seen many examples) is the file stored or is it translated into a string?  Is the 'size' of a string generally smaller than the image file it supports?

If you store the file in the database then the file is stored in the database. Whether it's a "string" or not is debatable but the answer is basically "yes".

The size of a PHP string is exactly equal to the size of the file. Please, think about that question until you arrive at the same conclusion yourself.

Link to comment
Share on other sites

Posted (edited)
Quote

Would an enormous overload of memory generally be a maliciously inspired? Or simply a by-product of a particular image's content?

Yes to both, huh?  Interesting

Quote

string is exactly equal to the size of the file.

Got it.

I suppose every pixel is individually represented.

I wasn't sure if the inner workings of an image allowed for coding that might say "each corner is black" or "top half is blue."

A few lines of code can create miles of resulting data, but I guess an image file is more literal in it's formatting.

Although there must be a differentiation somewhere down the line.  A camera can be set to take the same photo at different file size or different quality settings (what's the best combination when trying to budget a memory card?)

And yet, the same photograph will produce a different file size when created in raw, jpg, or others. But that's probably a different chapter. LOL

Edited by phppup
Typos
Link to comment
Share on other sites

41 minutes ago, phppup said:

I wasn't sure if the inner workings of an image allowed for coding that might say "each corner is black" or "top half is blue."

Nope. At least not the typical image formats - I wouldn't be surprised if SVG could do that, but that's a special image format that doesn't work like the others.

 

41 minutes ago, phppup said:

Although there must be a differentiation somewhere down the line.  A camera can be set to take the same photo at different file size or different quality settings (what's the best combination when trying to budget a memory card?)

And yet, the same photograph will produce a different file size when created in raw, jpg, or others. But that's probably a different chapter. LOL

It's all about compression. Raw images aren't, JPEG images use algorithms that are very well suited to photographs but will lose some information to do that, PNG images compress in different ways that don't lose information, and so on.

Link to comment
Share on other sites

40 minutes ago, phppup said:

Although there must be a differentiation somewhere down the line.  A camera can be set to take the same photo at different file size or different quality settings (what's the best combination when trying to budget a memory card?)

And yet, the same photograph will produce a different file size when created in raw, jpg, or others. But that's probably a different chapter. LOL

The size/quality variations come down to the different compression techniques and settings one uses.   When the image is decompressed, which it will be when you load it with something like imagecreatefromXXX to do work on it (ie, resize it) then it will be using a certain amount of memory per-pixel so the image size in pixels will give you an idea of how much RAM you need to load it.  A full color image for example may need 32-bits (4-bytes) per pixel when loaded into memory so a 1920x1080 image would need about 8MB of memory even though the compressed file size may only be a few hundred KB.

 

Link to comment
Share on other sites

I've got the is_uploaded_file in place.

Let's assume a user attempts to upload several images and the second file is an empty NOT-uploaded file.

Is it safe to CONTINUE my loop and rename the other files?
Or is it more advisable to BREAK the loop immediately.


Getting back to my initial thread, for file authentication, what is the equivalent to imagecreatefromjpeg for a TIFF file?
What's the best way to handle them to minimize vulnerability?

Link to comment
Share on other sites

10 minutes ago, phppup said:

Let's assume a user attempts to upload several images and the second file is an empty NOT-uploaded file.

Impossible.

The only way is_uploaded_file will return false is if you give it a file path for something that is not $_FILES[something]["tmp_name"]. Which, if it happens, is a sign that the code is very fundamentally broken.

Link to comment
Share on other sites

Quote

foreach ($_FILES['files']['tmp_name'] as $key => $value)  { 

        if( !empty($value) && is_uploaded_file( $value )){
            //FILE is REAL
            return true;
        }

}

Is there a way to test it's functionality?

Best way to ensure a TIFF is truly an image file?

Link to comment
Share on other sites

12 hours ago, phppup said:

I suppose every pixel is individually represented.

No. There are lossless and lossy image compression formats. Both use different methods of storing the data. A RAW image format is one form of lossless image format that has distinct data for every single pixel along with it's color. That is why they are huge in storage space. A gif and jpg (typically) are lossy formats (substitute some fidelity to create small file sizes) but work very differently. A gif has a color palet that can only hold 256 colors. It then defines each pixel in the gif by those colors. I suspect it does some other calculations such as define the pixel at index 1, 1 then also sets a repeat number. E.g. if the first 20 pixels are all the same color, it only has to define the color of the first pixel and then another value for the repeater. A JPG allows for 16 million colors but it does it's compression using more mathematical processes. For example, it may shift the color of a pixel slightly in order to make the compression more efficient.

 

17 hours ago, phppup said:

Likewise, I read that it is best to check the image BEFORE uploading. But isn't the image already uploaded when submitted (although not yet moved or renamed)?

What that really means is to verify the image before saving/using it. You can only do so much validation of the image before uploading it. Once it is initially uploaded to the $_FILES array, you an run whatever validations, modifications on them and THEN save them however you choose. I think the problem you are running into is that you are reading different bits and pieces of information, but not understanding the info or WHY you should do those things. It is possible to have a legitimate image that contains malicious code. And, depending on how you use the images on your site, you could potentially risk exposing your users. So, while you should be doing things to ensure what the user provided has a legitimate image extension and PHP can tell it is an image file, a best practice is to recreate the image to remove any potentially malicious content in the image.

Here is an article that explains how these vulnerabilities exist: https://asdqwedev.medium.com/remote-image-upload-leads-to-rce-inject-malicious-code-to-php-gd-image-90e1e8b2aada

Link to comment
Share on other sites

Here is my suggestion:

  1. Limit the size of the images you will accept
  2. Do an initial check on the extension and MIME type of the file and refuse anything that is not what you expect
  3. Use getimagesize() to verify it is an image.
  4. Resize/recreate the image. This will remove some/most malicious code.
  5. Change the name of the image
  6. Set the folder(s) where you store the images so files cannot be executed
  7. Don't allow direct access to images. E.g. when displaying the images on a page use something like <image src="getimage.php?id=5"> and create the script getimage.php to find the image based on the id (or whatever parameters you define) and pass the image contents back to the browser to be displayed. This way the malicious user won't even know how to access the file he uploaded.
Link to comment
Share on other sites

And I thought this was gonna be easy. LOL

Is this a correct and effective use for security:

Quote

foreach ($_FILES['files']['tmp_name'] as $key => $value)  { 

        if( !empty($value) && is_uploaded_file( $value )){
            //FILE is REAL
            return true;
        }

}

Does getimagesize() serve any purpose beyond obtaining the MIME type?

How do I re-create a TIFF file?

Link to comment
Share on other sites

Changed my code slightly, but still not getting a successful result

Quote

 

foreach ($_FILES['files']['tmp_name'] as $key => $value)  { 

        if( !empty($value) && is_uploaded_file( $value )){
            //FILE is REAL
            echo "success";
        } else {

            echo "false";

}

Does is_uploaded_file merely confirm that the path described is the same path used?

Does getimagesize() serve any purpose beyond obtaining the MIME type?

How do I re-create a TIFF file?

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.