Asking user to upload images or using remote images - php

I'm working on a portal that requires users to upload the images which wil be shown in a certain HTML pages. What should be the good practice here ?
Should I avoid uploading and ask users to give their own URL for the images ?
Ask users to upload image files.
Since we know, an image can be a deadly one if it contains code injection, but what about the remote ones, are they secure ?
Thanks

It depends on your website consistency. Uploading is much better than entering URL for example if the targeted audience is a professional clients they would prefer uploading as it would be difficult to explain to them what is a remote url and how to get it. But uploading is a more traditional way and feels more easy.
On the other hand if most of your targeted audience is internet users then there might be no need to give upload option. But as I said uploading feels much more natural and easy to users. It also depends on the type of images, if the images are the user's avatar then uploading would fit and if the users are adding images to your website to only share images they found from other websites then remote url would be more appropriate.
Both uploading and fetching remote ones to your server could be deadly, but if you use remote ones just to store the urls in your database then it will create no security problem.
So if you want upload feature or storing the remote images to your server you must do some certain steps to ensure the security of your server:
Verify the file extension and mime to be of valid image. (Don't rely only on this.)
Verify it's a valid image file (using php getimagesize)
Resize and copy the image into a new image object. And store that image into your server.
The folder where you are going to store must have all kinds of code executions disabled by using .htaccess (SetHandler default-handler)

Well, it depends on the nature of the project.
In fact any method could be fine, but you should validate and filter the user input.
There is a lot of options to validate a file if it is an image or not.
The getimagesize() function from php could be mentioned as an example, since every image file has to have a resolution and other relevant data.
There are other questions on SO here which answer yours too, you just need to take a look.
Validate image file php

In addition to Ghulam Ali's suggestions:
Make sure to sanitise the filenames. Best is to generate new filenames for user uploaded media.
Have the upload directory with only writable user permissions but that might lead to some complications.
Apart from tackling the security issues, you will also need to figure other important stuff such as orientation as media taken from a mobile device may have random orientations.

Related

What is the best practice for distributing static content via PHP?

This is a best practice question regarding how to handle user uploads and distribute static content to a large number of concurrent users.
I have an upload form for images (png, jpg, gif) and other forms of multimedia (mp4, webm). The files are created, hashed, and stored in storage/app/attachments/ as their hash with no extension.
The request URL /file/md5/filename (such as /file/9d42b752ecd0e3b4542aeca21c7c50a9/dancing_cat.gif) will distribute the file with that name. The route is completely flexible, so replacing dancing_cat.gif with boring_cat_dancing_poorly.gif will still fetch the same file, but will distribute it with the new filename specified.
The point of this system is to stop duplicates from being uploaded while preserving the original name of the document that the uploader had. Other instances of the same file uploaded will also keep their name.
The code I have for this works, however, people raise issue with distributing static content through PHP. I am told that on my large, target platform, this system will work poorly and will immediately become a bottleneck. I am told I should use routes in Apache/nginx/Lighhttpd/whatever webserver to try and serve the static file directly by capturing the request URL before it hits PHP, but that may cause issues with mime types (i.e. an image won't render correctly).
My question is: What is the best practice for achieving what I am doing? How would a big website handle distributing static, user-uploaded content while avoiding a "PHP Bottleneck". I am early enough into my project to consider major rewrites, so please be as informative as possible.
I hope im clear whats the problem but, you may try to hash your current user name and file name plus file extension with sha1 or any shorter encoder wich generates a hash and its barely hard to generate same hash with theese combinations and add that generated hash to file name saved in ur dir. for example
/file/9d42b752ecd0e3b4542aeca21c7c50a9/gifhse3peo40ed-user_photo.jpg
You may then distribute hashes per user for example creating specific folder for specific user to save his uploads so when user reuploads any file the code will know where to save vice versa.
Hope it helps!

CMS upload picture files security issue

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.

What is the best way to upload and store pictures on the site?

I have no idea how the big websites save the pictures on their servers. Could any one tell me how do they save the pictures that are uploaded by the users in their database?
I was thinking, maybe they would just save the file(the picture) in some path and just save that path in the databse is that right?
But I want to do it this way. Is this right? For example, a website named www.photos.com. When a user uploads a picture I would create a folder of the user name and save those pictures in that folder.
I believe we can create a directory using php file concepts. So when a new user uploads his picture or file, I want to create a directory with his name.
Example: if user name is john, I would create a directory like this on photos.com www.photos.com/john/ and then save all his pictures to this directory when he uploads a picture. Is this the right way to do this?
I have no one here that has good knowledge of saving the files to servers so please let me know how to do this? I want to do it the correct and secure way.
All big websites don't save pictures to the database they store them in the disk.
They save a reference to the picture's position in a table. And then link from there.
Why? Performance.
Pulling heavy content from a database is a huge performance bottleneck. And databases don't scale horizontally that well, so it would mean even a bigger problem. All big sites use static content farms to deal with static content such as images. That's servers who won't care less about your identity.
How do they keep the pictures really private you might ask? They don't.
The picture's link is, in itself, the address and the password. Let's take Facebook, for example. If I store a private picture on my account you should not be able to open it. But, as long as you have the correct address you can.
This picture is private. Notice the filename
10400121_87110566301_7482172_n.jpg
(facebook changes the url from time to time so the link may be broken)
It's non sequential. The only way to get the picture is to know it's address.
Based on a previous user photo you can't guess the next one.
It has a huge entropy so even if you start taking random wild guesses you'll have an extensive amount of failures and, if you do get to a picture, you won't be able to, from there, realize the owners identity which, in itself, is protection in anonymity.
Edit (why you should not store images in a "username" folder:
After your edit it became clear that you do intent to put files on disk and not on the database. This edit covers the new scenario.
Even though your logic (create a folder per user) seams more organized it creates problems when you start having many users and many pictures. Imagine that your servers have 1T disk space. And lets also imagine that 1T is more or less accurate with the load the server can handle.
Now you have 11 users, assume they start uploading at the same time and each will upload more than 100GB of files. When they reach 91GB each the server is full and you must start storing images on a different server. If that user/folder structure is followed you would have to select one of the users and migrate all of his data to a different server. Also, it makes a hard-limit on a user who can't upload more than 1T in files.
Should I store all files in the same folder, then?
No, big-sites generally store files in sequential folders (/000001/, /000002/, etc) having an x defined number of files per folder. This is mainly for file-system performance issues.
More on how many files in a directory is too many?
It is usually a bad idea to store images in your database (if your site is popular). Database is, traditionally, one of main bottlenecks in most any application out there. No need to load it more than necessary. If images are in the filesystem, many http servers (nginx, for example) will serve them most efficiently.
The biggest social network in Russia, Vkontakte does exactly this: store images in the filesystem.
Another big social network implemented a sophisticated scalable blob storage. But it's not available to the public, AFAIK.
Summary of this answer: don't store blobs in the database.
is this the right way to do
Yes.
The only thing I'd suggest to use not name but id.
www.photos.com/albums/1234/ would be okay for starter.
Image management may best be achieved by physically uploading images to the server and then recording file location and image details in a database. Subsequently, a Search Form could be configured to permit the user to do a text search, part number search, or other queries. A PHP script could be written to produce a valid HTML image tag based on data found in the table.
uploading images into a MySQLâ„¢ BLOB field is such a bad idea such image data is generally problematic if the images are much larger than thumbnails. If the images are large, you can end up having to copy/paste one SQL INSERT statement at a time (into phpMyAdmin). If the images are large and the SQL INSERT statement is broken into two lines by your text editor, you'll never be able to restore the image.

Can something "bad" happen via img src?

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=j&#X41vascript: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.

How do I handle image management (upload, removal, etc.) in CakePHP?

I'm building a site were users can upload images and then "use" them. What I would like is some thoughts and ideas about how to manage temporary uploads.
For example, a user uploads an image but decides not to do anything with it and just leaves the site. I have then either uploaded the file to the server, or loaded it to the server memory, but how do I know when the image can be removed? First, I thought of just having a temporary upload folder which is emptied periodically, but it feels like there must be something better?
BTW I'm using cakePHP and MySQL. Although images are stored on the server, only the location is stored in the dbb.
Save the information about file to MySQL, and save the last time the image was viewed - can be done via some script that would be altered everytime the image is being used.. and check the database for images not used for 30 days, delete them..
You could try to define a "session" in some way and give the user some information about it. For example, in SO, there is a popup when you started an answer but try to leave the site (and your answer would be lost). You could do the same and delete the uploaded image if the user proceeds. Of course, you can still use a timeout or some other rules (maximum image folder size etc.).
I'm not sure what does "temporary upload" mean in your app. The file is either uploaded or not, and under the ownership of a user. If a user doesn't want to do anything at the moment, you have no other choice but to leave the file where it is.
What you can do is put a warning somewhere on your image management page about unused images, but removing them yourself seems like a bad practice (at least from the user perspective).
As a user,When I upload the image to a server(assuming I want to use it later) and leave the site, I don't expect it to be deleted if I am a registered user.
I would prefer it to be there in my acct until I come back.I would suggest thinking in those lines and implementing a solution to save the users' images if possible.
Check the last accessed/modified time of file to see it if has been used.

Categories