38 使用 ChangeHat 构建 Web 应用程序的配置文件 #
AppArmor® 配置文件表示单个程序实例或进程的安全策略。它适用于一个可执行程序,但是,如果该程序的一部分需要与其它部分不同的访问权限,该程序可以“变换帽子”以使用有别于主程序访问权限的安全环境。这称作帽子或子配置文件。
ChangeHat 使程序能够在 AppArmor 配置文件内变成帽子或从帽子变成程序。这样您就可以定义比进程更细级别的安全性。此功能要求您将各应用程序配置为“感知 ChangeHat”,也就是说,将其修改为可以在应用程序执行期间的特定时间向 AppArmor 模块发出转换安全域的请求。Apache Web 服务器就是一款 ChangeHat 感知型应用程序。
一个配置文件可以有任意数目的子配置文件,但总共只能有两个级别:子配置文件不能有其他子配置文件。子配置文件是作为单独的配置文件编写的。其名称由包含配置文件的名称后接子配置文件名称构成,两者之间以 ^
^ 分隔。
子配置文件可存储在父配置文件所在的同一个文件中,也可存储在不同的文件中。在包含许多帽子的站点上,建议采用后一种存储方式 — 它使策略缓存能够在帽子级别处理更改。如果所有帽子都位于父配置文件所在的同一文件中,则必须重新编译父配置文件和所有帽子。
要用作帽子的外部子配置文件必须以单词 hat
或字符 ^
^ 开头。
下面两个子配置文件不能用作帽子:
/foo//bar { }
或
profile /foo//bar { }
而下面两个子配置文件将被视为帽子:
^/foo//bar { }
或
hat /foo//bar { } # this syntax is not highlighted in vim
帽子的安全性比完整配置文件的安全性要弱得多。攻击者有可能能够通过利用程序中特定类型的 bug 从帽子中逃脱并进入包含配置文件。这是因为,帽子的安全性由包含进程处理的某个机密密钥所决定,而帽子中运行的代码对该密钥不得拥有访问权限。因此,change_hat 在应用程序服务器中的作用最大。在这些服务器中,某个语言解释器(例如 PERL、PHP 或 Java)会隔离代码片段,以便防止这些代码直接访问包含进程的内存。
本章的其余内容将介绍如何在 Apache 中使用 change_hat 来包含通过 mod_perl
和 mod_php
运行的 Web 服务器组件。通过提供与第 38.1.2 节 “位置和目录指令”中介绍的 mod_apparmor
类似的应用程序模块,可以对任意应用程序服务器使用类似的方法。
有关更多信息,请参见 change_hat
手册页。
38.1 配置 Apache 以使用 mod_apparmor
#
AppArmor 为 Apache 程序提供 mod_apparmor
模块(apache2-mod-apparmor
软件包)。此模块使 Apache Web 服务器能够感知 ChangeHat。请连同 Apache 一起安装此模块。
当 Apache 可感知 ChangeHat 后,便会检查以下自定义的 AppArmor 安全配置文件,检查的顺序为向其收到的各 URI 请求指定的顺序。
URI 特定的帽子。例如,
^www_app_name/templates/classic/images/bar_left.gif
DEFAULT_URI
HANDLING_UNTRUSTED_INPUT
如果您安装了 apache2-mod-apparmor
,请确保启用该模块,然后执行以下命令重启动 Apache:
>
a2enmod apparmor && sudo systemctl reload apache2
Apache 的配置方式是在纯文本配置文件中放置指令。主配置文件为 /etc/apache2/httpd.conf
。编译 Apache 时,您可以指明此文件的位置。您可以将指令放置在这些配置文件的任一个中以改变 Apache 的行为方式。对主配置文件进行更改后,需使用 sudo systemctl reload apache2
重新加载 Apache,以便识别更改。
38.1.1 虚拟主机指令 #
<VirtualHost> 和 </VirtualHost> 指令用于封装一组仅应用于特定虚拟主机的指令。有关 Apache 虚拟主机指令的详细信息,请参见 https://httpd.apache.org/docs/2.4/en/mod/core.html#virtualhost。
特定于 ChangeHat 的配置关键字为 AADefaultHatName
。其用法与 AAHatName
类似,例如 AADefaultHatName
My_Funky_Default_Hat
。
您可以使用此关键字来指定用于虚拟主机和其他 Apache 服务器指令的默认帽子,这样便可对不同的虚拟主机使用不同的默认值。AAHatName
指令可以覆盖此关键字,仅当不存在匹配的 AAHatName
或者不存在 URI 所指定的帽子时,才检查此关键字。如果 AADefaultHatName
帽子不存在,它将回退到 DEFAULT_URI
帽子(如果存在)。
如果不存在匹配的帽子,则返回到“父” Apache 帽子。
38.1.2 位置和目录指令 #
位置和目录指令会在程序配置文件中指定帽子名称,以便 Apache 可调用与其安全性相关的帽子。对于 Apache,您可以在 https://httpd.apache.org/docs/2.4/en/sections.html 找到有关位置和目录指令的文档。
下面的位置指令示例针对给定的位置指定 mod_apparmor
应使用特定的帽子:
<Location /foo/> AAHatName MY_HAT_NAME </Location>
这会尝试将 MY_HAT_NAME
用于任何以 /foo/
开头的 URI(/foo/
、/foo/bar
、/foo/cgi/path/blah_blah/blah
等)。
目录指令的工作方式与位置指令相似,不同的是它代表的是文件系统中的路径,示例如下:
<Directory "/srv/www/www.example.org/docs"> # Note lack of trailing slash AAHatName example.org </Directory>
38.2 管理 ChangeHat 感知型应用程序 #
在上一节中,您已了解了 mod_apparmor
,以及它如何帮助您保护特定的 Web 应用程序。本节通过一个真实的示例来逐步讲解如何为某个 Web 应用程序创建帽子,并使用 AppArmor 的 change_hat 功能来保护该应用程序。由于 YaST 的 AppArmor 模块功能有限,本章主要使用 AppArmor 的命令行工具。
38.2.1 使用 AppArmor 的命令行工具 #
为便于演示,我们选择名为 Adminer (https://www.adminer.org/en/) 的 Web 应用程序。它是一个以 PHP 编写的全功能 SQL 数据库管理工具,不过只包括一个 PHP 文件。要正常运行 Adminer,您需要设置一个 Apache Web 服务器、PHP 及其 Apache 模块,以及一个适用于 PHP 的数据库驱动程序 — 本示例使用 MariaDB。您可使用以下命令安装所需的软件包
zypper in apache2 apache2-mod_apparmor apache2-mod_php5 php5 php5-mysql
要设置用于运行 Adminer 的 Web 环境,请执行以下步骤:
确保对 Apache 启用了
apparmor
和php5
模块。要在任何情况下均启用这些模块,请使用:>
a2enmod apparmor php5然后使用以下命令重启动 Apache
>
sudo
systemctl restart apache2确保 MariaDB 正在运行。如果不确定,请使用以下命令将其重启动
>
sudo
systemctl restart mariadb从 https://www.adminer.org 下载 Adminer,将其复制到
/srv/www/htdocs/adminer/
并重命名为adminer.php
,这样其完整路径就是/srv/www/htdocs/adminer/adminer.php
。在网页浏览器的 URI 地址字段中输入
http://localhost/adminer/adminer.php
以测试 Adminer。如果您将 Adminer 安装到了远程服务器上,请将localhost
替换为该服务器的实际主机名。图 38.1︰ Adminer 登录页 #提示如果您在查看 Adminer 登录页时遇到问题,请尝试检查 Apache 错误日志
/var/log/apache2/error.log
以寻求帮助。无法访问网页的另一个原因可能是,您的 Apache 已受 AppArmor 的控制,并且其 AppArmor 配置文件过于严格,不允许查看 Adminer。请使用aa-status
检查该配置文件,如果需要,可使用以下命令暂时将 Apache 设置为控诉模式#
sudo aa-complain usr.sbin.httpd2-prefork
Adminer 的 Web 环境就绪后,您需要配置 Apache 的 mod_apparmor
,使 AppArmor 能够检测对 Adminer 的访问以及对特定“帽子”进行的更改。
mod_apparmor
#Apache 在
/etc/apache2/
和/etc/apache2/conf.d/
下提供了多个配置文件。请选择所需的配置文件并在文本编辑器中打开。在此示例中,vim
编辑器用于创建新的配置文件/etc/apache2/conf.d/apparmor.conf
。>
sudo
vim /etc/apache2/conf.d/apparmor.conf将以下代码段复制到编辑后的文件中。
<Directory /srv/www/htdocs/adminer> AAHatName adminer </Directory>
当 Web 用户访问 Apache 文档根目录中的
/adminer
目录(以及该目录中的任何文件/目录)时,此代码段可让 Apache 告知 AppArmor 发生了 change_hat 事件。请记住,adminer.php
应用程序就放在该位置。保存文件,关闭编辑器,然后使用以下命令重启动 Apache
>
sudo
systemctl restart apache2
现在,Apache 就能识别 Adminer 并知道“帽子”发生的更改了。接下来我们在 AppArmor 配置中创建 Adminer 的相关帽子。如果您目前还没有 AppArmor 配置文件,请先创建一个,然后再继续。请记住,如果您的 Apache 主二进制文件为 /usr/sbin/httpd2-prefork
,则相关的配置文件命名为 /etc/apparmor.d/usr.sbin.httpd2-prefork
。
在文本编辑器中打开文件
/etc/apparmor.d/usr.sbin.httpd2-prefork
(如果该文件不存在,请创建一个)。其内容应如下所示:#include <tunables/global> /usr/sbin/httpd2-prefork { #include <abstractions/apache2-common> #include <abstractions/base> #include <abstractions/php5> capability kill, capability setgid, capability setuid, /etc/apache2/** r, /run/httpd.pid rw, /usr/lib{,32,64}/apache2*/** mr, /var/log/apache2/** rw, ^DEFAULT_URI { #include <abstractions/apache2-common> /var/log/apache2/** rw, } ^HANDLING_UNTRUSTED_INPUT { #include <abstractions/apache2-common> /var/log/apache2/** w, } }
在最后一个右花括号 (
}
) 前面插入以下部分:^adminer flags=(complain) { }
请注意帽子名称后面添加的
(complain)
— 此部分告知 AppArmor 将adminer
帽子保持控诉模式。这是因为,我们稍后需要通过访问 Adminer 来了解帽子配置文件。保存文件,然后依次重启动 AppArmor 和 Apache。
>
sudo
systemctl reload apparmor apache2检查
adminer
帽子是否确实处于控诉模式。>
sudo
aa-status apparmor module is loaded. 39 profiles are loaded. 37 profiles are in enforce mode. [...] /usr/sbin/httpd2-prefork /usr/sbin/httpd2-prefork//DEFAULT_URI /usr/sbin/httpd2-prefork//HANDLING_UNTRUSTED_INPUT [...] 2 profiles are in complain mode. /usr/bin/getopt /usr/sbin/httpd2-prefork//adminer [...]我们可以看到,
httpd2-prefork//adminer
是以控诉模式加载的。
最后一个任务是找出 adminer
帽子的正确规则集。这就是我们将 adminer
帽子设置为控诉模式的原因 — 当我们通过网页浏览器使用 adminer.php
时,日志记录工具将收集有关其访问要求的有用信息。然后,aa-logprof
将帮助我们创建该帽子的配置文件。
adminer
帽子的规则 #在网页浏览器中打开 Adminer。如果您在本地安装了 Adminer,则 URI 为
http://localhost/adminer/adminer.php
。选择要使用的数据库引擎(在本例中为 MariaDB),并使用现有的数据库用户名和口令登录 Adminer。您此时不需要指定数据库名称,可以在登录后再指定。使用 Adminer 执行所需的任意操作 — 创建新数据库、创建数据库的新表、设置用户特权,等等。
简单测试 Adminer 的用户界面后,切换回控制台并检查日志中收集的数据。
>
sudo
aa-logprof Reading log entries from /var/log/audit/audit.log. Updating AppArmor profiles in /etc/apparmor.d. Complain-mode changes: Profile: /usr/sbin/httpd2-prefork^adminer Path: /dev/urandom Mode: r Severity: 3 1 - #include <abstractions/apache2-common> [...] [8 - /dev/urandom] [(A)llow] / (D)eny / (G)lob / Glob w/(E)xt / (N)ew / Abo(r)t / (F)inish / (O)pts通过
aa-logprof
消息,我们可以确定系统已正确检测到这个新的adminer
帽子:Profile: /usr/sbin/httpd2-prefork^adminer
aa-logprof
命令会要求您选取每个已发现的 AppArmor 事件的正确规则。指定要使用的规则,并使用 确认。有关使用aa-genprof
和aa-logprof
接口的详细信息,请参见第 37.7.3.8 节 “aa-genprof — 生成配置文件”。提示aa-logprof
针对所检查的事件提供多个有效规则。有些规则属于抽象 — 影响特定的常用目标组的预定义规则集。包含这样的抽象(而非直接的 URI 规则)有时会很有用:1 - #include <abstractions/php5> [2 - /var/lib/php5/sess_3jdmii9cacj1e3jnahbtopajl7p064ai242]
在上面的示例中,建议点击
并使用 确认,以允许抽象。完成最后一项更改后,系统会要求您保存更改的配置文件。
The following local profiles were changed. Would you like to save them? [1 - /usr/sbin/httpd2-prefork] (S)ave Changes / [(V)iew Changes] / Abo(r)t
点击
保存更改。使用
aa-enforce
将配置文件设置为强制模式>
sudo
aa-enforce usr.sbin.httpd2-prefork然后使用
aa-status
检查其状态>
sudo
aa-status apparmor module is loaded. 39 profiles are loaded. 38 profiles are in enforce mode. [...] /usr/sbin/httpd2-prefork /usr/sbin/httpd2-prefork//DEFAULT_URI /usr/sbin/httpd2-prefork//HANDLING_UNTRUSTED_INPUT /usr/sbin/httpd2-prefork//adminer [...]我们可以看到,
//adminer
帽子已从控诉模式转变为强制模式。尝试在网页浏览器中运行 Adminer,如果在运行时遇到问题,请将它切换到控诉模式,重复前面出现问题的步骤,并使用
aa-logprof
更新配置文件,直到您对应用程序的功能感到满意为止。
配置文件 ^adminer
仅在基于父配置文件 usr.sbin.httpd2-prefork
运行的进程的环境中可用。
38.2.2 在 YaST 中向帽子添加帽子和项 #
使用第 36.2 节 “编辑配置文件”),或者使用 添加新的配置文件时(有关使用方法,请参见第 36.1 节 “手动添加配置文件”),您具有将帽子(子配置文件)添加到 AppArmor 配置文件的选项。如下所示通过 窗口添加 ChangeHat 子配置文件。
对话框时(有关使用方法,请参见