readfile() - Only allow download of certain filetypes from certain directories
I have folders on a website I am creating that I only want logged in users to be able to access the files from. So, I've decided to use some .htaccess rules and a PHP file handler so I can make sure us开发者_运维知识库ers are logged in before they can access the files. The file handler will take input in the form of "/download.php?file=filename.pdf". I only want the user to be able to download Word documents and PDF files. How do I make it so users can't abuse my file handler by downloading things like the .php files for my website or downloading files outside of those directories?
Well, I was going to note that this can be insecure to do. Nonetheless, it is a common type of program. The file handler should clean the user input. First of all, you should be running your web server on a separate account with limited abilities. That way, if the hacker can try to access your filesystem, they are already severely limited. Then, you should change the permissions of everything outside of the download folder.
Now, you have a couple options for cleaning the user input for which file to download.
You could use Perl Regex to find the extension.
You could use pathinfo() to get the basename and extension...this way you would not open any directory (like ../ or /home etc).
You could give each file an id in a database and then instead have the file handler do something like /download.php?file=12345 but you would have to clean the user input for the database.
Sanitize the value before offering the file for download. Check it for parent traversal and verify the file extension.
For one, don't directly expose the name of the file being downloaded. Use a hashed token of some sort. Ideally, you'd keep a list of all the possible files in the database, and use a salted+hashed copy of the record's primary key as the client-side identifier of the file. So instead of
/download.php?filename=my_bank_password.txt
the user will see
/download.php?id=235gdlhs987234rljfser23j8233r4
instead.
And inside the download.php script, you do the appropriate checks - is this person cleared to see the file, are they allowed to download this file type, etc... if they're not, you output an error page. If they are, you output the file, with the appropriate header so they'll get the original filename and not the hashed garbaged or "download.php"
精彩评论