Beefy Boxes and Bandwidth Generously Provided by pair Networks Bob
The stupid question is the question not asked

Security issues when allowing file upload via CGI

by George_Sherston (Vicar)
on Dec 06, 2001 at 20:14 UTC ( #129949=perlquestion: print w/ replies, xml ) Need Help??
George_Sherston has asked for the wisdom of the Perl Monks concerning the following question:

I want to give users the option to upload one or more modest-sized files to my site which can then form part of their "personal" space. In principle all I want to do is what the Monastery does with Monk images. My question is, is this a security minefield or not?

So far as I can see, it's not. Because when I save the files from my CGI script, I can make sure they are chmod to 555 or less. So this is just an inert file (of a defined maximum size, otherwise I didn't accept it) sitting on my hard drive.

If somebody else downloads it and then opens it, I can see that might give them trouble, and ideally I'd like to be able to disinfect the files when they arrive on my hard drive, for protection of others. But caveat emptor is the bottom line, and my main aim is to be certain the files aren't going to do anything to me. And I'm not quite certain.

Can any sibling monk think of a way to mess me up by uploading a file to my site under the conditions I've described?<

George Sherston

Comment on Security issues when allowing file upload via CGI
Download Code
Re: Security issues when allowing file upload via CGI
by davis (Vicar) on Dec 06, 2001 at 20:32 UTC
    You would want to make sure that you disallow execution of any file that the user uploads, otherwise the user could just upload a file that punts out your passwd file or whatever.
    But off the top of my head, I can't see it being a major problem....
    /me waits to be corrected :-)
(ichimunki) Re: Security issues when allowing file upload via CGI
by ichimunki (Priest) on Dec 06, 2001 at 20:33 UTC
    I don't see why they need to be chmod to 555, I think 644 is probably more appropriate for data files. This allows the process to write them and everyone else to read them. 555 allows everyone to execute them, which means all I have to do is upload a script to your server and the fun begins.

    Beyond that, no... you can't really prevent someone from uploading an .exe file to your system, but without it saying .exe at the end I suspect MS Windows isn't going to do anything meaningful with it-- and without the correct content-type header many other browsers aren't going to treat it correctly either. And if you upload an .exe as a .jpg, it's likely to get served back as a JPEG which won't display since the exe data is not in the correct JPEG format. If a hole existed whereby my browser was fed an unexpected file and then ran that file willy-nilly, it would have been exploited more than Outlook by now.

      never underestimate the stupidity of IE and outlook.

      if you take an html file, name it foo.jpg and send it with a mime-type of image/jpeg, IE 5 on the mac and IE 4 on windows will happily parse and render it as html. (probably some versions of outlook exhibit this broken behavior too).

      this technique was once used in a hotmail exploit. email someone a "jpg" and it could grab their password cookie and submit it to another site.

      if securityfocus hadn't changed the structure of their bugtraq archives and broken my bookmarks, i could give you a link...

      i don't think it's quite dumb enough to run an .exe the same way but there's still a lot of mischief that can be done with html+javascript/vbscript

      anders pearson

        Roger that!!

        Had it not been for Micro$oft's feature-laden behemoths, (and their commensurate security patches, and security-patch patches, and so on, new ones of which seem to be required almost daily), nevermind OS-related issues, there might never have erupted as pervasive an anti-virus cottage industry as we have (which has since become a full-fledged industry).

        I think you should quarantine uploaded files and run the shell command,

        file {upload filename}

        on them to confirm they are what they purport to be.

        use File::Basename; sub validate_image _file { my $fn = shift; my %file_types = ( jpg => 'JPEG file', jpeg => 'JPEG file', gif => 'GIF file, v8[79]' ); my $ext = lc (fileparse $fn )[-1]; # get suffix return 0 unless exists $file_types{$ext}; my $file_cmd_output = `file $fn`; chomp $file_cmd_output; return 0 unless $file_cmd_output =~ /^$file_types{$ext}$/; # OK, we probably have what we think we have # go ahead and make it accessible, etc. accept_file( $fn ); # ... or whatever return 1; }

        Update: The expectation here is that before this subroutine is called, a file has already been uploaded (ostensibly one whose name ends in .jpg, .jpeg, or .gif) and "quarantined" -- that is, stored somewhere "safe", out of harm's way -- and that the parameter, $fn, to the sub is the full path to this file.

        (Thanks, nufsaid, for bringing up the issue of the tainted-ness of $fn)


        Just call me the Anti-Gates ...
Re: Security issues when allowing file upload via CGI
by Fastolfe (Vicar) on Dec 06, 2001 at 20:50 UTC

    With a pre-defined list of acceptable file types, you can ensure that the file extension is what you expect, but even that isn't enough, as MSIE frequently second-guesses the web server-provided MIME type. A more thorough solution would be for you to use something like File::MMagic to ensure the contents are of a pre-defined acceptable MIME type as well.

    Unfortunately, short of installing a virus scanner in line with this process, or on a system constantly scanning new uploads for known viruses, there is no easy way for you to catch every conceivable piece of malicious data. Even explicitly allowing, say, JPEG images only, can still open you up to some vulnerabilities with carefully crafted JPEG code.

    Another caveat is getting the file someplace "local" to that user. Be wary of using user-provided variables to determine the location on a filesystem a file should reside. See Sanitizing user-provided path/filenames if this is the case here.

    I might also use umask instead of explicitly calling chmod to make changes to the permissions of the file.

    And lastly since this feature of your site inevitably opens you up to the potential for scripting vulnerabilities (users uploading data with HTML and/or JavaScript that will be executed in the context of your own site), you should be careful with the nature of the cookies you send to the user to avoid potentially sharing this with evil-doers. You should make sure nobody else can steal someone's cookie and pass it off as one of their own, for instance.

Re: Security issues when allowing file upload via CGI
by sparkyichi (Deacon) on Dec 06, 2001 at 22:13 UTC
    I would be careful about how the file is transferred. You do not want the user to include directory structures in the file name (such as ../../../../../file.ext). This could be a very bad thing. In this situation I would think that it is best to error on the side of caution. There is to great a possibility to introduce a security hole. Dont forget to taint check.

      There is no control there in how it is transfered, assuming it is POSTing it from a web form. It's browser dependent, and browsers send differnt sorts of things. So you have to munge the filename anyways. But you want to do it anyways, because different OSes have different filename standards.

      in my web upload scripts, I use this:

      $filename =~ tr{:\\}{/}; # convert mac and windows directory sep +erators to unix style $filename =~ s{.*/}{}g; # strip everything before the last sepe +rator $filename =~ s{[^\w\-\.]}{}go; # remove funny characters

      Snazzy tagline here
Re: Security issues when allowing file upload via CGI
by atcroft (Monsignor) on Dec 06, 2001 at 22:57 UTC

    The only major issues I see with it are: (a) making sure that quotas on the system are maintained, (b) permissions issues, and (c) potentials for liability for downloaded content. I am assuming there would also be a need for an authentication system to permit only users on the system to upload.

    Quotas: You need to test that the files uploaded fall under the user's quota. I saw a system once that datafiles created by a CGI were owned by the user the webserver ran as, which resulted in them not appearing properly in the user's quota. You also will want to make sure that the user (and group, on systems with that feature) they show up in are correct, and have quotas in place, to prevent someone from filling the site or group's quota, or in the worst case, the partition or drive itself.

    Permissions issues: On a *nix system, 644 would likely be the better permission to use. (For reference, the first place in the number is the permissions for the owner, the next for the group, the last for others on the system, and the value is the sum of the permissions, where 4 is read permission, 2 is write permission, and 1 is execute permission.) On other systems, permissions should be set so the uploaded data is not executable on the server. IF you are allowing users to upload CGI scripts, then that will be a special case, needing EXTREME care.

    Download issues: Others above in this thread have made cases regarding when others download the content, so I will not repeat poorly their comments. Issue is, though, that any website can wittingly or unwittingly contain harmful content (which partially depends on your definition of "harmful"), and all you can reasonably be expected to do is try to make it more difficult for someone to post something intentionally.

    In my own experience (which may or may not prove applicable to you), I had to set up a system for submitting files to a site that would notify the site owner of the submission. My solution was to have the uploads go to directory that was readily visible from the site, rename the file and set it non-executable, owned by the site owner's user/group, and send the site owner a link to the file, along with the name the submitter suggested. Beyond that, as a coder, I could only advise the site owner to use caution in dealing with the files.

    Something else you may wish to look into, which I have heard of but never tried, is loading the content into, and pulling it from, a database. Of course, this is only if that would be appropriate for said content, and as always, YMMV.

Re: Security issues when allowing file upload via CGI
by archimago (Pilgrim) on Dec 06, 2001 at 23:01 UTC
    for images, you can use Image::Magick's ImagePing method to very quickly learn if it is a valid image or not
Re: Security issues when allowing file upload via CGI
by jbert (Priest) on Dec 06, 2001 at 23:03 UTC
    You didn't mention the magic word, "taint".

    Depending on how you open the file, special characters in the filename can do dodgy things.

    e.g. if you passed it to a shell script, a filename of: "foo.jpg;rm -rf /" could ruin your day.

    As could "../../../../../../../etc/passwd", come to think of it, if someone uploaded their own passwd file. ( it won't be running as root. In that case "../../../../../home/guest/.rhosts". Whatever. Use your imagination.)

    Basically, turn on taint checking and then work out which characters you want to permit (don't try and make a list of bad characters). A reasonable policy might be alphanumeric plus a maximum of one '.' character. Maybe underscores if you feel generous :-)

    One other issues you may have (but probably not, if your size limits are small) is the problem of being used as a file exchange. This problem plagues anonymous FTP servers which allow upload. If you aren't careful you end up being an exchange point for the exchange of warez and/or nasty kinds of porn. (I've seen this happen to an FTP site not far from where I am sitting).

    Does this damage you? Depends on how well you are believed by your local law authorities when/if someone complains.

    Your defence here is to log all transfers and/or personally inspect uploaded content before making it available on your site. Small file size limits also make this unattractive to evil-doers.

    Basically this is one area where the urge to genericise your code should be resisited. You have a particular use in mind (sharing text files, uploading jpgs to perlmonks etc). If you can detect mis-use (is this a binary file? If this a valid JPG?) then you should probably try and do so...

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://129949]
Approved by root
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (4)
As of 2014-04-20 21:35 GMT
Find Nodes?
    Voting Booth?

    April first is:

    Results (488 votes), past polls