Chmod for PHP web application - php

Im writing web application. It's have:
index.php
/app - of course, with .htaccess but im not talking about it
/app/session - for sessions, session_save_path(/app/session) must be used on my server
/app/include - index.php includes files from this directory
/app/config - only .xml files, that files reads classes from scripts in include
/images, /styles etc.
My question is:
What is correct chmod settings for above directories? I know what is chmod (im working on Linux) and I know how I can change it, but I can't find useful informations about that. Only articles like "How i can change chmod to 777...
And I don't know who is owner, group and others. My page will be on shared web server, so I think owner is apache, and group is www-data, correct?
Please, tell me what chmod's must have directories (and files? I'm using -R for chmod to files) for safe website. Mainly it comes to the possibility of intrusion by any script.

Wordpress has a nice article explaining unix file permissions. Read it and you'll grasp the basics of it. In short (and not theoratically correct):
Unix systems designate 3 different 'roles': the user, the group and the world. Especially 'the world' seems to confuse people.
Every file AND directory (which are both nodes and as such not that different in Linux systems) is assigned to a user and a group. You can see the user and group as 'owners' of the specific file/directory (I'll talk about 'nodes' further on, because it doesn't really matter). File permissions define who can do what with the nodes. Example given:
The file index.php is assigned to user 'aso' and group 'www-data' and has file permission modus 644. This means that the user (6) has read and write permissions, the group has merely read permissions (4), as is 'the world' (the last 4 of the three digits).
Now first you have to understand that EVERY user on a *nix system is part of a group. The group name is sometimes the same as the user name, but A GROUP IS ANOTHER ENTITY. So it is possible that you have a user as well as a group named 'aso'.
File permssions are build from a 'bitmask' as follows: read permissions are designated by the digit 4, write by 2, and execute by 1. Any combination can be made from this. In example write and execute permissions are designated with 3 (write = 2, execute = 1), and read and execute permissions are designated with 5 (read = 4, execute = 1).
Let's see what this means, and I have to be as fair as to say that I cannot be complete in this matter. Please use Google if you want a complete story.
If I create a file on my *nix system it is automatically assigned to me (my user) and the group my user is part of. Having the permissions 644 this means that I (logged in with my own user) can read the file and can alter (write) it. But I do not have the execute (x) permissions. It doesn't matter however because this only applies to executable scripts (shell scripts, most of the times with a .sh extension). The group the file belongs to ('www-data') only has read permissions, so cannot alter the file. The 'world' also only has read permissions.
Please note that a user can be part of multiple groups, and as such *nix file permissions have a limited scope: you might want to assign write permissions to group 1, and only read permissions to group 2. In traditional file systems this is not possible. However file systems like reiserFS and Ext3 may use an extended ACL to accomplish stuff like that. That's another story however.
What does this all means? It's more easy then expected actually, as long as you understand what the assigned rights mean and what is the difference between a file node and a directory node.
Files
Read: Ability to read it's contents
Write: Ability to alter (write AND delete) it's contents
Execute: Ability to execute the file (execute a script, with all consequences possible)
Directories
Read: Ability to read it's content. Which means: list the node names, but NOT a nodes content, type, etc.
Write: Ability to add/delete files
Execute: Ability to list the it's content, including type, last modification date etc.
Back to your case. If you have a normal setup (a Linux server running Apache and PHP as a module) your files will be assigned to your ftp user and the group 'www-data' (the group Apache is running from). You yourself need read AND write permissions (as sometimes you want to change a file), but DO NOT NEED execute permissions (as PHP - or HTML for that matter - are not executables). So for the user, you'd need a 6 (read = 4, write = 2, combined makes 6). For the group user you only need read permissions, as Apache (or the PHP module) only need to read the contents of your php script. Any other user on the system has nothing to do with your files, and as such need no permissions as all (0).
So, for ALL your scripts, permissions of 640 (read and write for the user, read for the group and none for 'the world') are sufficient.
For the directories your user needs all permissions (read = 4, write = 2, execute = 1, 7 in total). Why? Because it needs to read it's contents (node names), has to be able to determine if it's a file or directory node (and other properties) AND has to be able to add and delete files (you want to add files sometimes, don't you?). So we'll giver your user a 7.
The group however ('www-data', the group Apache is running from) only need read and execute permissions. The read permissions to list the contents (node names) and the execute permissins to list other properties (node type, modification time etc.). It doesn't need write permissions though, because normally you don't want PHP (Apache) to add/delete files from your application tree.
Lastly the 'world', which is every other user on the system (that's NOT the same as the world in it's broadest sense) doesn't need any permissions. Why would anyone else on the server need access to your files?
Combined that would make 750 (all permissions for the user, read and execute for the group, none for others).
Summarized answer to your question, the bare minimum is:
File permissions: 640
Directory permissions: 750
But always good, quite standard and secure enough:
File permissions: 644
Directory permissions: 755

I use 640 on my server. The files are owned by me so I need read and write. Group is www-data so apache can read. PHP scripts don't need execute to run (if using the apache php module which is default. I think you need execute when using cgi), only read. No one else needs access. I have an uploads folder that gives apache write but just that one folder and I typically deny access with .htaccess, disable php to prevent script uploads or put it outside the webroot; depending on the needs of the project.

Related

File system permissions

It was a cms and I would like to set all my files on server to -rw-------
This will make my website working as usual? or they will not read each other, for example i have this:
require_once 'include/checksession.php';
First, you need to understand what each "segment" means.
first triad what the owner can do
second triad what the group members can do
third triad what other users can do
Your permission set (-rw-------) only has permissions on the first triad - the owner of the file - which only has read and write permissions.
read The Read permission refers to a user's capability to read the contents of the file.
write The Write permissions refer to a user's capability to write or modify a file or directory.
execute The Execute permission affects a user's capability to execute a file or view the contents of a directory.
Therefore, the owner of the group can read the contents of the file/directory, write to the file/directory, and modify the file/directory.
Under careful file/directory ownership policies, I guess this will be okay - but I wouldn't count on it. If Apache/Nginx/... doesn't have ownership of the file, your application won't work.
This being said, I'd like to raise a few questions;
Why change the permissions of all files/directories on your server?
Why set a global permission rule, and not individual to each file/directory?
What's the end-goal of this?
I'd take some consideration to Jon T's answer
Depends on whether PHP is running as your user or as as something else (Apache, nobody etc)
If it runs as your user (using suexec or something similar), then nothing else needs to read PHP files.
I'd set these to 0600, giving only your user read/write access. Set to 0400 (read-only) for things like config files.
If you have mutiple FTP users accessing your files, then you need to allow group read/write access as well. Permissions then would be 0660.
If PHP is running as another user and it's not in a chroot'd environment, change your webhost.
Also, on a side note, if your CMS requires permissions anywhere of 0777 (I'm looking at you, Joomla), use a different CMS

Differentiate each apache user and give permissions

In a web application, I want to create a folder for each www-data user and give write permissions just on that folder, and just to that user.
AFTER VALIDATION I can do:
mkdir($file->getPath().mt_rand(0,100000),0700);
This will create a new directory with a random name, in the path $file->getPath() with all permissions to the owner user. But it would give permissions to all www-data users.
If I create a chroot jail I have to copy all files again for each user, because I should create many jails (one for user).
I'm getting crazy with that and don't find out the solution.
If I understand your question right, your problem begins with the structure of the linux permission/user framework. Thus, the Apache process owning user is the one that is creating dirs and files when it is running your script.
If you need user separation for scripts, e.g.: you have different directories for different (virtual) hosts on your server and you don't want the script of one host is acting on data of a different host on the same (apache) server, then you should use 'mpm_itk_module' instead of the more common 'mpm-prefork' apache.
Using this you can go and define the user/group that apache is using when it executes any scripts and e.g. creates directories just by this command for each virtual host entry in the httpd.conf:
<IfModule mpm_itk_module>
AssignUserId USER GROUP
</IfModule>
If you really want to create different directories from ONE script execution, you need the apache process to be owned by root.root and then the script needs to set the permissions and owners for each directoy the way you want.
But it is never a good idea to run even the best scripts on a webserver as root, as you might fail to think of any risk.
The user/right separation by vhosts seems to be a much saver way in my view.
Another point - PHP only - is suPHP -> http://www.suphp.org
EDIT:
Ok, I had a look at your site and even if I can't speak spanish, it looks like you have just one website, acting for different users coming allways thru this webpage. So where is the need for user separation on linux filesystem permissions? You can restrict everything by your application with no need for filesystem users. Even if you give e.g. additional ftp access - restrict it e.g. with proftpd it has its own chroot mech for different users.
You should have to care about filesystem rights only if you can't control who is executing what. Thats a common problem on a multidomain host which you could solve with the mpm_itk_module I mentioned.
Maybe you should describe your situation a little bit more?
EDIT 2:
As suggest in the coment, if you ONLY use apache to give the users access to the files for uploading/manipulation, then just put the files outside(!) the documentroot tree of apache and create simple database to know which file is owned by which user:
user a | file parentdir/filename
This could be an easy table and your php code gives a list to the user from the database which file he is able to see/manipulate and your code does the work as intended by the user action.
As long as you don't give the user access to the files by other services (ftp, ssh, etc.) there is NO need to work with linux user rights at all. Just take care to place the files outside the documentroot of the server so that only your php code has access to the files by the rights of the apache user of your server.
EDIT 3:
Haha, now finally I got your problem after I read a similar post of you: (How can an Apache user write files when having permissions to do it?)
In this case (with REALLY anonymous users on your webpage) you have NO chance to solve this at all. Every visitor is handled as the same one without authentication. And as I assumed in my last EDIT and commented in the similar post: no need to handle with linux file permissions at all.
YOUR SOLUTION ;) :
You need to do the file manipulation in one sessions with session-ids while the user is visiting your page. So your code needs to handle the relation between the visitor (the session-id) and the file he uploaded with this session-id. Using a session-id that is valid as long the visitor is online is the best way to do this. And again - no need for filesystem permissions.... ;)
The second way is with authed users as suggested before: Create a db table with users/passwords to login the webpage (not the server) and another table that holds the user/file relations. Than, after he logs into the webpage, work again with sessions to allow the user accessing/manipulate already uploaded files.
I can that you run apache with mod_php. So then it means that your PHP instance work under apache instance and have apache USER and GROUP. You can create folder and can change owner of this folder but owner must be user in you system (not apache or same virtual user).
But you can store in every directory file for example ".permitions" and put inthat file virtual owner. Next you need filter every write (delete,rename, etc...) attempt to this directory and compare your virtual user and user that stored in .permitions file.
Sample Class (not full but it is more than enough to understand idea):
class UserDirs {
private $path='/home/vusers';
public function mkdir($user){
$d = $this->path.'/'.md5($user);
mkdir($d);
file_put_contents($d."/.owner",$user);
}
public function checkOwner($user, $dirname){
$f = $dirname."/.owner";
$virtual_owner = file_get_contents($f);
return $user === $virtual_owner;
}
}
$d = new UserDirs()
$d->mkdir("foo","bar");
echo $d->checkOwner("foo1","bar") === true ? "OK":"FAIL";
echo $d->checkOwner("foo","bar") === true ? "OK":"FAIL";
You can encapsulate all that you need in this class to work with UserDirs and extend class depending your requirement.
Your users do not have system accounts. It probably is not feasible to create those accounts either. Therefore, I'd recommend managing all of this via the Web UI.
Continue to create your directories as you are. The permissions are fine. Your user interface needs to change though, to only show that user's directory or files. I assume you have a database associated with this page. Associate the usernames and the randomly generated directory name with the user. If someone attempts to go to the direct path and they are NOT the user associated with that directory, kick them back to the login screen.
To illustrate, I created an account named test and was presumably given a unique directory. If I log out, I should not be able to visit that directory because your code would see that
I'm not logged in and therefore don't have access to that directory
If I were to login as test2 and visit the directory of test, your code should see that
I'm not the owner of the directory being visited and should therefore be redirected as appropriate.
You need to add a function that checks the directory the user is visiting and compare it to the directory associated with the user. If they two match, allow them to proceed. If they don't match, redirect the user.

Creating, moving, and deleting files in php without setting directory and file permissions to 777?

As the title suggests, I need the ability to create, move, and delete files and folders from php.
If I CHMOD all directories and files to 777, everything works great, but if I do 755 then the scripts die with errors about permissions.
From what I've read, using 777 permissions is insecure and should not be done. I have a VPS, but there are multiple users as I host a number of websites (some of which other people are in control of) and, regardless, I want to do whatever is the "best practice."
So, basically, what I'm wondering is how I should go about this? I'm new to php and "webmastering" and am not sure what to do.
Could anyone point me in the right direction?
One last note: In addition to being able to move and delete files that have been created from php, the scripts also need to move and delete files that have been uploaded via FTP from a Windows machine (I've noticed that by default when I upload files the CHMOD is 755).
EDIT: I it may be relevant for me to mention that I ran phpinfo() and found the following under the section "PHP Credits":
User/Group nobody(99)/99
Permissions are set for what the owner can do, what the owner's user group can do (the owner's peers in the same user group), and what everone else can do. That's what the 3 numbers are for: 753 is a "7" for the owner, a "5" for the group, and a "3" for everyone else. A "7" is full access (read, write, execute). A "5" is read and execute. You need write access to delete.
You should really read up on linux file permissions to see how they work.
I would recommend you use 775 or 770. The last digit is what anyone on the system or any shmoe browsing your site can do, so you want it as low as possible.
As far as your ftp script and your future other-users, just make sure they are in the same group as your apache user. Or, set up a group for those account you want to have access, and add your apache account to it.
In order to be able to manipulate files and directories without 0777 permissions, those files and directories need to be owned by the same user your PHP scripts run as.
You don't need to change things to 777, that gives the owner, group and guest all rights (read, write, execute). You can have it set to 755, or even 700 as long as the owner is whatever whatever the PHP process is running under. Typically this will be the Apache user, since the PHP script is running under the Apache process.
You don't need to give execute privs, but you need to give execute on the directories so that the process can do things like change directories (cd).
Nate, this relates to the basic 101s of UID and GID based access control. I am assuming that your "multiple uses" each have their own UIDs for FTP (and SSH?) access.
Typically files served by the webserver (Apache) must be read-accessible by the Apache child processes which will be running in www-data (or equiv) and hence must be o:r likewise any directories on the path to them must be o:e.
So you broadly have two options: (i) use a suEXEC / suPHP / FastCGI template to initiate PHP scripts in the UID of the owning directory, and (ii) run your scripts under mod_php5 and make any directories where you need script write-access owned by www-data.
This second approach is the most efficient in terms of machine resources, but it is terribly insecure as it in effect gives userA full R/W access to userB's resources and so on.
There's no way to square this circle. If you cannot guarantee shared trust between all users then you must read up on and implement a solution based on the (i) options.
Generally Folders should have 755 and files should have 644 permission set.
I'm facing this problem while working on PrestShop project.
Following PHP script solves my problem.
<?php
exec ("find /path/to/folder -type d -exec chmod 0755 {} +");
exec ("find /path/to/folder -type f -exec chmod 0644 {} +");
?>

Getting an uploaded file into home directory with proper ownership and permissions

I'm working on an upload script for students in my lab class to upload their assignments to a folder inside my home directory. The problem is that the script is run under the user apache and any directories and files created by the script end up owned by that user. In addition the permissions of the folder I wish the files to end up in have to be set wide open so that apache can create directories and move files into it (which of course will still be owned by apache).
I'm trying to replace an old script provided by the department which, among other problems, has about 5 different use cases where the student can receive a confirmation when the file wasn't actually uploaded. That script does use chown apparently without any of the problems PHP has. Perhaps the python interpreter runs with different access setting that the PHP one does.
What tactics are there for handling this?
There's a few ways to cope with this, but the most benign that I can imagine is to dedicated a sub-directory in your home directory for the purpose of uploading assignments.
All you have to do permissions wise is give the directory group ownership by some group the apache user belongs to. Suppose the webserver user is apache, and furthermore there is a group apache said user is a member of. You could also create a common group for this purpose that you and apache are part of.
Now let's say the directory you want to put the uploaded files in is ~/homework-submissions
As yourself
mkdir ~/homework-submissions
chgrp apache ~/homework-submissions
chmod g+a ~/homework-submissions
With this arrangement in place newly created files will be owned by apache:apache, but the webserver should have no problem changing ownership at this point.

PHP/CHMOD Questions

I am working on a PHP based website. In the admin there is a section that checks a form field and based on the field looks for a folder on the server. This folder will be in a sub-directory. If it does not exist it needs to be created. After that, previously existing or not, PHP will write file to the folder.
These folders will hold images and PDF files that will be viewed and/or downloaded on the main site.
Here is an example directory structure: merchants/east/user123
In the above merchants and east would definitely exist and user123 may exist or otherwise be created.
Given that info my questions are about folder permissions.
What should folders be set to for the best security.
Should I open them up wider during operations then chmod them (in PHP) after I'm done to something more secure?
What should upper level folders be set to?
770 would be a safe bet for the files. Setting it to that would disallow any public access. I would implement some sort of document delivery system in PHP. PHP will be able to access the non-public files and then send them to the user.
The upper level folders could be set to the same.
Update
As others have said, you can easily chmod them to 600 without any issues. That's the more secure way of handling it (prevents other users on the system from accessing the files). It also omits "execute", which isn't needed for file reading anyway. It's my personal practice to leave the extras in unless there's a defined reason not to.
The upper level folder would need to have read, write and execute permissions for the apache user., the top level folder could be owned by apache, and have permissions like 755 to allow the the webserver to read, write and list files.
You might think about permissions 750 or 700 if you are particularly concerned about other local users or services on the web server from seeing the files in this directory.
For file permissions: 644 or 600 as conventionally they do not need execute permission.
A nice compromise might be to use 750 for directories and 640 for files with owner set to apache, and change the group (chgrp) so that the group for the file allows access to the user that you normally edit the website files with.
I can't think of any significant advantage of the php script increasing and then reducing the permissions.
I think you should consider #chunk's comment about keeping the uploaded files own of the public html directory completely, and serving them back via an file delivery script. Otherwise you would need some careful validation of the content of the files and to tightening up the apache configuration for that particular directory - perhaps using some mimetype checking to make sure that the files really are docs and pdfs.

Categories