I'm implementing image upload solution.
Now that everything works fine, I started thinking about security.
After researching much on internet, I found that safest way to upload image it recreate it.
For that I use GD Image Editor, which gets image size and resizes it to -1px from every side.
The problem which rose is that I cant recreate GIF image, as it becomes static (and ugly).
My question is, if anyone has done something and what options I have? Maybe some other solution to safely allow users to upload GIF imagies?
First and most important thing is to assign your own filename and extension to any uploaded image. Since your webserver decides on what to do with your file depending on it's extension, you should make damn sure it is '.gif'.
Renaming the whole file and not only it's extension ensures noone finds a ways break your extension safety and inject his own extension.
Never rely on any mime type sent to determine file type. Mime types can be manipulated and are not reliable. If you HAVE to check your file, use something like getimagesize(). But again, this is not necessary if you set the filename and extension anyways.
http://www.php.net/manual/en/function.getimagesize.php
You should also ensure file size is not to large to avoid your server running out of space.
Ensuring a login before uploading and only allowing a reasonable number of uploads per user is also a nice safety agains running out of space.
So, in short:
Set filename and extension
Dont rely on sent filename
Dont rely on sent mime type
check maximum filesize
ensure user can not spam files
Related
I want to have an upload system on my website, where users can only upload images.
These images will be resized by PHP directly on upload, so the original image will not be stored.
Do I still have to worry about scripts like php, etc. executing from malicious images?
You still have the following attack vectors to consider:
The uploaded image will be stored for a certain time on the server and could be used for evil if there are bugs in your application.
Any byte trash uploaded as the image might trigger bugs in your resize code that reads the uploaded image, so it is important to stay up to date with this software or library.
Apart from that, the generated image should be considered safe.
Update:
Uploading images with PHP always results in a temporary file being created somewhere, possibly in an unknown "temporary file directory" location that everyone else on a shared host is also using. This file has a file name and possibly the malicious content. Although the filename is randomly generated, an attacker might be able to guess it and try to use it. On the other hand, you cannot protect yourself from this built-in php mechanism other than not to use unsafe include/require statements, because usually an attack requires a) getting evil code on your server and b) executing it.
Steps against it seem obvious: Configure a dedicated upload directory for your php. Secure it against code execution on the filesystem level by applying appropriate rights and restrictions. Don't mess with the random name generation. Keep this directory out of DOCUMENT_ROOT.
The second attack might be that an attacker tricks your code into reading a non-uploaded nonpublic file with the intent to reveal it's content. So it is a very good idea to check if the filename inside $_FILES really is an uploaded file before proceeding.
I am using a simple file upload script. The script allows file type filtering but I am unsure as to what files I should allow/disallow.
What file types should I prevent from being uploaded?
You should only allow types you need (whitelist). You never know what could change about your server, php, or types of files people can create and what they can do to a server.
It seems there is no reason to possibly sacrifice security in exchange for less type checking.
Found THIS (put in .htaccess):
php_flag engine off
which 'turns off' php, so the file cannot be ran! Then you can allow upload of whatever you want
(thanks to Pekka for link)
The mime provided in $_FILES is sent from the browser thus it is not safe to trust it.
There are other function to determine mime of the file but note, that most of them rely on the file extension. This is a poor way to determine it as I can easily rename .exe to .png and the functions will report that it's an image. I am not sure of your needs but you could limit the script to allow only image files and check if they're really images with imagemagick or gd libraries.
No file is dangerous to server as it is. However, if there is a flaw in the security that would allow to run user files ANY file might be a potential threat.
I suggest not to deny some file types but to allow a couple that users might want to upload.
Don't make a blacklist. Instead, make a whitelist of the allowed file types.
I've got a site that accepts user-uploaded files (images, pdfs, word docs, etc.) then allows other users to download them.
I realize this presents a security risk, since malicious users could upload scripts etc. that masquerade as useful files.
My question is this-- is it enough to check the mime type of the file being uploaded using PHP (mime_content_type or finfo) and set the file to read only (non-executable), or must I also store the uploaded files in a directory that is outside the web root? I would think this would eliminate most of the risk from the uploaded file, but I'm not sure. Performing a virus scan on uploaded files is not possible in this situation.
Thanks for input.
A common practice is to upload files outside the document root, and typically using randomized filenames which are then mapped to the correct item/object/post in the database. If additional permissions are needed to access the files, make sure you check them before allowing downloads, and of course you'll have only authenticated users uploading.
Fileinfo finfo_ is useful for validating most mimetypes, at least to verify that something called ".txt" is actually a text file and not a binary blob, or that a ".jpg" really appears to be a jpeg based on its first few or last few bytes. It may require some extra work sorting out MS Office mimetypes, as if I recall correctly, they all come out as application-msword. But you can then use the file extension to figure out what it is really supposed to be (xls, ppt, doc, etc).
A PHP script then supplies the downloaded file, rather than the web server directly serving it. For that reason, you should store the mime type along with it, so that you can serve the appropriate headers.
header("Content-type: application-whatever");
header("Content-length: size-of-the-file-in-bytes");
I can recommend you use every tool at your disposal to test for the file type. But know that there are other ways a hacker can implant a dangerous file.
Your best bet is to have the files be uploaded to a different server. One that can only host files.
I would check the mime type of the file but I wouldn't rely on this. Even if the file is a full blown .gif and contains a comment in its id3 tag which is a php, it can be executed with a local file include. A safer approach would be store files in the database using a long blob datatype. However this kind of overhead is crap.
The best solution from the perspective of security, scalability and perforce would be to use a no-sql database like CouchDB.
A few things to keep in mind, don't trust $_FILES[]. $_FILES['type'] could be anything the attacker wants so there is no point in checking it from a security perspective. And $_FILES['name'] could have nasty input like ../../../. Its best to rename files to the primary key and then store information about that file in a relational database (like mysql).
I use the PHP language for file upload and want to know that the following method that I use is secure or not?
I am using simple method for file uploading,
I check the file name from $_FILES['userfile']['type']
and then if it's having an allowed file extension, I upload the file with some random number.
Like if it is abc.zip it may become 8w43x9d.zip.
Please tell me: is it a really bad method for file upload?
Randomly-generated safe filenames are definitely a good thing. However if you allowing the file extension through to the webroot you'll still need to ensure that the extension is something that won't cause any problems on the server, such as .php (OK, PHP handling should be disabled in the web server for upload directories, but still). There are also problems if you are on a Windows server, where trailing dots and spaces will confuse the filesystem; make sure you lock down the extension to a few ‘known good’ values.
Unfortunately the ['type'] property cannot be relied on at all. Some browsers won't fill a content-type in, others will put the wrong type because their OSes are set up badly (an infamously unhelpful one is that IE on Windows by default calls JPEG image/pjpeg), some will always say application/octet-stream or even text/plain.
Even the ['name'] property is unreliable; apart from browsers lying or obfuscating the value, there's always the chance a given type will have an unexpected file extension on that particular machine. Or, for Mac and Linux clients, it's entirely possible an uploaded file won't have an extension at all (or may even have the wrong extension for the type the OS sees it as).
So yeah, this is all a bit of a mess. Whilst sniffing for type from the Content-Type submission or filename extension can be useful to guess what default type a file should be, it's entirely unreliable, so it's a good thing to provide a manual method to choose the type of a file in addition. Alternatively, if you are serving the uploaded files as attachments (eg. through a PHP script setting Content-Disposition: attachment), you can often get away with just calling everything application/octet-stream and letting the user sort it out when they save it.
If you're not serving as an attachment, you may have a security problem. IE will happily sniff many filetypes you serve it for <html> tags and treat those files as HTML even if you tell it they're something else. Then it can display them inline in the browser, and lets them inject script into your security context. If you have anything significant in your security context, such as user accounts and cookies, that's a cross-site-scripting security hole. The workarounds for this are serving as attachment and/or serving from a different hostname that is not in your main site's security context (typically, a subdomain is used).
Allowing users you don't completely trust to upload files to your server turns out to actually be a much more difficult task than the trivial example code in PHP tutorials would lead you to believe. :-(
From the PHP Manual:
$_FILES['userfile']['type']
The mime type of the file, if the browser provided this information. An example would be "image/gif". This mime type is however not checked on the PHP side and therefore don't take its value for granted.
I wouldn't trust anything the user or user's browser sends me.
If you're trying to learn, I would take a look at existing secure sources, such as HTTP_Upload from PEAR. You might even consider using the Beta version.
Addition to above post, we are relying on FileInfo or SplFileInfo, so far it has proven to be the best option for our needs.
OK, in case of images we can use getimagesize($_FILES['userfile']['tmp_name']);
and can validate them but what in case of ZIP, RAR and PDF files?
i check the file for its extension, and mime type - is there anything else i can be doing to help make file uploads safer?
its for an avatar (so all the images are in one folder). i was thinking about using htaccess to forbid any php execution just incase some php file found its way in there. what do you think?
Neither file extension nor mime type can give you 100% security that you are dealing with a image file. But as long as you're not going to execute the file (e.g. by using include()), that is not a problem and you do not need to check for PHP code or anything else. The only security breach imaginable using a forged image file would be something that exploits the browser's rendering engine. This is impossible to protect effectively against from server side and is the browser vendor's responsibility.
So, as long as you make sure you use is_uploaded_file() and move_uploaded_file() when handling the upload, you should be fine, at least on the image format front. Make sure you read #bobince's post below and follow the link, it contains a bunch of great information on other security aspects when dealing with files.
You could however, to provide totally maximum security, of course copy the image into a new image container using GD's imagecopy. This would erase any ID3 and other header information contained in the file, and probably destroy any exploit attempts (GD would probably choke on such a file and return an error). This works for GIF, JPEG, and PNG only, of course, and you may run into some issues like alpha channel and colour profile problems.
Never use user-submitted filenames at all; make up new ones like «random number».jpeg. ‘Sanitising’ filenames is harder than you think, especially if the app needs to be able to run on a Windows server.
For images, use the PHP getimagesize function to determine the filetype of an image, rather than looking at the highly-unreliable filename and mimetype submissions. Disallow uploads that don't parse as images.
For files that are intended to be downloaded, use the Content-Disposition: attachment header to stop IE sniffing for HTML content and displaying it in the browser.
For files that must display inline you'll have to serve them from a different hostname to your main site, otherwise HTML content inside them can cross-site-script into your security context.
Making a file upload feature secure is hard. More discussion.