I am using some shared hosting and have several websites. Root folder for every website is defined on domain manager. What is need, if it possible, to access some images from another folder that is not i root folder of website.
Example
I have some folder structure
example
demo
pictures
- 1.jpg
- 2.jpg
Some website www.example.com is pointed in folder example, but i have some images that are placed in root of my webhosting in folder pictures, folder pictures are not defined with some domain, i can only access them from FTP. For www.example.com website i need to show pictures that are places in picture folder. I know MODx manager works that way, and i think ot is possible, does somebody knows how?
The main problem here is how does PHP run, i.e. under which user.
Case 1: all your sites run as the same user (e.g. miomir:apache).
Then any of your sites can access all data on all of your sites, just by specifying the path, either absolute or relative (i.e. ../../...). To supply that information from the browser side you need to use a script that will take an URL, say img.php?img=nameofimage, and reply with the image taken not from the script's directory but from somewhere else.
You need to verify user parameters to avoid this trick becoming a vulnerability that gives access to everything on your site. For example check that the file exists, that it is in the appropriate folder (strip any other folder with basename() ), and that it is an image (quick way: getImageSize(), which will also allow you to glean the correct MIME type).
Case 2: your sites run with a different user each.
That is, scripts on www.example.com run as exampleuser:apache, www.foo.com is handler by foouser:apache, and so on.
In this case there is nothing you can do by yourself, and if there is, then the same trick would allow you to read any other customer's site, or allow them to read yours. You so don't want to take your custom to such a hosting company: it's a disaster waiting to happen.
There still is something you can do with your host's approval: ask them to change the user on all of your sites so that it is now the same user everywhere. Then apply case 1. Note that this may impact other things such as database connections (if user identity is not supplied directly from PHP, as it usually is). It shouldn't apply to you, most likely it doesn't, but if you hit some troubles that's the likely cause.
On some systems it will be possible for foouser to allow baruser to "sudo" some functions. This usually requires root (i.e. your host's knowledge, approval and possibly work), but in some setups you can do this by yourself. At that point you will be able to run a script with commands such as cat and copy a file to standard output. While possible, it is messy and not really very performant.
A compromise (still requires your host's approval) is to create a user group (miomirgroup), put some users (exampleuser, foouser, baruser...) in that group, then give group read permission to a folder in your own space to group miomirgroup. For that folder only, PHP will behave as if it was case 1.
Images will need to be placed in a public folder to be accessible. You can do this by placing your images in the public folder, or by placing a PHP script in the public folder that retrieve the "hidden" images and deliver them open request.
Example 1 - Images in the public folder
For example, let's say "/public" is our public www-folder and "/private" is a folder on the FTP server that cannot be accessed from the web.
You can access the /public folder:
/wwwsites/mysite/public/images/hello.png
Link to image: <img src="/images/hello.png">
You cannot access the private folder since the web server does not allow access.
/wwwsites/mysite/private/images/hello.png
Link to image: (not possible)
Example 2 - Retrieving "hidden" images using a PHP script
http://php.net/manual/en/function.imagepng.php
$im = imagecreatefrompng("test.png");
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
create a file img.php in the server from which you want to access images
<?php
//add all the image's names to this array for white listing
$images = Array( "1.png",
"2.png");
if(isset($_GET['image']) AND !empty($_GET['image'])){
$request = $_GET['image'];
if(in_array($request,$images)){
header('Content-Type: image/png');
include_once('/path/to/non-root/folder'.$request);
}
}
now you can access the files using some.thing/img.php?image=1.png
Related
In a PHP app I am allowing users to upload photos. Upon user upload, metadata is stored in the db and images are then stored in a directory on the linux server. I only want these images to be viewable when called through a view so I can verify that the correct party is viewing them. I do not want anyone to be able to just enter a url and view the image.
/site
/framework
/protected /**My PHP site**/
/www
/images /**This is where I am currently storing the images**/
In order to restrict viewing of these images do I need to move the images directory outside of www? If so to where?
What linux permissions should be given on the images directory?
For images that I have stored in my db that I want restricted access to I use access rules within my framework. Can rules such as these limit access to images in a given directory also?
Any info that can be provided as to how to approach this (so I can do further research) as well as answers to the questions above will be very helpful.
For all images in that directory to be denied (they ALL must be access through a script and none of them will have direct access available - ie only your server will be able to access them, and you have apache with mod_rewrite) you can put a .htaccess in that directory like the following:
deny from all
So to answer the questions by number.. ^^
No, the .htaccess will take care of it with the same effect.
You'll need read (+r) for the images for the server.
The framework may have something like that, but it can't prevent direct linking if the image URL is known. Doing it with .htaccess or moving the directory would be the best bet.
In order to restrict viewing of these images do I need to move the images directory outside of www?
No, but that is the most secure option.
If so to where?
Anywhere
What linux permissions should be given on the images directory?
The minimum you need for the server to read from and write to it. Possibly 700.
For images that I have stored in my db that I want restricted access to I use access rules within my framework. Can rules such as these limit access to images in a given directory also?
Since the images are only available via PHP, the PHP can add whatever auth/authz you like.
You could simply use a .htaccess file and restrict people from entering that directory, as well as turn off directory listing just in case.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have been going through the file uploads through various tutorials and sources, found that uploading into root or any folder which is web accessible is a security issue and is advisable to keep the upload folder outside the root.
Now, if someone is on shared hosting server like Godaddy, the user will not be having access outside the root folder.
And if really nothing can be done, how these open source software like Wordpress, Joomla, Drupal keep their uploads securely, and almost very much sure about the security?
The thing is what all has to be taken care, to save data securely on web when the condition is that, we only have option to keep our files within root.
Few checklist which i know for secure file uploads when you are forced to keep your files within the public accessible area are as follows:-
Functions to Check Uploaded File Size and Type.
While storing files rename the file to some random names and track the filename through database, md5 and sha1 is great.
Disable Script Execution with .htaccess.
This is an example for calling the uploaded files:-
// this is just example only to show how we can get the files
$imgfile = $rsPhoto['photo']; // or value from database
list($width, $height, $type, $attr) = getimagesize($imgfile);
switch ($type)
{
case 1: $im = imagecreatefromgif($imgfile);
header("Content-type: image/gif");
break;
case 2:
$im = imagecreatefromjpeg($imgfile);
header("Content-type: image/jpeg");
break;
case 3:
$im = imagecreatefrompng($imgfile);
header("Content-type: image/png");
break;
}
This is an example, it is not about saving few image files and retrieving it, the data's as we all know categorized in crucial elements of any business success.. so when such kinds of critical and important data has to be handled, what all options we have to make things perfect and secure as possible?
References:-
Implementing Secure File Upload in PHP
EDIT 1:
Is it a good idea to permanently redirect the domain to a sub folder of your domain...
So that your root is / but after redirection your root is /main-website/.
So if i keep my upload folder in /upload/, i think it will be assumed as outside the web accessible/public area...??
Hence my domain www.xyz.com points to /main-website/, And the upload folder is out of the scope of this domain...
Just a thought came to my mind so putting it up
Thanks.
I will assume that the uploaded files must be World readable. I will assume too that the file can be of any type: pdf, images (pdf, png, ico), documents (docx, xls), etc
The best solution here (generic that not just applies for PHP projects, but web projects in general) is to add a layer of complexity or a layer of redirection: You will save the file with a custom name self generated in the server, and use a BBDD to store the original file name.
Ok, let's see it by example. Imagine we have this directories:
/ -> Root. Its World Readable
/files -> Where we will store your files. World Readable too.
So, when I upload a file to your site named "foo.png", you will save it to "/files" directory, but you must change the name of my file to a auto generated one[1]. Let's say "1234asd". You must write in a BBDD a new record with the old file name ("foo.png") with the new auto-generated one. So... now, ¿how can I download my file if I don't know the new name?
Well, you must create "/file.php" in you server, that will accept GET parameter called "filename". Then I can do: "/file.php?filename=foo.png" and your code will do the follow:
Search in the BBDD if the file "foo.png" exists. If exists, get the name of the real filename. If not exist just return a 404 HTTP Code.
Then read the file from the direcory "/files/1234asd" and return it to the user
This way, any kind of files can be uploaded to you server (*.php files too), and you are secured, because the files are not accessed directly, but throw you PHP code (file.php).
This offers additional advantages like being able to check if a user have permission to read the file he is requesting (by implementing some kind of simple authentication). If the file is not found instead of return a ugly 404 HTTP code (that it's the correct stuff to do in that case) you can return a custom error message saying "ooops! 404 - The file you request is not available" or something like that.
Note: this solution applies to a files from 0 to maybe.... 10MB-20MB. If you are working with larger files, this solution is not optimal, and another approach should be take.
[1] http://php.net/manual/en/function.uniqid.php
Here's a link to (the google cached text only version) an article that is useful in helping secure wordpress.
http://webcache.googleusercontent.com/search?q=cache:V5RddpaOH4IJ:gerry.ws/2008/10/152/setup-and-secure-your-wordpress-upload-directory.html&hl=en&gl=au&strip=1
(i've linked to the google cache version becuase their site makes my chrome/firefox lock up, text only doesn't).
Basically you put your uploads in a location that only the app can access it (above or outside the web location) and then:
limiting the mimetypes of file that can be uploaded (and validating the files to make sure they don't contain known buffer overruns, exploits like exif poisining, embedded executables, etc)
make sure you aren't allowing parent paths
make sure that your upload path calculation is run server side not through some sort of hidden form field etc
make sure the execute access of your server platform (e.g. php/apache) won't execute in that location
make sure that only the web server (e.g. apache) account has rights to write to the location
make sure your scripts validate the data being posted in the upload
see also: http://codex.wordpress.org/Hardening_WordPress
Beside the methods to check file while upload it to your server like: check extension/mimetype, limit upload size... I have more tips bellow.
When I use shared hosting : turn off php execution in upload folder, you can use htaccess with php_flag=off.
When I have dedicated server: Setup a storage without any script(php) execution and upload file via ftp.
While you may not have access to any other folder outside root, typically on shared hosting you have access to your home directory.
I have tested on a server I have, and I can store files on /home/myuser which may be outside webroot (typically located in /home/youruser/www).
Also, you can use /tmp which is writtable for everyone, but if you do so, do not store sensitive data there, as it is readable by all users of hoster.
I have an application that let users to upload files to server. All files are stored in one directory called Uploaded Files (which has Thumbnails directory inside).
What are the most common ways for preventing users to see these files ? I mean I don't want users to see the files by typing URL like /path_to_website/Uploaded Files/1.png.
On the other side, authorized users should be able to see the files by getting a page that contains paths to files, like: ../Uploaded Files/1.JPG, ../Uploaded Files/2.png, ../Uploaded Files/3.gif. These users should be able to see only the files that appear on the page they got, i.e. I want to prevent them to see ../Uploaded Files/823.gif for example.
Please help to understand how this kind of things are done these days.
Thanks a lot !!
You can move the images into a folder out side the public directory and then stream them in via PHP to the users who are allowed to view them. By using the method detailed in the PHP header() manual for a very basic output (see Example 1).
Otherwise you could put a .htaccess file in the folder containing:
deny from all
if you are running Apache, but you still need to stream it out through PHP.
I have read the following tutorial "Uploading Files To the Server Using PHP"
and have several questions related to the topics.
Q1> The tutorial mentions that
"Note that PHP must have write access
to $uploadDir or else the upload will
fail"
For me, I only allow the user to upload the file after the user has login to the website.
If we set that $uploadDir permission as 777, then everyone can have written permission to that folder. How to avoid this problems?
Also I am using WAMP as my testing bed, can I simulate the same case as a real web server?
Q2> In order to prevent Preventing direct access, the tutorial mentions:
"A better approach is to move the
upload directory away from your web
root. For example, the web root for
this site is:
/home/arman198/public_html/ to prevent
direct listing i can set the upload
directory to /home/arman198/upload/."
Now my problem is that how can I display the uploaded images on other website pages. Since, the upload is not accessible directly anymore? I need to display the uploaded image save personal headshot dynamically on other website page. Is it possible?
Thank you
It's a common problem.
All modern computers have a temporary files directory. On Linux/Unix it's /tmp, on Windows it's usually c:\temp. The OS install will have set permissions on that directory so that anyone can write files there but only privileged users can delete files that don't belong to them. This is where PHP will want to put an uploaded file; your application then has to move it elsewhere (this is the purpose of the move_uploaded_file() function). PHP under Windows may need upload_tmp_dir actually set in the php.ini file.
Once you have an uploaded file, you can shift it whereever you like, including to where the webserver can read it to serve it. The biggest problem with that it is awfully easy to put this directory inside your codebase. Don't do that. As soon as you do anything beyond editing the files inside the directory they are served from, it will be problematic. Trust me: I've dealt with a few times this in code I've inherited. It's easy to let your webserver load files from a location outside your codebase.
The other alternative is to produce a download script. That way the file need not be servable by the webserver at all. One disadvantage is that you don't get to leverage the web server's MIME translation, but then, that lets you control which types of image files are permitted.
For the second question, you can use a PHP script intead of direct access to the directory. Lets name it image.php. Lets assume that it can take a parameter id, like image.php?id=image_id. In that file you can get the id using superglobal array $_GET. Then you can search for images with that Id and just send it as response.
First one I'm not sure, but maybe play with .htaccess file.
And for the first question, try setting your permissions to 775. That should allow PHP to write the file to the directory without giving the general public write access.
I am trying to secure my PHP Image upload script and the last hurdle I have to jump is making it so that users cannot directly excecute the images, but the server can still serve them in web pages. I tried changing ownership and permissions of the folders to no avail, so I am trying to store the images above public_html and display them in pages that are stored in public_html.
My File Structure:
- userimages
image.jpg
image2.jpg
- public_html
filetoserveimage.html
I tried linking to an image in the userimages folder like this:
<img src="../userimages/image.jpg">
But it does not work. Is there something I am missing here? If you have any better suggestions please let me know. I am trying to keep public users from executing potentially dangerous files they may have uploaded. Just as an extra security measure. Thanks!
You want something that's basically impossible.
The way a browser loads a page (in a very basic sense) is this:
Step 1: Download the page.
Step 2: Parse the page.
Step 3: Download anything referenced in the content of the page (images, stylesheets, javascripts, etc)
Each "Download" event is atomic.
It seems like you want to only serve images to people who have just downloaded a page that references those images.
As PHP Jedi illustrated, you can pass the files through PHP. You could expand on his code, and check the HTTP_REFERER on the request to ensure that people aren't grabbing "just" the image.
Now, serving every image through a PHP passthru script is not efficient, but it could work.
The most common reason people want to do this is to avoid "hotlinking" -- when people create image tags on other sites that reference the image on your server. When they do that, you expend resources handling requests that get presented on someone else's page.
If that's what you're really trying to avoid, you can use mod_rewrite to check the referer.
A decent-looking discussion of hotlinking/anti-hotlinking can be found here
Use an image relay script!
To serve a imagefile that is outside the public_html folder you would have to do it by a php script. E.g make a image-relay.php that reads the image that is outside the public html...
<?php
header('Content-Type: image/jpeg');
$_file = 'myimage.jpg'; // or $_GET['img']
echo file_get_contents('/myimages/'.$_file);
?>
Now, $_file could be a $_GET parameter, but its absolutley important to validate the input parameter...
now you can make an <img src="image-relay.php?img=flower.jpg"> to access a flower.jpg image that is located in /myimage/flower.jpg ...
Well, a web browser will only be able to access files and folders inside public_html.
If the public_html directory is the root of the server for your users, Apache cannot serve anything that is not inside/below that dorectory.
If you want a file to be served by Apache directly, you'll have to put it in/below public_html.
I think your misunderstanding is in the fact that if you include an image in an <img> tag, your browser will send the exact same request to the webserver to fetch it, that will be sent to the webserver if you try to open the src url of the image in your browser directly.
Therefore, either both things work, or neither.
There are hacks around, involving a (php or other) script to make sure that an IP that has requested the image has also requested the html page within the last few seconds (which will not work if the user is behind a proxy that rotates outgoing IPs) or by checking the referer (which does not work with HTTPs and also not if the user has referer disabled).
If you want to make sure that only some users can see the image (both via <img> tag and directly), you can put the image outside public_html and have a (php or other) script that verifies the user's credentials before serving the image.
If you are using Apache or lighttpd you can use the X-Sendfile header to send files that are not in the web root(provided you haven't changed the configuration of mod_xsendfile).
To learn more about X-sendfile see this site.
This solution is giving you the best possible performance as PHP doesn't send the file but the server does and therefore PHP can be exited while the files are being served.
Hope that helps.