After reading a lot of articles. I would say, so what should I actually do to secure my site from hack attempts via the file upload?
From these links:
This link says that MIME IS USELESS and that EXTENSION IS THE WAY TO GO. But in the end the 2 parties are just arguing and if I'm correct BOTH agreed to say that both MIME or EXTENSION has a security hole. A lot of hate over there.
This link agrees to say that MIME is also useless AND EXTENSION is also just not FOOL PROOF as HTML or JAVASCRIPT code can be inserted in a GIF image file (or others) and can be misinterpreted by IE leading to a quick backdoor entrance for malicious code(I really wish everyone would just vote to stop the use of IE. Its like it was made to use as a hacking browser.)
This link says to give the file a NON-EXECUTABLE PERMISSION so that no-matter what it is it wont run (but would this protect us from xss/html/javascript/etc. embedded in the images like the one mentioned in the 2nd statement? If giving the file a non-executable permission would protect us from those embedded threats. Would it also protect us from other threats? Are there other forms of hack that can bypass this approach?)
And then there's this link that says "Re-process the image" other methods are just "fun boring for hackers.". Which is kind of in a way a solid way of identifying if the IMAGE is an IMAGE(IMO, cause imagick wont convert a non image right? Not sure. Haven't dive into it yet. Looked deep).
So what is the best and secure way to protect our sites from file upload threats?
If we check for all:
VALID MIME TYPE
VALID EXTENSION
GETIMAGESIZE() CHECK
ENSURE NON-EXECUTABLE PERMISSIONS
REPROCESS THE IMAGE
Would that be enough? For a SAFE SECURE Image File Upload?
mime-type is easy to fake, file extension is easier to fake. Use them if you need a clue on what the file type is, assuming the user is a good guy. Don't rely on it.
My point exactly
Give the file non executable permissions is a good idea. It is useless from a web security point of view. Are your .php files executables? No. Are they still processed by the web server? Yes.
This is the way to go. Open the file with imagick for example. If imagick complains about the file format, then don't keep it.
Related
I have a CakePHP application that allows users to upload images. I am currently using version 2.
My concerned that hackers could embed code in the images and that code then being executed on the server.
Does anybody know if using the image validation methods used on the CakePHP documentation includes security checks for this?
Here is a link that may exaplin better what I am asking.
PHP image upload security check list
Thanks in advance
You may want to first properly elaborate the situation you are concerned about, like, how would code embedded in an image be executed on the server? What kind of code would that be? What does the server / the application do with these images? Just moving them in the filesystem certainly won't do anything, no matter the files content.
CakePHP does not ship with any validation functionality that would check for the integrity/validity of binary image data. Possibly image related validation methods like Validation::mimeType() only do very basic file header checks via PHPs finfo_* or mime_content_type function.
Even if CakePHP would validate the image data structure, people could still embed all kinds of stuff via metadata for example, so if someone managed to include an image in the right context, possibly embedded code could be executed.
As mentioned initially, assess the threat first, then figure the proper defense mechanisms. If you need more security than CakePHPs built-in validation provides, then you'll probably have to process the image and ditch/filter metadata. However, even that may be exploited, properly crafted PNG IDAT chunks for example may even survive processes like resizing/resampling:
https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
I was wondering if you know about any good and accurate PHP library or file I can include in my script in order to analyse the content of X file and then check if it is an especific type like .doc, .docx .jpg, etc.
I know PHP offers a big number of libraries that we could use to check them, but they're not that accurate at all, some just checks the file extension or the file header (they don't even know if the file is broken or not)
What I request is for something very accurate, simple and faster (probably I'm requesting too much) but any link or suggestion will be accepted and appreciated, Thank you!
As far as I know, no such library exists; it also wouldn't make sense to have one.
let's say I have jpeg image I would like to analyse, the headers probably would be okay but the image itself is broken, and when I want to convert them or cut them for thumbnails (with the GD library which is the one I use) the functions (mostly imagecreatefromjpeg) will throw me errors, and in order to create a good thumbnail I need a valid image.
The best place to catch a malformed JPG file with malformed headers is when GD errors out while trying to process it. Just deal with that in a transparent and useful way (= let the user know that something went wrong). Why add extra code that would essentially have to do the same thing?
By handling the error when it occurs, you can also catch issues that a simple analysis of the file wouldn't reveal anyway - for example, GD can't deal with CMYK JPGs. Still, CMYK JPGs are perfectly valid files. Another example is files that are too big to be processed on your server.
Of course, you can do header or size checks beforehand on every uploaded file. But a separate check that goes as deeply as you want it doesn't make sense.
Apart I would like to have it to prevent virus or code injection..
This isn't a realistic goal. What if the library you open the file with to check it is vulnerable to the injection?
Also, injections like this are very rare; library vulnerabilities tend to be widely publicized, and patches quickly provided. Just keep your machine up to date.
If you really need enterprise-grade virus protection, get a server-side virus detection product.
What i did for this was to open the file, read it, and search for the file headers. most of them are available in their wikipedia format definition.
%PDF for pdf, first 4 chars.
%PNG for png, first 4 chars.
Havent seen yet a library to do that.
This question already has answers here:
Security threats with uploads
(4 answers)
Closed 9 years ago.
So I have a client wants a photography site where users can upload their photos in response to photography competitions. Though technically this isn't a problem, I want to know the risks associated with allowing any user to be able to upload any image onto my server. I've got the feeling the risks are high...
I was thinking of using something like this http://www.w3schools.com/php/php_file_upload.asp
If I do let anonymous users upload files, how can I secure the directory the images (and potentially damaging files) will be uploaded into?
if you want to be sure that the image is a real image you can load using gd http://www.php.net/gd
if the gd resource is created correctly then the image is a real image
first detect the mime using:
getimagesize($filename);
then, for example if it is a jpeg load into gd:
$gdresource = imagecreatefromjpeg($filename);
if $gdresource is valid/created without warnings, the image is valid and not corrupted... getimagesize() is (probably) not good enough to detect corrupted images
also, another important note... don't rely on $_FILES['blabla']['name'] because it could contain non valid utf-8 sequences (assuming that you are using utf-8 for example) and it could be a potential attack mechanism, as any user input
so you'll need to validate / sanitize that as well
$originalFileName = $_FILES['blabla']['name'];
$safeOriginalFileName = iconv('UTF-8', 'UTF-8//IGNORE', $originalFileName);
// more additional checks here. for example filename is empty ""
move_uploaded_file(...., $safeOriginalFileName);
also, remember that $_FILES['blabla']['name'] contains the file extension, which may not be correct. so you'll need to strip it out and use the actual correct extension (that you previously resolved using getimagesize() + imagecreatefrom*())
$safeOriginalFileName = basename( $safeOriginalFileName ); // removes the extension
$safeOriginalFileName = $safeOriginalFileName . ".jpg"; // correct extension
hope this helps :)
also as DaveRandom pointed out, don't rely also on $_FILES['blabla']['type'], use instead as I suggested getimagesize() + imagecreatefrom*()
The uploaded file is stored at a temporary location, this location can be found in the $_FILES variable.
When your script accepts the uploaded file, you can use move_uploaded_file() to move it to the location of your choice.
So even the user is anonymous you are in control what to do with uploads and whether to accept them (eg based on content, size, etc.) or not.
Furthermore, the (anonymous) user provides the file and accompanied details. So, if you blindly use these details, your are vulnerable (a user with bad intents is probably providing the wrong details, to make it legit). So, if you need these details, gather them yourself (instead of using $_FILES)!
For more information see the PHP documentation
You will have to research a bit, but mainly these are the main hints:
The basic security you can have is to check actually the image's MIME type and extension. Although this is certainly easy to forge.
Use binary safe functions like readfile(), fopen() and file_get_contents(), I don't remember exactly which ones but there was a few php functions that had security issues handling files, research which ones are and avoid them.
There are some functions out there using preg_match() and similar that will check if there's something similar to a script in the file you are reading. Use them to make sure there isn't hidden scripts. This will slowdown the process a bit as preg_match() can be resource expensive reading big files but it shouldn't be very noticeable
You could also trigger an antivirus to run on the files uploaded as the email services do.
As far as I know the potentially damaging images would normally contain scripting languages, like php code or javascript to try XSS attacks, there are a lot of dangers out there, so I guess you can't guarantee 100% de safety of the files, but keep having a look periodically to see all the new dangers and ways to avoid them.
I have a quick question if anyone could help. I am building a CMS for a client where they can log in, and change content (including pictures via upload file form) that are all stored in a database.
My question.. I have been researching, and everywhere says I need to store the image files outside the root folder. Is this necessary in my case if only a few people will be uploading files, inside an admin panel, where they must first log in to the site? I will have already taken steps client side by making sure of file type, size, extension etc... then changing the name of the file before adding it to my DB... Is this secure enough, or am I asking for trouble down the road?
Thanks
Its generally a good idea to store uploaded content someplace where it cant directly be addressed by a browser. You dont want someone uploading a .php file (or some other format you forgot to check for) and then being able execute it by pulling up the direct url. Rather, you'd have a wrapper script that delivered the file.
So yes, its a good idea, but not 'necessary' (by the dictionary definition of the word). You can certainly choose not to do so if in your judgement the admin area is otherwise secure.
That said, in the scenario you describe, as long as its only admin users who can upload images, I dont think its a huge deal either way.
btw, if you are not already, verify the images by their file headers or content, not file extension.
I know, I know, title is quite bad, but I'll try to explain what I mean here. So, I ask my members to show their photos. They upload it somewhere, then paste their photos' URL into input and I save it to my database (MYSQL). Then, the photo is being seen on their profiles. I get the URL from database and do something like that: <img src="<?=$photo;?>" height="123px" width="123px">"> where $photo is URL taken from MYSQL. Is it totally safe? Can somebody upload for example .php file and harm my website? Do I need to check if URL's ending is .gif, .png, .jpg?
Thank you.
Edit: Yeah, of course I would protect my website from SQL injections and XSS attacks. But is there any way to harm my website in other way?
What you described may be vulnerable to an XSS (Cross-site Scripting) attack. Essentially, a nefarious user may be able to inject javascript code that could do bad things, while executing as your site.
For an example of this attack vector, check out: http://jarlsberg.appspot.com/part2#2__stored_xss_via_html_attribute
EDIT: It sounds like you are already protecting yourself agains SQL injections and XSS, and you are wondering if there is some way for someone to inject PHP code into your site. I don't think this is possible, since your server-side code will not be executing this string. You are simply instructing the client browser to download an image from a URL.
It may be possible for someone to link to an image file that is infected with a virus, which would then infect other visitors to your site, but it would not affect the site itself.
No, it's not safe at all, XSS attacks can be executed through image tags.
A simple example would be:
<IMG SRC=jAvascript:alert('test2')>
http://www.owasp.org/index.php/Cross-site_Scripting_%28XSS%29
One thing you should consider - I could link you my "XUltra highres" image with about 200 megs. I guess this could break the loading experience of your site (depending on the design).
So beside "script attacks" is allowing users to link content into your site always problematic.
A couple of things to do are to validate that it is a real image in an accepted format (tpyically jpg,png and gif), and sanitize and change the filename.
You can use the PHP getimagesize function to check if it's a valid picture, and which format. You receive the alleged MIME type when the file is uploaded, but that is useless for validation. So, the following should work as the getimagesize function also validates images and returns the exif type.
$image_info=getimagesize($tempname);
$allowed_types=array(IMAGETYPE_PNG,IMAGETYPE_JPEG,IMAGETYPE_GIF);//these are actually the integers 1, 2 and 3
if(in_array($image_info[2],$allowed_types)){
//image is a valid image. You can also check the height and width.
}
In your upload processing, giving your file a new unique name that you have chosen is a good idea, and then you don't have to worry about them doing anything strange with the filename.
Edit:
I noticed you are referring to users supplying a URL to an image.
The answer I gave related to accepting, storing and displaying images users upload to your server.
The same principles apply, though, for displaying a URL of an image. You can get the image via cURL or fopen, save it to a temp file, and then check if it's really an image as described above. This can also catch the user linking to a non-existant or invalid image, so you could warn them. Also, enforce a filesize/dimension limit - you don't want someone linking to a 5 GB picture in their profile (though it would be their own bandwidth problem) as that could inconvenience your other users. The user could always change the file to something else later on, though. You could check once every x hours and warn people who are doing something suspicious, but that seems like a lot of effort on your end.
You can also enforce file name rules, say no unicode in file names, and the name must not include <>''""# -, which are characters that are rarely in legitimate image URLs.
Assuming you're already sanitizing for SQL injection. You need to prevent the user from doing something like this:
<img src="http://usmilitary/launchAllNukes?When=Now" />
or:
<img src""<script>//Evil code</script>" height="123px" width="123px" />
There's no point in checking the file extension, as that doesn't guarantee it's not processed by a script. GET requests (as used by img src) should be safe, and should not cause a major state change (e.g. purchase, delete user, etc.). However, there are buggy sites that do so.
Thus, the safest solution is to require users to upload the image to your site. If you do allow remote images, you should at least require the http or https scheme.
Before inserting into the db, use imagemagik to validate that the photo is a real image, not something else, and you should be OK.
If you allow users to specify any URL as a profile image, an attacker could exploit that to facilitate a denial of service attack against a smaller website. Its impact to the targeted website is equivalent to being slashdotted. For example, an attacker could change his/her profile picture URL to a large resource hosted on the targeted website. Each time a visitor to your site sees the attacker's profile, the targeted website wastes bandwidth serving the resource to the visitor.
A solution to this would be to only allow profile picture URLs that link to image hosting sites.
Strictly speaking - yes. I can post an image in your site that is hosted by my server.
<img alt="Kobi's Photo" src="http://example.com/photo.jpg" />
Seems innocent enough, but in fact, every visitor in your site, watching my image, can be tracked and recorded. Every visitor will get a session in my server, and and can even be given a cookie (not the fun kind). To make things even worse, I can track every page view of your visitors that displays my photo - the browser sends each url where the photo is display via the referer header.
By letting people hosting their own photos, you give away some privacy of your visitors.
Besides what the others have said regarding nefarious intentions, the only other issue I can see is if the image is of something really horrible, but then that can happen on any website where you can upload images.
If you actually allow the users to upload images, you can check the mime type (PHP's getimagesize() function can give you this information). This is not bulletproof either, but better than just checking the extension.
By uploading "somewhere", will you be hosting the files on your webserver?
There are lots of potential issues:
<img src="http://hacker.ru/badtimes.php" />
<img src="javascript:alert(String.fromCharCode(88,83,83))" />
Plus, specially-crafted jpgs can infect users machines:
http://www.microsoft.com/technet/security/bulletin/ms04-028.mspx
You could use a regular expression to filter the url in the PHP. That way you could prevent javascript tags being called and specify the valid file extensions.