How would you implement private images? - php

I'm developping an App in Android which somehow has avatars like Whatsapp do. As you know, in WhatsApp you can create a group, and set a group picture for it.
I don't have any problems on taking the image, saving, etc. The problem I have is that I'm developing the webservice in Symfony2 (PHP) and I want to receive the image and save it somewhere on the server. However, obviously those images are NOT public and should be only viewed for users with permissions. I've thought about traditional method: saving the image on a folder and giving the link or not, but this is totally easy to hack.
So guys, how would you do this? Maybe saving the binary data into MySql directly? Is there any clean way to achieve this?
Any tips are appreciated.
Thanks.

Another answer is to set the mime type of the PHP call to be an image. A call to a URL like http://xxx/images.php?id=8989031289130 would then return an image instead of an HTML file.
You then have access to the PHP security context and can validate whether the user actually has permissions to view this file.
There are some more details at:
Setting Mime type in PHP

The typical answer here is to use a file naming scheme that precludes guessing. For example, you could take the filename plus a secret salt, hash them together, and append the hash to the filename (before the extension). Thus, what would be /foo/bar/baz.jpg would become /foo/bar/baz_8843d7f92416211de9ebb963ff4ce28125932878.jpg.
So long as your hash salt remains secret, filenames are more or less mathematically protected from random or brute-force discovery. This is, for example, the core of how Facebook protects its' users pictures without having to actually require authentication for each image request (which doesn't scale well at all).

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!

Security Logic when storing images outside of root

I have a social network where users can create posts with embedded images. The images are stored outside the document root. When a page is requested for viewing I want to send a normal HTML response with <img> elements that have an src attribute. The problem is, how to efficiently protect the images so that only authorised users can view them?
The permissions system behind the network is quite complex. The social graph has several different types of nodes and edges, and a user's permission to browse content depends on this graph. I consult the user's subgraph once on each page request, to retrieve a list of permitted content, but I don't want to have to consult it again for each image. It's an expensive exercise and some pages may have 50 or more images.
So, as far as I can see, when I serve the page I will need to send a key (or keys) which, when combined with data by the server, will 'unlock' the image. Here's an example of what I mean - in the example I am putting a key in an url, where the url is the src attribute of an image:
http://example.com/images?id=1234_my_image_id&key=1234123412341234FFF
In this implementation I pass a parameter that uniquely identifies the image. I need to do this since I don't want to get in to translation tables, or user-specific translation tables (because of complexity and performance). I also send an 'image key'.
My idea is that the user's session will include a 'session key'. When the server receives a GET for an image, it will add the session key to the image filename requested and hash them (just like password + salt). If the result of the hash equals the image key, I'll retrieve the image from disk and send it.
The problem with this is that if a hacker gets hold of an image url, they have one input to the hash (ie. the image key), and the required output of the hash (ie. the image file name), so they could (using rainbow tables) work backwards to get a list of potential session keys. Then, through a series of requests and a process of elimination, they could establish the exact session key.
So, how do I get around this? I could change the session key with each request, but that would mean that image urls would change with each request, so there will be no image caching.
I'm sure I'm not the first to have this problem. Is there a 'common' approach to the problem? (I can't find such a thing). I could consider base64 encoding the images in the page response, but I'm guessing that would come at a performance cost.
FYI - I'm using PHP and Apache. I'd use url rewriting to tidy things up a bit.
Well I was thinking the same as you did. So get the image id + an user secret, make a hash et voilâ. You got an easy to use system.
But the problems you got is mostly rainbow tables. So possibilities to tackle that issue;
bcrypt and do it like a realy password would be
make it a time sensitive secret, so the secret is only valid for 30 seconds, which could be as simple as hash(hash(secret + time) + secret), although now you have to send the time it was hashed with it too, so not much of a secret there any more
Other solutions that come to my mind
save with the images a list of allowed users, on changes of rights + upload update this list
you could make a function displayImage(id), what it does it renders a <img src="url" /> but also in the background it sets a flag for x seconds to allow the user to access the image.
Once you store your images outside of the root directory, then the only way to view them is to have the code access them. In PHP, that code will look something like...
$file_location = '../../images/' . $some_id_that_is_authenticated_and_cleansed_for_slashes . '.jpg';
readfile($file_location); // grabs file and shows it to user

Best way to store user's avatars

I have a website where users each have their own profile page. Here they can upload a single image that acts as their avatar. This is the only image users can upload to the server across the whole site. There is no archive so it can be overwritten if a user wishes to update their avatar.
I have never had to do anything like this before so I would like to open it up and ask for a suitable, scalable option for this website.
My initial thought is to give each user's image a random name, a string 6-12 characters long. This way you couldn't build a script that just pulls every user's profile pic from a directory (eg 001.png, 002.png etc). My second thought is that there should be only be a certain amount of images per directory to make sure they can be retrieved quickly by the server.
There may well be other things I'm missing here, I'm not sure on exact details hence why I'm asking.
I would recommend storing the images on something like Amazon S3. Depending on how many pictures you're storing, serving images can really take a tow on your web server. S3 is scalable and with multi-zone deployments through CloudFront (Amazon's version of a CDN), you can really speed up this part of your service.
It's good idea to not overload single directory. Very often you can see that images are stored in hierarchy of folders according to theirs first few letters. An example of this is
b5dcv5.jpg -> /b/5/b5dcv5.jpg
bsgb0g.jpg -> /b/s/bsgb0g.jpg
a5dcbt.jpg -> /a/5/a5dcbt.jpg
and so on. I thing you got the principle. Advantage of this is to have access to and image in O(log N) when filenames are uniformly distributed instead of O(N) as it would be in single folder solution.
I've been using base64 to store them within an SQL database. No need to manage files. It works well for relatively low resolution options.
How about not storing them as images at all?
You could leverage an external placeholder for each user, you could cache a random image from lorempixel.com: http://lorempixel.com/100/100. Use an MD5 hash of the user's name or ID. You could also just save the image using the user's ID, for example 442.jpg.

php & mySQL: Storing doc, xls, zip, etc. with limited access and archiving

In my application, I have a provision for users to upload files like doc, xls, zip, etc. I would like to know how to store these files on my website and have only restricted people access it. I may have a group of people and let only these group access those uploaded files. I know that some may try to just copy the link to the document or the file and pass it to another (non-permitted) user and they can download it. So how can I prevent it? How can I check if the request to download the file was made by a legitimate user who has access to the file? The usernames of the group members are stored in the database along with the document name and location in the database so they can access it. But how do I prevent non-permitted users from being able to access that confidential data in all ways?
With the above in mind, how do I store these documents? Do I store the documents in a blob column in the Database or just just let user upload to a folder and merely store the path to the file in the database? The security of the documents is of utmost importance. So any procedure that could facilitate this feature would definitely help. I am not into Object Oriented programming so if you have a simpler code that you would like to share with me, I would greatly appreciate it.
Also how do I archive documents that are old? Like say there are documents that are 1 year old and I want to conserve my website space by archiving them but still make them available to the user when they need it. How do I go about this?
Thank you.
Store them as a BLOB in the database. That way you can associate files to user groups and have security restrictions as you would normally do with users-related websites.
Decided to throw in an answer anyhow ;)
Here's a simple, but I think useful (haven't used it myself, just quickly found it for you) guide to uploading and downloading files to/from databases.
The uploading part of it looks good, but don't use the part of the download section that wants to echo links to the files - I don't think that's what you want. Echo the file contents immediately instead as the tutorial also describes, remembering to set the header.

Restricting access to images on a website

I'm putting together a portfolio website which includes a number of images, some of which I don't want to be viewable by the general public. I imagine that I'll email someone a user name and password, with which they can "log-in" to view my work.
I've seen various solutions to the "hide-an-image" problem on line including the following, which uses php's readfile. I've also seen another that uses .htaccess.
Use php's readfile() or redirect to display a image file?
I'm not crazy about the readfile solution, as it seems slow to load the images, and I'd like to be able to use Cabel Sasser's FancyZoom, which needs unfettered access to the image, (his library wants a link to the full sized image), so that rules out .htaccess.
To recap what I'm trying to do:
1) Provide a site where I give users the ability to authenticate themselves as someone I'd like looking at my images.
2) Restrict random web users from being able see those images.
3) Use FancyZoom to blow up thumbnails.
I don't care what technology this ends up using -- Javascript, PHP, etc. -- whatever's cleanest and easiest.
By the way, I'm a Java Developer, not a web developer, so I'm probably not thinking about the problem correctly.
Instead of providing a link to an image. Provide a link to a cgi script which will automatically provide the proper header and content of the image.
For example:
image.php?sample.jpg
You can then make sure they are already authenticated (e.g. pass a session id) as part of the link.
This would be part of the header, and then your image data can follow.
header('Content-Type: image/jpeg');
Edit: If it has to be fast, you can write this in C/C++ instead of php.
Using .htaccess should be the safest/simplest method, as it's built in functionality of the webserver itself.
I do not know if it fits your needs, but I solved a similar poblem(giving pictures to a restricted group of people) by using TinyWebGallery, which is a small gallery application without database.
You can allow access to different directories via password and you can upload pictures directly into the filesystem, as TinyWebGallery will check for new dirs/pics on the fly. It will generate thumbnails and gives users possibility to rate / comment pictures (You can disable this).
This is not the smallest tool, however I thik it is far easier to setup than using apache directives and it looks better as naked images.
If you're using Nginx, you could use the Secure Link module.

Categories