SELinux 中 Apache HTTP 详解

在使用CentOS时多多少少会涉及SELinux,尤其是针对Web服务,大部分的做法是关闭SELinux,正确的做法是设置好SELiunx,可以防范网站攻击风险。

本文参照官方SELinux文档整理

1. Apache HTTP服务和SELinux

当SELinux启动,Apache HTTP服务(httpd)默认运行在受限模式下。运行的进程只能在设定好的域domains内运行,并与其他受限进程分开。如果一个受限进程被攻击,依靠SELinux策略policy配置,攻击者访问的资源和可能的损失都会被限制。
接下来演示一下:

  1. 运行getenforce命令确认SELinux的运行在enforcing强制模式下:
~]# getenforce 
Enforcing
  1. 查看httpd的状态,确认服务正在运行:
~]# systemctl status httpd.service
httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: active (running) since Mon 2018-11-05 17:13:09 CST; 43min ago
  1. 查看httpd进程是否关联了SELinux context(上下文):
~]# ps -eZ | grep httpd
system_u:system_r:httpd_t:s0     30275 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     30276 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     30277 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     30278 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     30279 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     30280 ?        00:00:00 httpd

通过ps命令的-Z参数可以查看进城SELinux上下文状态。
SELinux 上下文与httpd进程关联内容为,system_u:system_r:httpd_t:s0。其中httpd_t是SELinux的类型type。这个类型定义了一个进程域domain和一个文件类型type
当前httpd进程运行在httpd_thttpd_t中。

SELinux策略policy定义了在受限域(如httpd_t)中运行的进程,如何与文件、其他进程和系统进行交互。

文件必须被正确标记label,以通过httpd访问它们。比如:httpd可以读取标记为httpd_sys_content_t类型的文件,但是不能进行写入操作,即便是文件加入了写入权限,如下:

~]# ls -Z /var/www/html/index.html
-rw-rw-rw-. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.html

SELinux的布尔型设置boolean必须启动,以便允许确定的行为,比如,允许脚本网络访问,允许httpd访问NFSCIFS卷,或者httpd允许执行CGI脚本。

2. Apache HTTP端口与SELinux端口

/etc/httpd/conf/httpd.conf文件配置完,httpd监听一个或多个端口,比如80,443,448,8080,8009或者8443等等。
必须使用semanage port命令添加新的端口到SELinux策略配置中。
下面演示使用新的httpd端口后,必须添加SELinux端口策略,否侧httpd无法启动。

  1. 确认httpd服务没有运行
~]# systemctl stop httpd
~]# systemctl status httpd.service 
 httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
  1. 使用semanage工具查看当前关于httpd的监听端口:
~]# semanage port -l | grep -w http_port_t
http_port_t  tcp  80, 81, 443, 488, 8008, 8009, 8443, 9000
  1. 编辑/etc/httpd/conf/httpd.conf文件,修改Listen的端口号为12345,可以确认12345端口不再SELinux策略policy配置中:
~]# vim /etc/httpd/conf/httpd.conf
---
#Listen 12.34.56.78:80
Listen 12345
---
  1. 再次启动httpd查看结果:
~]# systemctl start httpd
Job for httpd.service failed because the control process exited with error code. 
See "systemctl status httpd.service" and "journalctl -xe" for details.

~]# ausearch -m avc -c httpd
type=AVC msg=audit(1541420299.439:1731): avc:  
denied  { name_bind } for  pid=51139 comm="httpd" src=12345 
scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 
tclass=tcp_socket

httpd服务无法启动
使用ausearch命令查看SELinux相关日志
日志显示SELinux已经拒绝(denied)启动httpd服务

  1. 现在允许httpd监听12345端口
~]# semanage port -a -t http_port_t -p tcp 12345
~]# semanage port -l | grep httpd
http_port_t  tcp  12345, 80, 81, 443, 488, 8008, 8009, 8443, 9000
  1. 再次启动httpd服务,可以看到添加端口后,服务正常启动了
~]# systemctl start httpd.service

为了保证能正常访问,还需要在防火墙中添加端口12345

~]# firewall-cmd --permanent --add-port=12345/tcp
~]# firewall-cmd --reload
  1. 至此可以发现SELinux中对于端口的限制策略。

注意:
a. semanage port 删除端口,使用 -d参数即可
semanage port -d -t http_port_t -p tcp 12345
b. firewall-cmd删除端口,使用--remove-port参数
firewall-cmd --permanent --remove-port=12345/tcp
firewall-cmd --reload

3. 类型上下文(TYPES)

在SELinux的默认策略targeted中,高级进程隔离的主要权限控制方法是使用类型强制Type EnForcement
所有文件和进程都使用类型type标签label来标记:为进程定义一个SELinux域domain类型,为文件定义一个SELinux类型type
SELinux策略规则定义了类型如何互相访问,域是不是正在访问一个类型,或者一个域访问其他的域。
只有在指定SELinux策略规则允许访问时,才能访问。

参照下面例子在/var/www/html/目录中创建一个新文件,显示当前文件是继承了父目录/var/www/html/目录下的httpd_sys_content_t类型:

  1. 查看/var/www/html/目录的SELinux上下文context
~]# ls -Zd /var/www/html
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html/

可以看到当前目录使用的是httpd_sys_content_t类型
所有的类型上下文都用_t结尾

  1. 创建一个新文件再次验证文件的类型上下文:
~]# touch /var/www/html/myfile1
~]# ls -Z /var/www/html/myfile1
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/myfile1

可以看到文件的类型上下文被标记为httpd_sys_content_t,说明这是继承了父目录的类型上下文。

使用httpd_sys_content_t类型,那么SELinux允许httpd读取当前文件,但不允许写操作,即便是给文件加入了写权限。
SELinux策略定义了运行在httpd_t域中的进程可以读写的类型,这有助于防止进程访问其他进程使用的文件。

例如:httpd能访问标记为httpd_sys_content_t类型的文件,但是默认情况下不能访问标记为samba_share_t类型的文件。
同样,在用户主目录中的文件被标记为user_home_t类型:默认在用户目录中,不允许httpd读取或写入文件。

下面列出了一些关于httpd的类型,不同的类型允许灵活的配置和访问:

httpd_sys_content_t
这个类型针对静态web内容,比如静态网站使用的.html文件。
标记为这种类型的文件,httpd可以读取访问,并且可以执行脚本。
默认情况下,标有此类型的文件和目录不能被httpd或其他进程写入或修改。
需要注意的是,默认情况下,在/var/www/html/目录中创建或复制的文件都用httpd_sys_content_t类型标记。

httpd_sys_script_exec_t
如果希望httpd执行的脚本,使用这种类型。
这种类型通常用于/var/www/cgi-bin/目录中的通用网关接口(CGI)脚本。
默认情况下,SELinux策略阻止httpd执行CGI脚本。为了实现这一点,使用httpd_sys_script_exec_t类型标记脚本,并启用httpd_enable_cgi布尔值。
httpd_sys_script_exec_t标记的脚本在httpd_sys_script_t域中运行时被httpd执行。
httpd_sys_script_t域可以访问其他系统域,比如postgresql_tmysqld_t

httpd_sys_rw_content_t
标记为这种类型的文件可以由标记为httpd_sys_script_exec_t类型的脚本写入,但不能被标记为任何其他类型的脚本修改。
标记为httpd_sys_rw_content_t类型来标记文件,将由具有httpd_sys_script_exec_t类型的脚本读取和写入。

httpd_sys_ra_content_t
标记为这种类型的文件可以由标记为httpd_sys_script_exec_t类型的脚本追加写入,但不能由标记为任何其他类型的脚本修改。
使用httpd_sys_ra_content_t类型来标记的文件,将由标有httpd_sys_script_exec_t类型的脚本读取并追加到这些文件中。

httpd_unconfined_script_exec_t
标记为这种类型的脚本,意味着脚本不受限,运行在没有SELinux保护的情况下。
在无可奈何的情况下,针对对复杂脚本使用此类型。
换个角度来说,最好使用这种类型,而不是对httpd或整个系统禁用SELinux保护。

4. 修改SELinux上下文context

a. 临时修改上下文

可以通过使用chcon命令修改文件和目录的类型上下文。chcon的修改模式是临时的,当系统重新标记relabel或者执行restorecon命令时就会失效。
SELinux策略控制用户是否能够修改指定文件的SELinux上下文。
接下来演示,创建一个新的目录/my/website/index.html文件供httpd使用,并且设置标签允许httpd访问:

  1. 在根目录下,创建一个新的目录,查看当前目录的上下文状态:
~]# mkdir -p /my/website
~]# ls -dZ /my
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /my

可以看到默认新建的目录的类型上下文是default_t

  1. 使用chcon命令修改/my/目录及子目录的类型上下文:
~]# chcon -R -t httpd_sys_content_t /my/
~]# ls -dZ /my
drwxr-xr-x. root root unconfined_u:object_r:httpd_sys_content_t:s0 /my
~]# ls -Z /my
drwxr-xr-x. root root unconfined_u:object_r:httpd_sys_content_t:s0 website

可以看到/my/目录和子目录/website的类型上下文都修改为httpd_sys_content_t
chcon命令的-R参数是递归全部子目录和文件
chcon命令的-t参数是添加一个类型

  1. 创建一个新文件,查看文件的类型上下文:
~]# touch /my/website/index.html
~]# ls -Z /my/website/index.html 
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /my/website/index.html

可以看到,新建文件自动继承了,所在文件夹的类型上下文

b. 永久修改上下文

使用semanage fcontext命令是创建一个标签,并在重新标记,配合restorecon命令使用。
步骤:先使用semanage fcontext修改文件上下文的配置,然后运行restorecon,读取文件的上下文配置,并且允许修改标签。
接下来还是使用上面的例子来演示,创建一个新的目录/my/website/index.html文件供httpd使用,并且设置标签允许httpd访问:

  1. 在根目录下,创建一个新的目录,查看当前目录的上下文状态:
~]# mkdir -p /my/website
~]# ls -dZ /my
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /my
  1. 使用semanage fcontext命令修改类型上下文:
~]# semanage fcontext -a -t httpd_sys_content_t "/my(/.*)?"
~]# ls -dZ /my
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /my

可以看到使用semanage fcontext命令后,文件夹的类型上下文并没有发生变化。

  1. 创建一个新的文件:
~]# touch /my/website/index.html
~]# ls -Z /my/website/index.html 
-rw-r--r--. root root unconfined_u:object_r:default_t:s0 /my/website/index.html

新建的文件index.html类型上下文也没有发生改变

  1. 接下来使用restorecon命令重新读取文件上下文配置:
~]# restorecon -R -v /my/
restorecon reset /my context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
restorecon reset /my/website context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
restorecon reset /my/website/index.html context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0

至此,可以看到文件夹和文件的类型上下文都变为httpd_sys_content_t
restorecon命令的-R参数是递归全部子目录和文件
restorecon命令的-v参数是显示修改的标记

5.布尔值设置boolean

SELinux是在系统底层运行。服务以多种方式运行,可以通过使用布尔值来实现如何运行指定的服务。布尔值设置允许在运行时更改SELinux策略的部分内容,而不需要了解如何编写SELinux的策略。布尔值是实时更新的,例如允许服务访问NFS卷,而无需重新加载或重新编译SELinux策略。

修改布尔值的状态很简单,只需通过setsebool命令即可。比如:启动httpd_anon_write布尔值,输入下面的命令:

~]# setsebool httpd_anon_write on

关闭一个布尔值同样使用setsebool命令,仅仅是在onoff之间切换:

~]# setsebool httpd_anon_write off

需要注意
如果想永久修改布尔值,需要在setsebool命令后加入-P参数。
一旦加入-P参数,则系统重启后依然有效。

下面列出与httpd相关的部分布尔值:

布尔值 说明
httpd_anon_write 当被禁用时,这个布尔值允许httpd只能读取标记为public_content_rw_t类型的文件。启用此布尔值允许httpd写入标记为public_content_rw_t类型的文件,例如包含公共文件传输服务文件的公共目录。
httpd_mod_auth_ntlm_winbind 启用此布尔值允许使用httpd中的mod_auth_ntlm_winbind模块访问NTLM和Winbind身份验证机制。
httpd_mod_auth_pam 启用此布尔值允许使用httpd中的mod_auth_pam模块访问PAM身份验证机制。
httpd_sys_script_anon_write 这个布尔值定义是否允许HTTP脚本对标记为public_content_rw_t类型的文件进行写访问,就像在公共文件传输服务中使用的那样。
httpd_builtin_scripting 这个布尔定义了对httpd脚本的访问。PHP内容通常需要启用这个布尔值。
httpd_can_network_connect 当禁用此布尔值时,将阻止HTTP脚本和模块启动到网络或远程端口的连接。启用此布尔值以允许此访问。
httpd_can_network_connect_db 当禁用此布尔值时,将阻止HTTP脚本和模块启动到数据库服务器的连接。启用此布尔值以允许此访问。
httpd_can_network_relay 当httpd用作正向或反向代理时,启用此布尔值。
httpd_can_sendmail 当禁用此布尔值时,将阻止HTTP模块发送邮件。如果在httpd中发现漏洞,这可以防止垃圾邮件攻击。启用此布尔值以允许HTTP模块发送邮件。
httpd_dbus_avahi 当被禁用时,这个布尔值拒绝httpd通过总线访问avahi服务。启用此布尔值以允许此访问。
httpd_enable_cgi 当禁用此布尔值时,将阻止httpd执行CGI脚本。启用此布尔值以允许httpd执行CGI脚本(CGI脚本必须用httpd_sys_script_exec_t类型标记)。
httpd_enable_ftp_server 启用此布尔值允许httpd在FTP端口上侦听并充当FTP服务器。
httpd_enable_homedirs 当禁用此布尔值时,将阻止httpd访问用户主目录。启用此布尔值以允许httpd访问用户主目录;例如,/home/*/中的内容。
httpd_execmem 当启用时,这个布尔值允许httpd执行需要可执行和可写的内存地址的程序。从安全角度来看,不建议启用这个布尔值,因为它减少了对缓冲区溢出的保护,但是某些模块和应用程序(如Java和Mono应用程序)需要这个特权。
httpd_ssi_exec 这个布尔值定义web页面中的服务器端包含(SSI)元素是否可以执行。
httpd_tty_comm 此布尔值定义是否允许httpd访问控制终端。通常不需要这种访问,但是在配置SSL证书文件等情况下,显示和处理密码提示需要终端访问。
httpd_unified 启用后,此布尔值允许httpd_t完全访问所有httpd类型(即执行、读取或写入sys_content_t)。禁用时,在只读、可写或可执行的web内容之间存在分离。禁用此布尔值可以确保额外的安全级别,但增加了管理开销,即必须根据每个脚本和其他web内容各自具有的文件访问权限分别标记脚本和其他web内容。
httpd_use_cifs 启用此布尔值以允许httpd访问标记为cifs_t类型的CIFS卷上的文件,例如使用Samba挂载的文件系统。
httpd_use_nfs 启用此布尔值以允许httpd访问标为nfs_t类型的NFS卷上的文件,例如使用NFS挂载的文件系统。

提示:
可以使用getsebool -a命令获取全部的布尔值

~]$ getsebool -a | grep service_name

使用下面的命令查询具体布尔值的说明:

~]$ sepolicy booleans -b boolean_name

需要安装policycoreutils-devel软件包,才能使用sepolicy命令。

你可能感兴趣的:(SELinux 中 Apache HTTP 详解)