在使用CentOS时多多少少会涉及SELinux,尤其是针对Web服务,大部分的做法是关闭SELinux,正确的做法是设置好SELiunx,可以防范网站攻击风险。
本文参照官方SELinux文档整理
1. Apache HTTP服务和SELinux
当SELinux启动,Apache HTTP服务(httpd)默认运行在受限模式下。运行的进程只能在设定好的域domains内运行,并与其他受限进程分开。如果一个受限进程被攻击,依靠SELinux策略policy配置,攻击者访问的资源和可能的损失都会被限制。
接下来演示一下:
- 运行
getenforce命令确认SELinux的运行在enforcing强制模式下:
~]# getenforce
Enforcing
- 查看
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
- 查看
httpd进程是否关联了SELinuxcontext(上下文):
~]# 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_t域httpd_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访问NFS和CIFS卷,或者httpd允许执行CGI脚本。
2. Apache HTTP端口与SELinux端口
当/etc/httpd/conf/httpd.conf文件配置完,httpd监听一个或多个端口,比如80,443,448,8080,8009或者8443等等。
必须使用semanage port命令添加新的端口到SELinux策略配置中。
下面演示使用新的httpd端口后,必须添加SELinux端口策略,否侧httpd无法启动。
- 确认
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)
- 使用
semanage工具查看当前关于httpd的监听端口:
~]# semanage port -l | grep -w http_port_t
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
- 编辑
/etc/httpd/conf/httpd.conf文件,修改Listen的端口号为12345,可以确认12345端口不再SELinux策略policy配置中:
~]# vim /etc/httpd/conf/httpd.conf
---
#Listen 12.34.56.78:80
Listen 12345
---
- 再次启动
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服务
- 现在允许
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
- 再次启动
httpd服务,可以看到添加端口后,服务正常启动了
~]# systemctl start httpd.service
为了保证能正常访问,还需要在防火墙中添加端口
12345~]# firewall-cmd --permanent --add-port=12345/tcp ~]# firewall-cmd --reload
- 至此可以发现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类型:
- 查看
/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结尾
- 创建一个新文件再次验证文件的类型上下文:
~]# 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_t和mysqld_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访问:
- 在根目录下,创建一个新的目录,查看当前目录的上下文状态:
~]# mkdir -p /my/website
~]# ls -dZ /my
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /my
可以看到默认新建的目录的类型上下文是
default_t
- 使用
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参数是添加一个类型
- 创建一个新文件,查看文件的类型上下文:
~]# 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访问:
- 在根目录下,创建一个新的目录,查看当前目录的上下文状态:
~]# mkdir -p /my/website
~]# ls -dZ /my
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /my
- 使用
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命令后,文件夹的类型上下文并没有发生变化。
- 创建一个新的文件:
~]# 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类型上下文也没有发生改变
- 接下来使用
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命令,仅仅是在on和off之间切换:
~]# 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命令。
