在使用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
命令。