0
-= Security of user switching support in Passenger
0
+Security of user switching support in Passenger
0
+===============================================
0
-== Introduction and problem description
0
+Introduction and problem description
0
+------------------------------------
0
Passenger is an Apache module for Ruby on Rails support. When a URL of a Rails
0
application is accessed, Passenger will be responsible for forwarding the HTTP
0
request to the Rails application. Passenger does not run Rails applications
0
@@ -23,8 +24,8 @@ inform the reader about the solutions have we have analyzed, so that
0
Passenger's security may be reviewed.
0
-== Analysis of possible solutions
0
+Analysis of possible solutions
0
+------------------------------
0
It seems that the only way to solve this problem on Unix, is to run each Rails
0
application server as its owner's user and group. Passenger can make use of
0
one of the following methods to implement this:
0
@@ -40,19 +41,20 @@ one of the following methods to implement this:
0
Let us take a look at each method in detail.
0
-=== Apache must already be running as root
0
+Apache must already be running as root
0
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0
First, let us take a look at the typical Apache setup, in which Apache is bound
0
to port 80, and uses the prefork MPM. Binding to any port lower than 1024
0
requires root privileges, so Apache is typically run as root. This poses an
0
unacceptable security risk, so Apache's prefork MPM will, upon receiving an
0
HTTP request, spawn a child process with the privileges of a normal user,
0
-typically "www-data" or "nobody". See the documentation for the prefork MPM
0
-(http://httpd.apache.org/docs/2.2/mod/prefork.html) - in particular the
0
-"User" and "Group" directives - for details. The process which is responsible
0
-for spawning child processes (also called the control process) is run as root.
0
-This is also true for the worker MPM
0
-(http://httpd.apache.org/docs/2.2/mod/worker.html).
0
+typically 'www-data' or 'nobody'.
0
+See http://httpd.apache.org/docs/2.2/mod/prefork.html[the documentation for the
0
+prefork MPM] - in particular the ``User'' and ``Group'' directives - for details.
0
+The process which is responsible for spawning child processes (also called the
0
+control process) is run as root. This is also true for
0
+http://httpd.apache.org/docs/2.2/mod/worker.html[the worker MPM].
0
Since Passenger has access to the control process, in the typical Apache setup,
0
Passenger can already launch Rails applications as a different user. But now we
0
@@ -68,17 +70,18 @@ incredibly easy, and requires no new framework to be written. However, testing
0
this method in automated unit tests will require running the unit test suit as
0
-=== Using Apache's suEXEC
0
-Apache's suEXEC allows one to run CGI processes as different users. But it
0
-seems that suEXEC can only be used for CGI, and is not a general-purpose
0
-mechanism. The PHP-suEXEC software allows one to run PHP applications via
0
-suEXEC, but it requires patching suEXEC. If Passenger is to use suEXEC, then
0
-it is likely that we'll have to patch suEXEC. The suEXEC website strongly
0
-=== Using a setuid root wrapper application
0
+Apache's http://httpd.apache.org/docs/2.0/suexec.html[suEXEC] allows one to
0
+run CGI processes as different users. But it seems that suEXEC can only be
0
+used for CGI, and is not a general-purpose mechanism. The
0
+http://alain.knaff.lu/howto/PhpSuexec/[PHP-suEXEC] software allows one to run
0
+PHP applications via suEXEC, but it requires patching suEXEC. If Passenger is
0
+to use suEXEC, then it is likely that we'll have to patch suEXEC. The suEXEC
0
+website strongly discourages patching.
0
+Using a setuid root wrapper application
0
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0
If we use this method, we must be extremely careful. It must not be possible
0
for arbitrary processes to gain root privileges. We want Passenger, and only
0
Passenger, to be able to gain root privileges.
0
@@ -89,6 +92,7 @@ the use of proper file permissions. The password file must never be world
0
1. Passenger runs the wrapper.
0
2. Passenger passes the content of the password file to the wrapper, via
0
an anonymous pipe (or some other anonymous channel, that no other
0
@@ -111,8 +115,9 @@ process's user is in the whitelist.
0
Writing a wrapper is not too hard. Furthermore, unit tests do not have to be
0
run as root, in contrast to the run-Apache-as-root method.
0
-=== Using a setuid $X wrapper application.
0
+Using a setuid $X wrapper application
0
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0
A setuid $X wrapper will work in a fashion similar to the setuid root wrapper,
0
i.e. it will use a password file for authorization.
0
@@ -120,7 +125,7 @@ Passenger does not spawn Rails applications itself, but does so via the spawn
0
server. This spawn server is also responsible for preloading the Rails
0
framework and the Rails application code, in order to speed up the spawning
0
of Rails applications. See the design document of the spawn server for details.
0
-The spawn server never calls
exec(): doing so will make preloading useless.
0
+The spawn server never calls
`exec()`: doing so will make preloading useless.
0
If Passenger is to use a setuid $X wrapper, then it must start the spawn
0
server via the wrapper. The spawn server itself cannot use the wrapper.
0
@@ -132,13 +137,13 @@ methods.
0
Implementing this will also take more work. One has to create a different
0
wrapper for each user, and to install it.
0
The standard Unix 'su' tool asks for the root password. It's a bad idea for
0
Apache to know the root password, so using 'su' is not a viable alternative.
0
It might be possible to use the 'sudo' utility. sudo can be configured in
0
such a way that the user Apache runs as can use sudo without having to enter a
0
@@ -150,12 +155,12 @@ communicate with the spawn server via a non-anonymous channel, such as a named
0
Unix socket. Because other processes can access this channel, it can introduce
0
potential security problems. Note that passing information via program arguments
0
is not secure: it is possible to view that information with tools like 'ps',
0
-or (on Linux) by reading the file
/proc/$PID/cmdline.
0
+or (on Linux) by reading the file
`/proc/$PID/cmdline`.
0
So it seems 'sudo' is not a viable alternative.
0
-=== Common security issues
0
Whatever method Passenger will use, the following security principles must be
0
@@ -169,16 +174,16 @@ Also, the following questions remain:
0
the ability to restrict the set of users that Passenger can switch to?
0
Running Apache as root and writing a setuid root wrapper are the main
0
contestants. The former is preferred, because it's easier to implement.
0
We have had some conversations with people on the IRC channel #rubyonrails.
0
Among those people, nobody has ever run Apache as non-root. Because of this
0
-we have chosen to implement the "Running Apache as root" solution, until
0
-a significant number of users request us to implement the "setuid root wrapper"
0
+we have chosen to implement the <<apache_root,Running Apache as root>>
0
+solution, until a significant number of users request us to implement the
0
+<<setuid_root,setuid root wrapper>> solution.
0
See the Ruby API documentation for the 'ApplicationSpawner' class for
0
implementation details. In short: it will switch to the owner of the file
Comments
No one has commented yet.