http://www.perlmonks.org?node_id=798222

keiusui has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

I have written a Perl script for a website. The script accepts an image submitted by the user. The image is then displayed on the user's profile.

Clearly, there are security issues when accepting an image from a user. Here are some of the precautions I have taken:

  1. Make sure the image is no larger than 1 megabyte.
  2. Make sure the image mime type is jpeg, gif or png.
  3. Save the image on the web server under a randomly generated file name.
  4. Make sure the dimensions of the image is within an acceptable range of pixels. (I use the Image::Size module to determine the dimensions.)
  5. Make sure the user checks the box that says he has permission to upload the file as his image.

My concern is that, even with all those precautions, someone could still embed a virus in the image. How do I prevent this from happening? Should I use a module like Image::Magick to write a new image altogether? Do I need to run a virus check on each submitted image?

Also, are there any other security precautions that I need to take in regards to accepting a user-submitted image?

Thank you so much for your time and help.

  • Comment on security: making sure graphics uploaded by users are safe

Replies are listed 'Best First'.
Re: security: making sure graphics uploaded by users are safe
by CountZero (Bishop) on Sep 30, 2009 at 06:13 UTC
    A good trick might be to randomly change the size, the format or the resolution of the image a few times (of course ending up with the original size and resolution or with a standard size, format and resolution). This is likely to seriously scramble the contents of the file and break any embedded code.

    Especially if you use a "lossy" format such as jpeg the chances of anything hidden in the file to survive will be low.

    Unfortunately it will also reduce the quality of the image, but nowadays, most images have too high a resolution for webpages anyhow and reducing this to a mofre reasonable resolution will also serve the purpose of "destroying" any unwanted payload in the file.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: security: making sure graphics uploaded by users are safe
by Illuminatus (Curate) on Sep 30, 2009 at 01:20 UTC
    I don't know of any way to embed a virus in jpg or png (not totally sure about gif) files that can self-activate. They would require a separate 'activation' trojan, that modifies the local registry first. This would only be a problem to machines already affected by the trojan before retrieving the uploaded image.

    Of course, there are no filters or scanners to identify pornographic or copyrighted materials...

      A bad guy can embed malicious code into ANY file format, even plain text. The real question is: Will it be executed? If the bad guy can make the victim use an application that does not properly check the file it reads, the malicious code will probably be executed. Microsoft has been taught this lession several times, and still there are exploits based on maliciously modified files. This problem is not limited to Microsoft, but Microsoft's software is often the largest target.

      So, what can you do to prevent this happening to your code?

      Simple: DO NOT TRUST YOUR INPUT.

      Validate all input. Treat it as malicious until you can mathematically prove that every single byte of input is correct and not malicious. Refuse to work with input that does not pass the validation. Do not try to auto-correct invalid input. Perl's taint mode can be helpful here, but it is only an automatic tool. It can't prevent all attacks, simply because it is limited to a few critical functions. This is better than what many other languages offer, but it is NOT FOOLPROOF.

      Passing malicious, unvalidated input to another tool (Image::Magick or any other module or external application) to "make it safe" does not work unless the tool is EXPLICITLY designed to validate the input as described above.

      A simple file type detection tool (like file(1)) may be a first step towards validation, but you need to be aware that those tools only test a few bytes of the input to detect the file type. They DO NOT VALIDATE the entire file. For example, the test for the GIF file format just reads the first six bytes and compares them with "GIF87a" and "GIF89a".

      What can you do to prevent attacks to the computers of your users?

      Nothing.

      You can not control them. You don't even know what software they will use. And it is not your responsibility to protect them.

      If we talk about a controlled corporate network, things are a little bit different, and your main job should be to educate your users -- the usual drill: Do not open unknown attachments, do not open unrequested attachments, do not open or execute files of unknown origin, and so on. You should also make sure that all software on all systems is regularely updated. You should remove software whose author repeatedly fails to fix security bugs within a short time. Even if the author is Microsoft or Apple.

      Firewalls are of little use. They are great to separate the malicious internet from a protected network, and they are fine for this job. But you need to open the firewall to access servers on the other side of the firewall, and there the problem begins: If the firewall inspects the content, it needs to know the exact data format to validate it. All firewalls I've seen just scan for known attack patterns, like a virus scanner. That obviously can not work for new attacks. And it is not the job of the firewall. The application needs to validate its input, not the firewall. There are even attacks that target the content scanner of the firewall.

      Virus scanners do not help, for the same reasons. They can only test for known patterns and known behaviours. So, they MUST FAIL for new attacks with new patterns or new behaviours.

      I've bypassed several content filters (combined with virus scanners) simply by zipping a problematic file and sending a hex dump of the ZIP file as plain text instead of the original file. I've even prefixed the hex dump with a small perl script that automatically converted the hex dump back into the ZIP file. The last incarnation was a perl script that automatically generated the self-unpacking hex-dump-perl-script text file. I was even prepared to change the hex dump into a format that looked like plain english text.

      I've seen malware coming through content filters and virus scanners while at the same time harmless and useful files were blocked. So, no, I do not trust content filters and virus scanners.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
        I think you are being a little alarmist here. File formats like jpg and png have no 'executable' aspect to them. They are simply read and displayed. The only way you could make such a file malicious in-and-of-itself would be to exploit some buffer overrun bug within usual rendering software, such as a browser. Since image rendering is pretty basic, this type of situation is highly unlikely to occur.

        The only plausible way to make a jpg/png file malicious is to trick the destination system into thinking that some 'extra' processing is required for the file type. For example, if you modify the registry to change the default behavior associated with double-clicking on a jpg file, so that it is treated differently, then all bets are off. As I originally stated, this requires some other malware execute first.

        Notice I did not include gif format in here. The gif standard allows for animations, which means there is an 'executable' aspect to the file. While I believe the scope of what can be executed within a gif is very limited, I don't know enough about it to say for sure that it could not be hijacked for nefarious purposes

        fnord

Re: security: making sure graphics uploaded by users are safe
by Anonymous Monk on Sep 30, 2009 at 02:44 UTC
    My concern is that, even with all those precautions, someone could still embed a virus in the image. How do I prevent this from happening? Should I use a module like Image::Magick to write a new image altogether? Do I need to run a virus check on each submitted image?

    Yes, and yes, and you should do both under account with limited permission. You should also remove execute permission from image file.

    You should also virusscan the files periodically. A good time would be when you update virus definitions.

    This is reasonably everything that you can do.

Re: security: making sure graphics uploaded by users are safe
by SFLEX (Chaplain) on Sep 30, 2009 at 09:25 UTC
    I use Image::ExifTool for that, it can replace the Image::Size you want to use and has error & warning's for the image files.
    Also supports other file formats.
    I normally us it to read the file and if there is and error of any sorts it gets deleted.

    Run a virus check if you want to, guess it doesn't hurt to be safe.

    What did the Pro-Perl programmer say to the Perl noob?
    You owe me some hair.
Re: security: making sure graphics uploaded by users are safe
by gizzlon (Initiate) on Oct 02, 2009 at 10:41 UTC

    Since it's data it should not be a problem unless there's a bug in the parser.. Of course that happens but unless your site is insanely secure there are probably more pressing problems..

    It might be a good idea to run it through ImageMageick or something once since that, if I recall correctly, fixes a problem with stacking code(?) in GiFs.

    But if there's a parsing bug in ImageMagick you just made their problem your problem.

    Scanning with AV seems kind of useless.. if there's code there wouldn't it be custom?

Re: security: making sure graphics uploaded by users are safe
by dolmen (Beadle) on Oct 01, 2009 at 14:38 UTC
    • 3.5. Check the file with an up to date antivirus
    • 3.6. Use Image::ExifTool. Any warning makes the image suspicious and you must reject it

      ExifTool is not designed to detect security problems in images, so I don't think that exiftool warnings are very indicative of a problem like this. Instead of rejecting any image with a warning, I would recommend removing all metadata from the image with "exiftool -all=". This should also remove any warnings associated with the metadata. If warnings or errors persist after cleaning an image like this, then it would be reasonable to reject the image.

      - Phil Harvey