I'm building a file sharing site, and I'm thinking, I want my users to be able to upload and share anything.
Sounds dangerous, I know. But, is there a method to allow this to be possible? For example, forcing the download when the user requests the link with a mime type? Rather than "running" something on the page.
Any ideas how to allow any file type without the security issue.
Thanks
Store the file on a location not accessible by the user through the browser. (so above the document root)
when loading a file, use the readfile() function.
Set correct headers, including these:
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=[INSERT FILENAME HERE]");
And also use the correct content-type header for each type of file
If you only want it to be dangerous to other users (as they will be sharing virus ridden files in no time), but provide some protection for your web server from code injection attacks, you might consider storing the uploads in a database BLOB field. That should at least make it harder to inject code that will run on the server.
You can allow users to upload anything by using a simple HTML multipart form along with PHP's $_FILES. Only issue I see is file size limits.
You than can simply post a link to any of these files. It's the user's browsers settings that determine if a file is executed or downloaded, not yours. So you can suggest that they right click on them, and select 'save to', but besides that it's limited.
Any ideas how to allow any filetype without the security issue.
You say it yourself. It's like wanting to make scrambled eggs, without wanting to break the eggs.
Related
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'm looking for a way to hide the source of my download. I'm surprised this is not more covered, but it also makes me wonder whether it's possible.
(Edit: By hide I mean make it difficult or impossible for end user to find a direct link to the file. They will thus be forced to actually be on the page, clicking it, for it to work.)
I found a script to force download files that are locally stored. The way I see it, it hides the true source (at least it's not in view source or download history).
http://w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php/
So this works, I made it into a function that gets a linkID, and check that with a DB for the actual file-source. Hooray!
Only what if your downloads are on another server? Then you can't use most of the functions used here (like filesize, isreadable, fopen, ...). I'm not proficient enough to decide whether it is possible/feasible to make this work cross-server.
I realize that probably my webserver will lose bandwidth even though files aren't stored there, that's not a big issue.
Any info on the subject would be greatly appreciated. I prefer PHP, but I can work with whatever you give me, I really have no idea about this one.
You mean you want to hide the path of files stored on your server? If this is the case, simply store the files outside of your web root, and serve the files with a PHP script which will make use of readfile() + header() of appropriate headers depending on whether you are serving the file for opening or forced download. See http://php.net/readfile for plenty of examples on forced download scripts.
Sorry not possible. You HAVE to tell the browser where the resource is located so any savy user can simply decode the address or scan the HTTP request or their firewall logs or download history in the browser.
If you're trying to hide the path on your server then URL rewriting with mod_rewrite or aliases or other similar method should be sufficient.
UPDATE: Ok if using your own bandwidth is not an issue then all you need to be doing is outputting the files binary content to the browser and setting the relevant HTTP headers (ie, Content-Type and Content-Disposition). If the files MUST be stored remotely then you'll need your script to download and read them on-the-fly using CURL or similar before outputting the content.
If you mean hide the script or the directory the file is coming from, it's a simple answer--you can't.
BUT, you can make it only accessible on your terms, like using a script to render the file (as you have) but only when specific criteria are met. Alternatively you can move the file to a temp/secured directory and allow them direct access, but this also means waiting for the move, providing (what is deemed) reasonable and fair time to download the file, then removing it/deleting it when it's done.
You could use cURL to serve as a pass-thru for the content. This would conceal the source of the actual data, and allow you to secure it any way you choose. It would also take a lot of bandwidth, roughly 2 times the size of all downloaded files.
Give this a shot and let me know if it works?
if ($passesallyoursecurity) {
set_time_limit(0);
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header("Content-Type: application/download");
header("Content-Disposition: filename=filetheyget.ext");
$ch = curl_init("http://remotedomain.com/dir/file.ext");
curl_exec($ch);
curl_close($ch);
exit();
}
I would recommend that you use a die() message without any HTML, whatsoever. in the document.
Then, insert the IP Addresses you want the webpage to decline. I would break the IP Addresses you don't like in an array(). Then use an "if" construct to see if any of those IP Addresses are lurking.
$decline_ips = array('ip_1' => '127.0.0.1');
if ($_SERVER['REMOTE_ADDR'] == $decline_ips['ip_1']) {
die("You aren't permitted direct access to this page.\n\n\n\n
Sources are blank.");
}
It works like a charm! And for XTRA-XTRA security, I would recommend inserting the IP address that isn't allowed (when they visit) to the Database so that whenever they try again, both the source is covered and the entire document.
But, you can just use the script I have posted on a different part of the document.
I know this question is silly.
But as per our intelligent Client request, I am not able to answer his question. Any one help for this.
We are building a online tutoring site. where it contains pdf, .ppt, .doc formats files are uploaded for reading as course materials. His (Client) request is that user can read all the contents but they must not download the materials and use this.
That is all the documents must be opened in their browsers.
Is it possible? Any other ideas?
Any other ideas?
Explain to your client that the only way for a document to appear on a user's computer screen is for the document to exist on that user's computer.
In other words, viewing a document involves downloading it. Even supposing the software on the user's computer somehow makes it impossible for the user to directly manipulate an electronic copy of the material, the user can take out a digital camera and take a picture of the screen.
There are ways to make it difficult for the user to save a copy of the file. However, it's likely that this will do more harm (frustrating users) than good (preventing theft).
Some users may want to peruse the material at times when they do not have an internet connection, or may want to copy it onto their mobile device (for instance), but accessing the internet on their mobile device is expensive so they would like to do the download on their computer.
If you send the data to the client the client has effectively downloaded it. You can make this difficult, but not impossible.
The only sure way to prevent downloading is to prevent viewing.
If this is a copyright problem it should be solved with legalese, not software.
Here are some guide-lines you may consider:
Don't put direct link of files such as:
Download
Instead, try to generate your pdf dynamically or put a another encrypted medium for
downloading eg:
Download
2: Don't allow directory browsing, use htaccess file with following commands:
Deny from ALL
3: Not sure, but you may possibly allow file opening this way too:
$filename="/path/to/file.jpg"; //<-- specify the image file
if(file_exists($filename)){
header('Content-Length: '.filesize($filename])); //<-- sends filesize header
header('Content-Type: image/jpg'); //<-- send mime-type header
header('Content-Disposition: inline; filename="'.$filename.'";'); //<-- sends filename header
readfile($filename); //<--reads and outputs the file onto the output buffer
exit; //and exit
}
Note: above is just an example of image not pdf but you can modify it for your needs.
An online site does not necessarily mean it is a web site. You could write a custom client that accesses the data and displays it.
The data would need to be encrypted between the client and the server. It probably should not be sent 'in bulk' either.
The effort associated with developing that is prohibitive.
You could license the software that allows users to read books, page by page, that is part of the Safari Books Online web site.
As best I can tell, they take the pages that they are going to display and turn them into small images. These images look as if they are sent in a random order, and assembled by the browser via javascript.
These tactics won't stop a determined person from getting your clients content... but the effort is unlikely to be worth it.
You could put the docs into Google docs and embed the docs viewer into your site. Of course, there's no stopping people from taking screenshots, copy/pasting text, downloading HTML, etc.
What do you mean by "read" but not "download"?? Do you know that even if you disable cache (which by itself is a bad idea) won't restrict an eaaaasy right-click>view source, "save target as", etc.?
I mean, the best you can have is a flash reader that is harder to save the content from, and that means disabling selection and copying, but anyway, it doesn't forbid anything.
The only way to forbid download is to return HTTP 403 :)
Writing a small app that (among other things) lets users upload a file (like an image, a .doc or a text file) as part of their posting/submission.
Our current prototype just dumps the file into /{app_root}/files/, but of course, anyone can get to that even if they are not logged in or using the system. The goal is to only grant access (view access) to the files if user is logged in and does in fact have access to the post that the file belongs to.
So, in short, I am looking for a good way to do this.
I am thinking of either creating a folder outside the /web/ (http) folder and then having PHP render it somehow using header() commans, or, maybe just dumping the file into the database? I have never done either one, however.
While I suspect I can figure it out eventually, there are just too many smart people on here that I was figuring someone will know of some sort of existing class or function library that does this already?
You have to do the following:
Move all the files out of the webroot. You could disable access to the folder with .htaccess, but it is not worth the hassle and potential security risk. Just move it out there.
Keep a table of the files uploaded, storing the user's original file name there. Rename the file to $id.$ext and so on. In short, you don't want to use the user's file name in your system.
Have a script, download.php or whatever, get the file's ID, verify who is logged in, and if everything checks out, fetch the file, read it out to the browser, and send the appropriate download headers.
These headers would be something like:
header('Content-type: application/octet-stream');
header('Content-disposition: attachment; filename=usersuppliedname.txt');
header("Content-Length: " . filesize('../safefiles/1.txt'));
header("Content-Transfer-Encoding: binary");
readfile('../safefiles/1.txt');
exit;
You can then get more fancy if you want to allow resuming files and such, but the above should do it.
I've inherited an application with a glaring security hole.
It has session-based security, but file uploads (which are user specific) are not secured in any way and they are stored in the public file tree.
Filenames do not follow any convention as such, making them hard to guess, but the data is sensitive and thus I need to implement a security measure to prevent unauthorized file access.
Moving the location of the files is not really an option, so I'm looking at a htaccess solution to forward requests to a php handler script.
Does anyone have experience in implementing this type of thing or any good alternative solutions? Specific examples of .htaccess syntax greatly appreciated, as I'm struggling in this area.
Don't really understand why moving them isn't an option, since pushing requests for them to a handler means it no longer matters where they're stored. But you're the man on the scene.
.htaccess looks like:
RewriteEngine on
RewriteRule path/to/where/these/files/live/(.*) /handlerscript.php/$1
Then you pick up the remaining file path and name from $_SERVER['PATH_INFO'].
Well, you could make apache parse .jpg file's for a certain folder adding the following to your .htaccess
AddHandler php5-cgi .jpg
then you could set a file of php to parse the request the way chaos was recomending you and doing a certain validation, then just return jpeg headers along with the correct picture u'd like to display
here's an example
<?php
if($validUser)
{
header("Cache-control: No-cache");
header("Pragma: No-cache");
header("Content-Type: image/jpeg");
//correct picture address
$img = imagecreatefromjpeg("2326_b_lil.jpg");
imagejpeg($img);
}
else
{
//code for error image
}
?>
please let me know if you want a more extensive example
I think you may need to write a script that will serve the images, then use htaccess to completely restrict access to the actual images from a browser.
The script can take in the web path to the image, decide if the user has access, then use something like fpassthru to feed an actual image to the browser.
All references to the images would need to be modified, however, to reference the serving script.
So instead of accessing the images with /images/123/5423453245.jpg,
it would be /image.php?images/123/5423453245.jpg
Or something similar to that.