Using sudo to Execute root-privileged Commands
One of most frequently asked questions I find in the web development mailing list is "How can I execute a root-privileged commands from my scripts?". I found this question so often that I think it would be worthy for me to write this entry. There are several solutions for this situation however, and each comes with different impacts on both performance and security degree of the application.
Three commonly known solutions are:
- Running the web server daemon as
root. A very very bad and insecure solution. This is the simplest way of enabling your script to runroot-privileged commands. However no one would recommend this, including me. This practice exposes a very serious security hole in your application. Little mistake in your coding, might enable some nasty users to send well crafted request to your server and take over your web server. And since the service runs asroot, in other words he/she takes over your whole system. - Using
suEXECfeature of Apache HTTP Server. This Apache built-in solution (though it doesn't included in the default installation) offers a secure way to execute system commands. However there are some performance hits come with this technique.suEXECis based onsetuid-wrapper program provided by Apache that performs 20 security checkings (as per version 2.2), before that wrapper program launches the target system command. For a more detailed information please refer to Apache HTTP Server Documentation - Utilising
sudo. This is my favorite, otherwise the title of this writing won't be the one you clicked a moment ago.sudois a *nix system utility to enable non-root user to executeroot- or other-user-privileged commands or scripts. The central of this utility is a configuration file/etc/sudoers, where all sudo rules are defined, including the host, user, and command configuration.
The Scenario: Enabling nobody user to execute kill * command
By default Apache HTTP Server runs either as apache or nobody user. For the example I'll use nobody however, to make it clear that sudo is in fact a system-wide utility, designed not just for web related tasks.
All you need to do is to edit the file /etc/sudoers, and put some declarations about the system user, command, and host involved in your application. Although you could edit the file manually using pico or vi, it is strongly recommended you use visudo, special editor for sudo that will check for syntax mistakes every time you save the file. You need to login as root in order to launch visudo.
[root@nargothrond root]# visudo
For the scenario, the /etc/sudoers file would look something like this one:
...
# Host alias spec.
# Typically this would be the IP address of the Apache HTTP Server
# In this example we set the host with alias name LOKAL
Host_alias LOCAL=127.0.0.1
# Command alias spec.
# Set alias for /bin/kill command to KILL
Cmnd_alias KILL=/bin/kill *
# Finally, user privilege spec.
# The line below says that
# the user nobody may execute the KILL command (/bin/kill) without password from host LOCAL (127.0.0.1)
nobody LOCAL=NOPASSWD:KILL
...
The file and comments are quite self-explanatory there, so I don't think it needs further explanations. And now assume you run a PHP-based web application with Apache HTTP Server runs as nobody, and one of the application's need is to kill process with PID 1234. You would write this line somewhere in your PHP script then:
...
$PID = '1234';
shell_exec('sudo /bin/kill ' . escapeshellarg($PID));
...