PHP secure root - php

My friend found a problem in my script, it gives acces to root files.
This url gives passwd file:
http://site.com/attachment.php?file=../../../../../../etc/passwd
How to escape this security hole?

Dont download the files using URL String.... Define unique IDs to denote a file, rather than paths.
You might have seen downloads like this http://www.mysite.com/download.php?id=23423 what they do, use this id, to take out the file name and path from the db and then download it.

There are several different solutions.
If there can be only a filename, a basename() solution would work.
However, if it can be path, a more complex solution is needed
//assume current directory, but can be set anything. Absolute path of course
$basedir = dirname(__FILE__);
//assume our files are below document root.
//Otherwise use it's root dir instead of DOCUMENT_ROOT
$filename = realpath($_SERVER['DOCUMENT_ROOT'].$_GET['file']);
if (substr($filename,0,strlen($basedir)) !== $basedir) {
header ("HTTP/1.0 403 Forbidden");
exit;
}
there is also a useful PHP configuration option open_basedir

You can use realpath() and dirname() to check URLs against $_SERVER['DOCUMENT_ROOT'] (or whatever directory is "safe" for downloading).
If the result of realpath() points outside the safe directory, you can deny the download request.
There's also the open_basedir security directive (and runtime option as of 5.3).

I suppose you have a directory where all attachments are stored.
Just test if file is located in your directory.
// http://www.php.net/manual/en/function.basename.php
// http://cz.php.net/manual/en/function.file-exists.php
if (file_exists($attachments_path . "/" . basename($_GET['file'])) {
// do work
}
Starx posted a solution which seems fine. It can be done without a database, though. If somebody uploads a file you can store the file as md5($filename).$extension and use your script.

Related

PHP Unlink Not working

I am trying to delete photo in php using unlink. I have used it earlier on other server but this time it is not working. I have used absolute path for a test but still does not works:
I have used it as:
unlink('img1.jpg');
and :
unlink('http://www.mysite.com/img1.jpg');
Please anyone having such experience?
url not allow in ulink function
can you please used this
It's better, also safety wise to use an absolute path. But you can get this path dynamically.
E.g. using:
getcwd();
Depending on where your PHP script is, your variable could look like this:
$deleteImage = getcwd() . 'img1.jpg';
unlink($deleteImage);
check this
bool unlink ( string $filename [, resource $context ] )
and
filename
Path to the file.
So it only takes a string as filename.
Make sure the file is reachable with the path from the location you execute the script. This is not a problem with absolute paths, but you might have one with relative paths.
Even though unlink() supports URLs (see here) now, http:// is not supported: http wrapper information
use a filesystem path to delete the file.
If you use unlink in a linux or unix you should also check the results of is_writable ( string $filename )
And if the function returns false, you should check the file permissions with fileperms ( string $filename ).
File permissions are usual problems on webspaces, e.g. if you upload an file per ftp with a ftp user, and the webserver is running as an different user.
If this is the problem, you have do to a
chmod o+rwd img1.jpg
or
chmod 777 img1.jpg
to grand write (and delete) permissions for other Users.
unlink($fileName); failed for me.
Then I tried using the realpath($fileName) function as unlink(realpath($fileName)); it worked.
Just posting it, in case if any one finds it useful.
php unlink
use filesystem path,
first define path like this:
define("WEB_ROOT",substr(dirname(__FILE__),0,strlen(dirname(__FILE__))-3));
and check file is exist or not,if exist then unlink the file.
$filename=WEB_ROOT."img1.jpg";
if(file_exists($filename))
{
$img=unlink(WEB_ROOT."img1.jpg");
}
unlink won't work with unlink('http://www.mysite.com/img1.jpg');
use instead
unlink($_SERVER['DOCUMENT_ROOT'].'img1.jpg');//takes the current directory
or,
unlink($_SERVER['DOCUMENT_ROOT'].'dir_name/img1.jpg');
There may be file permission issue.please check for this.
Give relative path from the folder where images are kept to the file where you are writing script.
If file structure is like:
-your php file
-images
-1.jpg
then
unlink(images/1.jpg);
Or there may be some folder permission issue. Your files are on a server or you are running it on localhost? If it is on a server then give 755 permission to the images folder.
you are using url insted of path, here is how you should do it...
i am assuming your are uploading the picture to public_html. i suggest you to create a folder for pictures.
unlink("public_html/img1.jpg");

$_SERVER['DOCUMENT_ROOT'] path not working

I am using document root to provide absolute path which is not working. if i echo this path it turns out to be C:wamp/www/proman/header.php. I i give relative path it works fine what is the problem here?
$path = $_SERVER['DOCUMENT_ROOT']."proman/header.php";
I elaborate my problem here: I have 2 php files data_object.php and user.class.php. user.class.php has an include statement for data_object.php which is relative to user.class.php.These two files are under different directory hierarchy.
Now I have to include this user.class.php in various files (like projects.php, links.php) under different hierarchy when I want to create a User() object. The problem is the relative path for file inclusion of data_object.php does work for say projects.php but if I open links.php the error message says it could not open file data_object.php in user.class.php.
What I think is for relative inclusion of data_object.php it is considering the path of the file in which user.class.php is included.
I am facing such problems in more than one scenarios I have to keep my directory structure the way it is but have to find a way to work with nested includes. I am currently running on a WAMP server but after completion I have to host the solution on a domain. Pls help
Since that's a server variable, you may or may not see it, depending on which web server you're running under (especially IIS), or if something's configured weird.
One way to deal with this problem is to set the variable.
$_SERVER['DOCUMENT_ROOT'] = "C:/some/absolute/path";
// or, if you put this code in a file that's in your document root:
$_SERVER['DOCUMENT_ROOT'] = dirname(__FILE__);
Then, you can either require() this file when you need to verify the document root, or use the auto_prepend_file php.ini option to include the file automatically.
If you are actually trying to make a URL, then you just specify an absolute URL - /proman/header.php, or a relative URL - ../proman/header.php.
In my experience, $_SERVER['DOCUMENT_ROOT'] doesn't including a trailing slash. Try:
$path = $_SERVER['DOCUMENT_ROOT'].'/proman/header.php';

Properly navigating relative local paths in PHP

I'm having trouble specifically with the getimagesize function. I'm making the function call from /item/ajax/image.php relative to the domain's HTTP root. I'm trying to get the dimensions of an image stored at /portfolio/15/image.jpg. From what I understand, the function takes a filename as an argument, so I tried the following:
getimagesize('/portfolio/15/image.jpg')
And
getimagesize('../../portfolio/15/image.jpg')
But both of them just threw PHP errors.
try prefixing below to path:
$_SERVER['DOCUMENT_ROOT']
Relative paths always start from the file that is executed, which is most likely index.php. This is true for included files as well. This means in any file within you project relative paths start from your index.php. (Except a chdir() is done before)
I think it is really bad code to have paths like "../../file.ext" or the like. Define a Constant that has the full path to your application (eg: $_SERVER['DOCUMENT_ROOT']) and prepend it to any path you're using.
Example:
# somewhere in your index.php
define('ROOT_PATH', $_SERVER['DOCUMENT_ROOT']);
# in any included file
$my_path = ROOT_PATH."/portfolio/14/image.jpg"
This is imho the cleanest and most readable way to define paths.
In PHP "/" is not the same as the Apache "/" (web root). In PHP "/" refers to the system root. You should use paths relative to your PHP script location ('portfolio/15/image.jpg' if your script and the 'portfolio' folder are in the same location)
The filename you enter is not related to the http root but should be an existing path in the file system of your web server.
To see what goes wrong you could enter:
realpath('../../portfolio/15/image.jpg')
To see what directory you end up at.
Or use:
imagesize(dirname(__FILE__) . '/../../portfolio/15/image.jpg')
to get the full directory qualification.
As an alternative you can use the web address, but you should specify the full url:
getimagesize('http://yoursite.com/portfolio/15/image.jpg')
However, this is a slower option.

php paths that work on both local (mac) and remote server

I'm testing a website on my local machine and I'm wondering what would be the best way to write paths to make sure they work when I upload the site to its final location.
In general I'm a bit confused about paths, and in many cases I have to 'tweak' each path until it works, so wouldn't want to be forced to do the same on a production site!
I'm not clear when to use $_SERVER['DOCUMENT_ROOT'].
For example, I have a directory that I want to scan, which is just under the root. So why can't I just use "/dirname"?
$dir = $_SERVER['DOCUMENT_ROOT'] . '/uploads'; //this works
// $dir = "/uploads"; //this doesn't work
if (is_dir($dir)) {
//do something..
}
I'm not clear when to use
$_SERVER['DOCUMENT_ROOT']. For
example, I have a directory that I
want to scan, which is just under the
root. So why can't I just use
"/dirname"?
When you work with paths in the php file the root (/) is the root of the filesystem, not the root you get when you visit your website.
So $dir = "/uploads"; gives you the filesystem root.
To minify your problems I would declare a variable in a configuration file that specifies the root of your php application, and use that path+whatever more is needed.
As adamse mentioned, the reason you can't use the '/path' is because it points to the root of the filesystem.
However, instead of declaring a variable that defines the root, I recommend using dirname(__FILE__) to retrieve the full path to the directory that the calling file is in.
From there, append relative path information to the file you want and you end up with a complete path, fully dynamically.
For example, if you want to include the 'header.php' file in the directory above the file that you wish to include it in use:
include(dirname(__FILE__) . '/../header.php');
The beauty of that is that PHP will always automatically convert the forward slash to the directory separator required for the host OS.
I would define a variable/constant that describes the absolute filesystem path to the application. Something like this:
$appDir = rtrim(str_replace('\\', '/', realpath(dirname(__FILE__))), '/');
Then you have this base path you can address your application’s files from:
include $appDir.'/library/foo/bar.php';
Or you even change your include path to that directory:
set_include_path($appDir);

How do I set an absolute include path in PHP?

In HTML, I can find a file starting from the web server's root folder by beginning the filepath with "/". Like:
/images/some_image.jpg
I can put that path in any file in any subdirectory, and it will point to the right image.
With PHP, I tried something similar:
include("/includes/header.php");
...but that doesn't work.
I think that that this page is saying that I can set include_path once and after that, it will be assumed. But I don't quite get the syntax. Both examples start with a period, and it says:
Using a . in the include path allows for relative includes as it means the current directory.
Relative includes are exactly what I don't want.
How do I make sure that all my includes point to the root/includes folder? (Bonus: what if I want to place that folder outside the public directory?)
Clarification
My development files are currently being served by XAMPP/Apache. Does that affect the absolute path? (I'm not sure yet what the production server will be.)
Update
I don't know what my problem was here. The include_path thing I referenced above was exactly what I was looking for, and the syntax isn't really confusing. I just tried it and it works great.
One thing that occurs to me is that some people may have thought that "/some/path" was an "absolute path" because they assumed the OS was Linux. This server is Windows, so an absolute path would have to start with the drive name.
Anyway, problem solved! :)
What I do is put a config.php file in my root directory. This file is included by all PHP files in my project. In that config.php file, I then do the following;
define( 'ROOT_DIR', dirname(__FILE__) );
Then in all files, I know what the root of my project is and can do stuff like this
require_once( ROOT_DIR.'/include/functions.php' );
Sorry, no bonus points for getting outside of the public directory ;) This also has the unfortunate side affect that you still need a relative path for finding config.php, but it makes the rest of your includes much easier.
One strategy
I don't know if this is the best way, but it has worked for me.
$root = $_SERVER['DOCUMENT_ROOT'];
include($root."/path/to/file.php");
The include_path setting works like $PATH in unix (there is a similar setting in Windows too).It contains multiple directory names, seperated by colons (:). When you include or require a file, these directories are searched in order, until a match is found or all directories are searched.
So, to make sure that your application always includes from your path if the file exists there, simply put your include dir first in the list of directories.
ini_set("include_path", "/your_include_path:".ini_get("include_path"));
This way, your include directory is searched first, and then the original search path (by default the current directory, and then PEAR). If you have no problem modifying include_path, then this is the solution for you.
There is nothing in include/require that prohibits you from using absolute an path.
so your example
include('/includes/header.php');
should work just fine. Assuming the path and file are corect and have the correct permissions set.
(and thereby allow you to include whatever file you like, in- or outside your document root)
This behaviour is however considered to be a possible security risk. Therefore, the system administrator can set the open_basedir directive.
This directive configures where you can include/require your files from and it might just be your problem.
Some control panels (plesk for example) set this directive to be the same as the document root by default.
as for the '.' syntax:
/home/username/public_html <- absolute path
public_html <- relative path
./public_html <- same as the path above
../username/public_html <- another relative path
However, I usually use a slightly different option:
require_once(__DIR__ . '/Factories/ViewFactory.php');
With this edition, you specify an absolute path, relative to the file that contains the require_once() statement.
Another option is to create a file in the $_SERVER['DOCUMENT_ROOT'] directory with the definition of your absolute path.
For example, if your $_SERVER['DOCUMENT_ROOT'] directory is
C:\wamp\www\
create a file (i.e. my_paths.php) containing this
<?php if(!defined('MY_ABS_PATH')) define('MY_ABS_PATH',$_SERVER['DOCUMENT_ROOT'].'MyProyect/')
Now you only need to include in every file inside your MyProyect folder this file (my_paths.php), so you can user MY_ABS_PATH as an absolute path for MyProject.
Not directly answering your question but something to remember:
When using includes with allow_url_include on in your ini beware that, when accessing sessions from included files, if from a script you include one file using an absolute file reference and then include a second file from on your local server using a url file reference that they have different variable scope and the same session will not be seen from both included files. The original session won't be seen from the url included file.
from: http://us2.php.net/manual/en/function.include.php#84052
hey all...i had a similar problem with my cms system.
i needed a hard path for some security aspects.
think the best way is like rob wrote. for quick an dirty coding
think this works also..:-)
<?php
$path = getcwd();
$myfile = "/test.inc.php";
/*
getcwd () points to:
/usr/srv/apache/htdocs/myworkingdir (as example)
echo ($path.$myfile);
would return...
/usr/srv/apache/htdocs/myworkingdir/test.inc.php
access outside your working directory is not allowed.
*/
includ_once ($path.$myfile);
//some code
?>
nice day
strtok
I follow Wordpress's example on this one. I go and define a root path, normally the document root, and then go define a bunch of other path's along with that (one for each of my class dirs. IE: database, users, html, etc). Often I will define the root path manually instead of relying on a server variable.
Example
if($_SERVER['SERVERNAME'] == "localhost")
{
define("ABS_PATH", "/path/to/upper/most/directory"); // Manual
}
else
{
define("ABS_PATH, dirname(__FILE__));
// This defines the path as the directory of the containing file, normally a config.php
}
// define other paths...
include(ABS_PATH."/mystuff.php");
Thanks - this is one of 2 links that com up if you google for php apache windows absolute path.
As a newbie to intermed PHP developer I didnt understand why absolute paths on apache windopws systems would be c:\xampp\htdocs (apache document root - XAMPP default) instead of /
thus if in http//localhost/myapp/subfolder1/subfolder2/myfile.php I wanted to include a file from http//localhost/myapp
I would need to specify it as:
include("c:\xampp\htdocs\myapp\includeme.php")
or
include("../../includeme.php")
AND NOT
include("/myapp/includeme.php")
I've come up with a single line of code to set at top of my every php script as to compensate:
<?php if(!$root) for($i=count(explode("/",$_SERVER["PHP_SELF"]));$i>2;$i--) $root .= "../"; ?>
By this building $root to bee "../" steps up in hierarchy from wherever the file is placed.
Whenever I want to include with an absolut path the line will be:
<?php include($root."some/include/directory/file.php"); ?>
I don't really like it, seems as an awkward way to solve it, but it seem to work whatever system php runs on and wherever the file is placed, making it system independent.
To reach files outside the web directory add some more ../ after $root, e.g. $root."../external/file.txt".

Categories