Jump to content

Making documents only accessible to specific users?


Kristoff1875
 Share

Recommended Posts

I'm storing website files online and each user can upload their own files and admin can upload files for that user specifically. How would I go about making sure nobody else can download their PDF file? Would it be a case of assigning a folder for each user's documents and not allowing access to any other user to that folder?

Thanks in advance.

Link to comment
Share on other sites

If you have users then you need to authenticate a user before they are allowed to upload or download a file. i.e. They need to login to the website. If your users are stored in a database table then each user will have an id (primary key). Store the uploaded filenames in a database table along with the id of the user who uploaded them. A user should only be allowed to download their own files. i.e. If my user id is 123 I can only download files where user_id = 123

 

Simple database schema

 

user

======

user_id

name

username

password

 

user_file

=======

file_id

user_id

filename

 

You only need to split the folders up if you are going to have thousands of files uploaded otherwise just upload the files to a folder that it outside of the website document root.

Edited by neil.johnson
Link to comment
Share on other sites

I've gone about it slightly differently, how secure does this sound? I'm using the document name, along with their UserID and Salt to generate a hashed file name for the file. I'm then running a script that is decoding that using the session username and document ID they clicked through from to download the file.

Link to comment
Share on other sites

Sounds like you need to find a simple file manager written in php/js/html. Neil is already described the basic skeleton, but dealing with users/dirs/files/permmissions and so forth on the web server ( where the users not belong to the file server) is not an easy job as you think.         

Link to comment
Share on other sites

If you believe that obfuscation is a form of security, then yes what you propose would work. (Hint: obfuscation is not the same as security).

 

 

 

How would I go about making sure nobody else can download their PDF file?

 

If you want to be sure no one but the authorized user can download the files then you need to first put the files into a directory that is not web accessible. Then, you would put a process in place to provide an authentication mechanism (as described above) when either displaying the list of files or when attempting to "download". The download process would be implemented by passing an id to a download page. The download page would use the ID to find the file (typically stored in a DB) and send it to the user directly.

 

Here is what the directory structure might look like

 

 | 

 |-[my_website_root]

 |        |

 |        |-[images]

 |        |-[style_sheets]

 |        |-[pages]

 |

 |-[files_for_download]

Link to comment
Share on other sites

 

If you believe that obfuscation is a form of security

 

I think he renames the uploaded file using a hash algorithm as a file name, then just compare if this name exists in the db table and belongs to the uploader (user) with this ID. Well, this would work good, but could cause a lot of server's resources :)   

Edited by jazzman1
Link to comment
Share on other sites

Well I have a page called show-docs.php and that loads all of the docs from the database for that user, each document has a hashedID which is generated using a second (different from the password one) salt, called UpSalt. When uploading the file, the hashedID is generated and stored in the documents table along with the UserID. When a user is on show-docs.php and they click one of the items in the list, the page then grabs that user's UpSalt, and uses their session ID to identify the correct file in the documents folder.

 

The thinking behind this is that each document when uploaded will have it's own unique generated filename and that is simply matched up when trying to download it.

 

I'm actually thinking now that it would be a good idea to run a small query to check the document stored in the database belongs to the current user in the session, that wouldn't take up much resources would it?

 

So far in my tests that is working fine, but as Psycho says, the files aren't secure, just hidden... Could you guys point me in the direction of making the directory unaccessible?

 

Edit:

 

Psycho, you posted this:
 

 | 

 |-[my_website_root]

 |        |

 |        |-[images]

 |        |-[style_sheets]

 |        |-[pages]

 |

 |-[files_for_download]

Which i'm not too sure I understand currently... I have the following:

 

 | 

 |-[my_website_root]

 |

 |-[css]

 |-[documents]

 |-[images]

Edited by Kristoff1875
Link to comment
Share on other sites

Psycho, you posted this:

 

 | 

 |-[my_website_root]

 |        |

 |        |-[images]

 |        |-[style_sheets]

 |        |-[pages]

 |

 |-[files_for_download]

 

Which i'm not too sure I understand currently... I have the following:

 

 | 

 |-[my_website_root]

 |

 |-[css]

 |-[documents]

 |-[images]

 

I'm pretty sure that is not your directory structure. If it was, then users would not be able to load images or CSS files. All those folders must be in a parent folder that is your actual root. Using my previous example:

 | 
 |-[my_website_root]
 |        |
 |        |-[images]
 |        |-[style_sheets]
 |        |-[pages]
 |
 |-[files_for_download]

You would need to configure, on your web host, to point your domain to the [my_website_root] folder. I.e. when a user enters www.mysite.com it points to the [my_website_root] folder. It is impossible for a user to enter a URL to directly access any of the files because they are not publicly available.

 

As for your current approach, I think the logic is more complicated than it needs to be. You already have to authenticate the user, correct? Then there is no need, in my opinion, to use some sort of hash on the file name as part of the security. Instead, you can have database details to determine who can access which files. If all files have one, and only one, user with rights to access the file. Then you can have a column in the files table with the user ID who has rights to the file (you can implement logic that an 'admin' can access any files). Then, when a request is made to a file, you would verify that the logged in user has rights to the file before providing it to them.

 

How you provide the file to them, since it is not publicly accessible, is through a force-download script which will 'read' the file from the file system folder that is accessible on the server, but not from the user, and output to the user. Here is an example of a force download script: http://davidwalsh.name/php-force-download

Edited by Psycho
Link to comment
Share on other sites

Sorry, you're right, I completely read your structure wrong, it's currently like this:

 

 | 

 |-[my_website_root]

 |      |

 |      |-[css]

 |

 |      |-[images]

 |

 |-[documents]

 

So if I understand correctly, on the server I need to put the files in / instead of /www ?

 

I currently download the file using:

    if (!isset($_SESSION['UserID']))
    {
        echo 'None';
		exit;
    }
$file = '../documents/'.$hashedID.'.'.$FileType;

if (file_exists($file)) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename=' . basename($file));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    ob_clean();
    flush();
    readfile($file);
    exit;
 } else { echo 'error'; }

I know I need to change the path for the documents in that, but basically if I add a database query (select where documentID = documentID where userID = Session[userID] for example) then that should be fairly secure?

Link to comment
Share on other sites

Well, in this case instead of build a new layer of security based on the web server (most likely a shared hosting) for multiple users, I'd be consider to use the database as an upload storage.

It's currently being built on shared storage, but moving to dedicated hosting due to the nature of the files to be hosted.

Link to comment
Share on other sites

Since you are reading the files and pushing them to the user rather than the user downloading them, you really don't need to additional layer of "encryption" of the file name. Just authenticate the user and verify they are allowed to view the file and push it to them. The file name hashing really adds no additional security since you would have to authenticate the user first anyway. If someone has already gotten around the authentication process as another user then the additional hashing of the filename is moot since their "UserID" would be that of the user they are impersonating.

 

If the files are of a very sensitive nature, then you could look at securing them on the server-side from someone who gains access to the server. You could either store the files directly in the database and encrypt them there (as jazzman1 suggested) or you could encrypt the actual files and then decrypt them before sending them to the user. Of course, if you are going to go to that extent then you should be using HTTPS.

Link to comment
Share on other sites

It's currently being built on shared storage, but moving to dedicated hosting due to the nature of the files to be hosted.

A lot of security technics you could apply in the dedicated server from MAC/DAC/SeLinux until chroot, LXC so forth if you're running the project on a linux server. About SSL, this is a method of encripting all TCP/IP transmissions stack (including web pages and data entered into web forms) in case some malicious user tries to sniff and catch the data trafic and tying to read or re-write the same data pretending that he is the owner of the file, most often that happened in a local environment. So HTTP over SSL is a good thing you should use it. I'm still stay behind the scenario to use the database as an upload files storage engine since the files contain a sensitive data and not to be publish at all.

Edited by jazzman1
Link to comment
Share on other sites

In situations where your application needs to store and share a lot of public binary files, as pics, movies, other shared data, etc.. where you expect to have multiple requests to those files and queries to your database server, I' m agree that the preffered method is to save the binary files using the server’s file system and that's considered to be the easiest and fastest way when storing files. However, you have a completely different situation here! When the data shouldn't be shared amoung people, as I said above the database application will provide you a new different level of security onto the main server-system, that means you must have an account name and password for the server administrator or for a group administrator that has the privilege to perform some actions on databases and handling those account permmisions on the files in much more easier way. Anyways.... you should get the fastest and eaysiest way for youself :)  

Link to comment
Share on other sites

This thread is more than a year old.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.