suEXEC支持

suEXEC特性使得Apache可以使用与调用web服务器的用户不同的用户身份来运行CGISSI程序。而通常情况下,CGI或者SSI程序执行时使用和web服务器相同的用户身份。

正确运用该特性,可以减少很多因为提供用户执行私有CGI或者SSI程序所带来的安全风险。但如果配置不当的话,则可能引起很多问题,使你的计算机产生更多的安全漏洞。如果你对管理 setuid root 程序以及可能导致的安全问题不熟悉的话,我们强烈建议你不要使用suEXEC。

开始之前

在我们开始切入正题之前,你必须明白Apache开发组以及本文档所做的假设。

首先,我们假设你正在使用类UNIX操作系统,只有这类操作系统才具有setuidsetgid命令。所有的其他命令行的例子也是如此。其他的操作系统平台,即使也支持suEXEC,但是它的配置可能和我们所讲的并不相同。

第二,我们假设你熟悉计算机的安全和管理计算机的一些基本概念。这关系到如何正确理解setuid/setgid操作以及对你的系统可能带来的各种影响和不同的安全等级。

第三,我们假设你正在使用源代码未经修改的suEXEC版本。所有suEXEC的代码都经过开发者的仔细查验并做过大量测试。在这些代码中,人们采取了各种预防措施,使之简单、健壮、安全。修改这些代码可能会导致预料之外的问题和安全隐患。所以我们强烈地建议你不要修改代码,除非你精通安全编程,并愿意和Apache开发组共享成果。

第四,也是最后一点,Apache开发组已经决定默认不安装suEXEC。suEXEC的配置需要管理员细致关注各个细节。在仔细考察过关于suEXEC的各种设置方法后,管理员应该使用标准的安装方法来安装suEXEC。设置的参数应该经过仔细推敲,以保证系统的安全运行。Apache开发组希望通过限制suEXEC的安装,仅使那些经过细致理解,并有能力运用它的管理员来使用。

你还想使用suEXEC吗?还想?很好!那我们开始吧!

suEXEC的安全模型

在我们开始配置和安装suEXEC之前,我们需要先讨论一下它的安全模型。这样,你才能更好的理解suEXEC内部究竟做了些什么事情,以及哪些确保系统安全的预防措施。

suEXEC是基于一个setuid的"封装"程序,该程序由"主"Apache web服务器调用。当一个HTTP请求的是管理员指定的、以不同于"主"服务器用户身份运行的CGI或SSI程序时,该封装程序将被调用。处理这样的请求时,Apache将被请求的程序名及其UID和GID提供给suEXEC封装器。

封装器(wrapper)通过处理下面所描述的步骤,来决定封装的成功或失败:如果有任意一个条件为假,程序将把错误情况记录到日志中,退出并返回错误信息。否则继续执行。(以下所说的"程序"均指"CGI/SSI程序")

  1. 用户使用了合法的系统账号来执行封装程序了吗?

    确保运行封装器的是一个系统中确实存在的用户。

  2. 封装器被调用时,使用的参数个数正确吗?

    封装器仅在使用了正确数量的参数调用时才会执行。Apache web服务器知道正确的参数格式是什么。如果封装器没有收到正确数量的参数,则说明要么被黑客攻击,要么Apache二进制代码中suEXEC的部分出了问题。

  1. 这个合法的用户被允许运行封装器吗?

    这个用户是可以运行封装器的用户吗?仅有一个用户(Apache用户)被允许运行封装器。

  2. 目标CGI/SSI程序有不安全的分级路径索引吗?

    目标CGI/SSI程序包含了"/"开头或者有".."后向路径索引吗?这些都是不允许的;并且目标程序必须位于suEXEC的文档根目录下。(参见下面的:--with-suexec-docroot=_DIR_)

  3. 目标程序的所属用户名合法吗?

    目标程序的所属用户名存在吗?

  4. 目标程序的所属用户组合法吗?

    目标程序的所属用户组存在吗?

  5. 目标程序的所属用户名不是超级用户吗?

    目前,suEXEC不允许root执行CGI/SSI程序。

  6. 目标程序所属用户的UID高于最小UID值吗?

    最小UID值是在配置中指定的。你可以指定允许执行CGI/SSI程序的最小UID值,这样可以保证不会和系统账号冲突。

  7. 目标程序的所属用户组不是超级用户组吗?

    目前,suEXEC不允许root组用户执行CGI/SSI程序。

  8. 目标程序所属用户组的GID高于最小GID值吗?

    最小GID值是在配置中指定的。你可以指定允许执行CGI/SSI程序的最小GID值,这样可以保证不会和系统账号冲突。

  9. 封装器能够成功地变为目标用户和组吗?

    这里就是程序变为目标用户和组的关键步骤了。我们是通过调用setuid和setgid来实现的。在组访问列表中,和该用户相关的所有组信息都将被初始化。

  10. 能够切换到程序所在的目录吗?

    如果不存在,将无法包含程序文件。如果不能切换一般也表示目录不存在。

  11. 这个目录在Apache的网络空间中吗?

    如果是对于服务器的一般请求,那么请求的目录是在suEXEC的根文档目录下吗?如果请求的是一个用户目录,那么该目录是在suEXEC配置的该用户的根目录下吗?(参见:suEXEC配置选项)

  12. 该目录不具有其他用户可写的权限吗?

    我们不想把目录开放给其他人;只有属主才可以改变该目录中的内容。

  13. 目标CGI/SSI程序存在吗?

    如果不存在,当然无法继续运行。

  14. 目标CGI/SSI程序不可以被其他用户改写吗?

    我们不想给其他人有修改程序的权限。

  15. 目标程序尚未被setuid或者setgid ?

    我们不想要执行的程序被再次改变UID/GID。

  16. 目标用户和组与程序的用户和组相同吗?

    用户是这个文件的属主吗?

  17. 我们可以成功清除进程的环境变量并保证操作的安全性吗?

    suEXEC通过建立一个安全的可执行路径(在配置中定义)来清除该进程的环境变量,同时只传送在安全环境变量列表(配置中定义)中所列出的环境变量。

  18. 可以成功的变为目标程序并执行吗?

    这里就是suEXEC结束,并开始运行目标程序的地方了。

这是suEXEC封装器标准操作方式的安全模型。它有些严格,并强加了CGI/SSI设计上的限制。但它是仔细考虑过安全之后一步步发展起来的模型。

更多关于该安全模型如何根据服务器的配置来限制使用者的权限,以及恰当的suEXEC安装步骤能够避免的安全隐患,请参见警告和举例部分。

配置和安装suEXEC

继续我们的探险 ...

suEXEC配置选项

--enable-suexec

该选项启用默认禁止的suEXEC功能。并同时至少提供一个 --with-suexec-xxxxx 选项,以使APACI使用suEXEC功能来处理请求。

--with-suexec-bin=_PATH_

出于安全考虑,suexec二进制程序的路径必须用这个选项指定并硬编码在服务器里。比如:--with-suexec-bin=/usr/sbin/suexec

--with-suexec-caller=_UID_

Apache运行时所用的UID。这是唯一允许执行程序的用户。

--with-suexec-userdir=_DIR_

定义suEXEC允许访问的用户宿主目录下的子目录。suEXEC将以用户身份执行这个目录下的所有可执行程序,所以这些程序必须是"安全程序"。如果使用"简单的"UserDir指令(即不带""),则此处应该被设置为相同的值。当UserDir指令所指向的目录与"passwd"文件所指定的用户宿主目录不同时,suEXEC将不会正常工作,其默认值是"public_html"。如果所支持的虚拟主机对每个用户有不同的UserDir ,则应该把他们集中在同一个父目录下,而用这个参数指向这个父目录。*如果配置不当,"~userdir"下的cgi请求将无效!

--with-suexec-docroot=_DIR_

定义Apache的DocumentRoot。它是除UserDir外suEXEC唯一可以使用的目录。其默认目录是 --datadir 值所指定的带有"/htdocs"的后缀的目录,比如:如果配置了"--datadir=/home/apache",那么"/home/apache/htdocs"目录将作为suEXEC处理器的文档根目录。

--with-suexec-uidmin=_UID_

定义了suEXEC目标用户的最低UID。对大多数系统,一般是500或100。默认值是100

--with-suexec-gidmin=_GID_

定义了suEXEC目标组的最低GID。对大多数系统,是100,默认值也是100。

--with-suexec-logfile=_FILE_

它定义了suEXEC用于记录所做的事情以及发生的错误的日志文件名(对审核和排错很有用),默认文件名是"suexec_log",并位于标准的日志文件目录中(--logfiledir)。

--with-suexec-safepath=_PATH_

定义传给CGI程序的一个安全的PATH环境变量的值。默认值是"/usr/local/bin:/usr/bin:/bin"

编译和安装suEXEC处理器 若用 --enable-suexec 打开了suEXEC功能,那么执行make命令时(Apache自带的)suexec二进制文件就会被自动建立。所有组件编译完毕后执行 make install 命令进行安装时,suexec文件将被安装在 --sbindir 选项指定的目录中,默认为"/usr/local/apache2/sbin/suexec"。 注意,安装过程需要root权限。为了使suEXEC处理器可以设置UID,其所有者必须为_root_ ,并且文件模式中的执行位必须设置为1(允许执行)。

设置许可权限 虽然suEXEC包装会检查以确保它的调用者就是配置选项 --with-suexec-caller 所指定的用户。但是总是存在这样的可能性:一个系统或者库在suEXEC执行用户身份检查之前调用它,这样就存在一个可利用的漏洞。通常,避免这种问题的最佳办法是,使用文件系的统权限来确保只有Apache组用户运行的程序才能执行suEXEC。

如果你的web-server是按照如下所示进行配置的:

    User www

    Group webgroup

并且suexec被安装在"/usr/local/apache2/sbin/suexec"目录,你应当运行以下命令:

    chgrp webgroup /usr/local/apache2/bin/suexec

    chmod 4750 /usr/local/apache2/bin/suexec

这将确保只有Apache组用户运行的程序才能执行suEXEC。

启用和禁用suEXEC

Apache在启动过程中,会在 --sbindir 选项指定的目录(默认为:"/usr/local/apache/sbin/suexec")中寻找suexec。如果Apache找到了一个正确配置的suEXEC处理器,会在错误日志中记录以下信息:

    [notice] suEXEC mechanism enabled (wrapper: <var class="calibre40">/path/to/suexec</var>)

如果服务器启动后没有这个信息,那么很可能是服务器没找到适当的处理器,或者是这个执行程序没有安装setuid root

如果要在Apache服务器运行过程中打开suEXEC功能,则必须停止并重新启动Apache。用一个简单的HUP或USR1信号来重新启动是不够的。

如果要关闭suEXEC功能,应该删除suexec文件,并停止和重新启动Apache。

使用suEXEC

对CGI程序的请求仅在下述两种情况下才会调用suEXEC包装:对一个含SuexecUserGroup指令的虚拟主机发起请求,或者该请求由mod_userdir模块处理。

虚拟主机: 使用suEXEC处理器的方法之一是在VirtualHost定义中使用SuexecUserGroup指令。通过设置这个指令来确定不同于主服务器的UID,所有对CGI资源的请求将以<VirtualHost>所定义的UserGroup身份执行。如果<VirtualHost>中没有这个指令,则将以主服务器的UID身份执行。

用户目录:mod_userdir处理的请求会调用suEXEC处理器以被请求的用户目录所属的UID执行CGI程序。此功能的唯一要求是,此用户必须有CGI执行权限,并且其脚本符合上述安全检查的要求。参见 --with-suexec-userdir 编译选项

调试suEXEC

如上所述,suEXEC处理器会在 --with-suexec-logfile 选项所指定的日志文件中记录信息。如果你感觉配置和安装不正常,可以查看这个日志以及服务器的错误日志。

谨防Jabberwock:警告和举例

注意!这部分文档可能还没有完成。查看最新的修订版本,请到Apache开发组的在线文档

以下是有关限制和服务器安装的几个注意事项,在提交任何关于suEXEC的"bugs"以前,请仔细阅读。

  • suEXEC注意事项
  • 层次限制

    出于安全和效率考虑,所有suEXEC请求必须被限制在虚拟主机或者用户目录的顶层。举例来说,如果你配置了4个虚拟主机,你必须把所有虚拟主机的文档根目录都安置在同一个主Apache目录中,这样才能为虚拟主机启用suEXEC。(例子以后会有的)

  • suEXEC的PATH环境变量

    改变这个变量的值是危险的,必须确保其中每个路径都是可以信任的目录。你不会希望谁都可以在你的服务器上安装特洛伊木马。

  • 改变suEXEC的代码

    重申,如果你不清楚你在干什么就尽量避免,否则会带来大麻烦的。