Sophivorus
Sophivorus

Reputation: 3083

Allow users to view or download files, but not execute them

I'm making a website that allows users to upload any kind of files. All the files are stored in a 'files/' folder. I want users to be able to see and download any of the files in that folder, but not execute them.

Some files, like JPG files, are easy: browsers have a built in system to display them, as we all know.

Other files, like PDF files, cannot be displayed directly, so what browsers do is prompt the user a download screen. Thats fine too.

However, other files, like PHP files, pose a problem. When I open one such file, if I am not careful, it gets executed. For example, if the file contains

<?php echo 'ok'; ?>

then when I go to 'files/myphpfile.php', what I see is just 'ok', and not the contents of the file. This will happen not only with PHP files, I presume, but also with any other file types that my server can execute (for example ASP files, I suppose).

What I need is to prevent users from executing the files, so that when they go to 'files/myphpfile.php', they either see the file contents, or the browser prompts them the download screen. Ideally it would be a general solution, that would not require me to construct a list of every file type executable by the server.

To me, the most reasonable approach was to set the file permissions to 644, so that users could only read the files. But after doing so, the PHP files keep getting executed.

Upvotes: 0

Views: 1225

Answers (2)

Sophivorus
Sophivorus

Reputation: 3083

I solved the problem by displaying the files through a script, and not directly from their real location. The script was taken from an answer to a previous question of mine.

$fileinfo = finfo_open( FILEINFO_MIME_TYPE );

header( 'Content-Type: ' . finfo_file( $fileinfo, 'files/' . $filename ) );

finfo_close( $fileinfo );

readfile( 'files/' . $filename );

So now users that want to see 'files/myfile.php' must go to 'open/myfile.php', and the script above will prompt them the download screen, or display the file in the browser, if the browser is able to do so.

Upvotes: 0

PeeHaa
PeeHaa

Reputation: 72682

To download:

header('Content-Type: text/plain');
header('Content-Disposition: attachment; filename=somefile.php');
header('Pragma: no-cache');
readfile('/path/to/somefile.php');

To display:

echo htmlspecialchars(file_get_contents('/path/to/somefile.php'));

UPDATE

When I open one such file, if I am not careful, it gets executed

That's why you don't have a direct link to the file. I.e. the files should not get uploaded to a location somewhere inside the document root. If the files are uploaded to a directory outside the document root people cannot access it directly by URL, e.g.: http://example.com/files/somefile.php.

This will happen not only with PHP files, I presume, but also with any other file types that my server can execute (for example ASP files, I suppose).

You are the only one who can tell what files may be dangerous. We cannot know whether you have some server which also serves (and parses) asp files nor what other potential dangerous files may be on there.

What I need is to prevent users from executing the files, so that when they go to 'files/myphpfile.php', they either see the file contents, or the browser prompts them the download screen.

See my already provided solutions above.

To me, the most reasonable approach was to set the file permissions to 644, so that users could only read the files. But after doing so, the PHP files keep getting executed.

This is because PHP files are not getting executed. They are only being parsed (i.e. being read by the webserver).

So basically you need to find out what are the possible dangerous file types (also think about other files that may get parsed by PHP e.g. .phtml or what not). Users shouldn´t be able to call executables anyway through a HTTP request. Because when I would do http://example.com/run-virus.exe it never gets executed on the server, but it only requests the file.

Upvotes: 2

Related Questions