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 run
root-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 as
root, in other words he/she takes over your whole system.
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 on
setuid-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
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 execute
root- 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
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
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
[slepi@nargothrond slepi]$ 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)); ...