Elevating priviledges from webscripts
By Flib
2009-05-04
Category: PHP
The problem
There are times when your permissions just aren't enough. The Unix (and Linux by extension) security model enforces separation of permissions of users. You don't normally want one person's code writing over someone else's files. There are exceptions though.
In this article I try to explain the basics of the security model, how to work within it and how to work around it.
This article contains examples that can be very insecure if used badly. Please be aware of this and look for more secure options first before considering these options
The Solution
Permissions
If we ignore SELinux and similar security extensions, the Unix security is fairly simple. Each file or directory has a set of flags, an owner and a group that specify who is able to access or execute it.
These flags are as follows.
| r(ead) | w(rite) | x(ecute) |
| owner | ||
| group | ||
| other |
When each bit or flag is turned on, that permission applies. So if the owner-read bit is enabled, the owner of the file has read access to the file. Its similar with write permissions and execute permissions.
Permissions for a directory are slightly different. Read access allows the user to list the contents of the directory, execute gives access to the files in the directory or to change into the directory.
Groups
Groups allow users to be placed together in such a way as they can share certain permissions. A user can be a member of more than one group. The usual way this is done is to have a directory that is writable by a group. Any user of the group can then add files to the directory. If you want files written to the directory to be owned by the same group as the directory itself then you will need to set the s bit for the directory.
Changing your permissions
To change permissions for any file or directory the chmod command is used.
chmod [options] file
Bypassing restrictive permissions through scripting.
FTP
On many systems FTP is configured to write files with the owner as the ftpuser. For systems where all scripts are execcuted as another unpriviledged user, this can be used to write files to directories that the unpriviledged user alone can not.
This technique is seen occassionly in some Content Management Systems (CMSs) and weblog software. Its useful because it doesn't require anything special from the server.
sudo
For many embedded solutions such as network appliances or control panels, using ftp is undesirable. It requires a running ftp daemon, which can open security holes up, and requires that the ftp server is configured in a way that might not be desirable or possible for some applications.
For this reason, many apps use sudo (or similar solutions) to run one or more scripts with elevated privileges.
On a typical webserver this is accomplished by adding a line to the /etc/sudoers file such as
apache ALL= (root) NOPASSWD: /path/to/script/script.php
where apache is the user that your scripts are commonly run as and /path/to/script/script.php is the executable script that you wish to run with elevated permissions.
If you get the error
sudo: sorry, you must have a tty to run sudo
then you will need to disable the option
RequireValidTTY
in /etc/sudoers
Note: It is important to sanitise all input your script accepts, since an error could introduce serious security holes in your server.
cron
An alternative to sudo is cron. Cron is used to run repetitive tasks at predefined intervals.
For example,
Every day at 6.30am
Every Monday at 1am
Every 15th day of the month at 1,3,5 and 7am
SSH
SSH can be used to send arbitrary commands to remote machines (or local using a loopback interface) the same way that rsh used to be able to (before security became an issue).
You can do this using
ssh user@host
however this will require you to type in your password which is not ideal if you are running it from a script.
You can avoid this requirement by setting up keybased authentication. I wont go into it here, since there are already many decent tutorials online that cover it fairly well, but once this is setup you can can do something similar to the following
ssh -i /path/to/my/privatekey user@host
and command will be executed on the remote machine without any password required.
This can be a security risk especially if a root user is used. However you can secure this on the server side using options in the ssh remote user authorized_keys file in the .ssh directory within the users home directory.
The most useful options (consult the documentation for more) are
from="hostlist"
command="shell command"
no-port-forwarding
no-X11-forwarding
no-agent-forwarding
no-pty
from allows you to limit what machines are allowed to connect using this key and command forces the use of a particular executable on the server on connection. This isn't the end of the world however since the command that you passed on the command line ends up in $SSH_ORIGINAL_COMMAND.
If you combine them, you can allow only localhost to login and ask the enforced command to do something with the arguments passed on the commandline.
The best part about this solution is it isn't limited to a single machine. It can scale up to clusters just as easily.
other wrappers / options
There are other options such as using a root owned script and suphp and pinging the script from the webserver or using a setuid binary (scripts wont work for this), but it really depends on your requirements.