2.1 Web组件安全
Web组件包罗万象,本节主要介绍Nginx、PHP、Tomcat组件的安全问题,其他组件在下一节介绍。
2.1.1 Nginx安全
Nginx是一个高性能的HTTP和反向代理Web服务器,在出现之后,使得网站服务从LAMP(Linux、Apache、MySQL、PHP)组合很快变成了LNMP(Linux、Nginx、MySQL、PHP),通过搜索两个关键字发现Nginx的应用数量更高,如图2-1所示,因此本节将介绍Nginx相关的安全问题。
图2-1 Nginx与Apache使用对比
1.Nginx基本安全配置
读者应该全面了解Nginx的配置文件,这里笔者只重点介绍一些常见的安全配置建议。
(1)关闭列目录
Nginx默认是不允许列出整个目录的,不过为了安全,最好还是确认这个选项是否真的关闭,否则有可能导致整个Web站点代码泄露。在配置文件中确认(下述都是在Nginx配置文件中确认或配置),如见到autoindex on;(可能在HTTP、server、location这三个位置),则列目录功能被打开,除非有特殊需要(例如提供下载等),否则建议关闭,如图2-2所示。
图2-2 在Nginx配置文件中确认列目录功能是否打开
(2)关闭版本号显示
Nginx默认会在返回的数据包中显示版本号,如图2-3所示。
这就有可能被别有用心的人针对这个版本进行信息收集,或有针对性地进行攻击。因此要注意遵循对外提示信息越少越好的原则,建议关掉版本号信息,命令如下:
server { server_tokens off; }
关闭后的显示如图2-4所示。
图2-3 显示Nginx版本号
图2-4 关闭Nginx版本号的显示
(3)访问控制
对Nginx是可以做访问限制的,allow是允许访问的IP和IP段,deny是禁止访问的IP和IP段,例如,只允许10.255.0.0/24和主机172.31.255.1访问,代码如下:
location / { allow 10.255.0.0/24; allow 172.31.255.251; deny all; }
想更精准地控制访问权限,还可使用auth_basic指令,用户必须输入有效的用户名和密码才能访问站点。用户名和密码应该列在auth_basic_user_file指令设置的文件中:
server { ... auth_basic "Authorized Require"; //可以随意定义,为显示提示的内容 auth_basic_user_file conf/htpasswd; //使用htpasswd命令生成的文件 }
在网络中,时常会遇到各类爬虫,要通过Web服务器做到反爬(防盗链),可以使用Nginx默认的location实现:
location / { valid_referers none blocked www.example.com example.com; if ($invalid_referer) { return 403; } }
另外,还可以使用location参数限制外部可以访问的资源,例如,不允许访问zip、rar、gz、bak等文件(有些管理员会把一些日志或网站备份到网站目录下),代码如下:
location ~* .*\.(zip|rar|gz|bak)?$ { deny all ; }
更多location配置可以参考官方文档。
(4)启用HTTPS
为了站点安全,推荐开启HTTPS(Hyper Text Transfer Protocol over SecureSocket Layer)。HTTPS是以安全为目标的HTTP通道。在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS在HTTP的基础上加入SSL层(需要在编译时使用--with-http_ssl_modul参数,并获得证书):
server { listen 443; //将监听端口修改为443,默认为80 server_name website.name; //设置网站名 ssl on; ssl_certificate cert/2019/cert.pem; //设置证书位置 ssl_certificate_key cert/2019/cert.key; //设置证书私钥位置 ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:! aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1.2; ssl_session_tickets on; ssl_stapling on; ssl_stapling_verify on; ssl_prefer_server_ciphers on;
2.Nginx透过代理获取真实客户端IP
在应用服务器上,Nginx日志中采集的关于定位用户身份信息的IP维度数据有可能会不准确,不准确的原因是:因为在应用服务器中Nginx使用XFF与remote_addr字段采集客户IP,XFF字段很容易被攻击者伪造,而remote_addr字段一般采集的都是直连时的IP,在经过多层代理、网关等设备时,更容易导致后端服务器获取的客户端IP不真实。
这里给出一个案例,拓扑图如图2-5所示。
图2-5 Nginx透过代理获取真实客户端IP案例
在默认配置下,客户访问Server服务器,只能得到Proxy2的IP,而如果客户端伪造XFF信息,Server端也只能得到伪造后的信息。因此可以使用X-Forwarded-For+Nginx的realip模块获取客户端的真实IP。
首先,确认在编译时已经使用了-with-http_realip_module参数(可以通过nginx-V命令查看),在Server角色的Nginx配置文件中配置三个参数:
·set_real_ip_from:表示从何处获取真实IP,只认可自己信赖的IP,可以是网段,也可以设置多个。
·real_ip_header:表示从哪个header属性中获取真实IP。
·real_ip_recursive:递归检索真实IP,如果从X-Forwarded-For中获取,则需要递归检索;如果从X-Real-IP中获取,则无须递归。
相关配置如下:
proxy1与proxy2服务器正常配置,设置代理并且设置XFF字段信息。此时,即使客户端伪造XFF信息,Server端也可以获取真实的信息。更多细节可以参考heysec公众号中的“日志分析系列(外传一):Nginx透过代理获取真实客户端IP”。
3.Nginx漏洞回顾
Nginx也出现过比较严重的漏洞,下面列举两个比较严重的漏洞。
(1)Nginx文件解析漏洞
Nginx文件解析漏洞是Nginx中PHP配置不当而造成的,与Nginx版本无关,但在高版本的PHP中,由于security.limit_extensions的引入,使得该漏洞难以被成功利用。当请求中的URL中路径名以*.php结尾,则Nginx不管该文件是否存在,直接交给PHP处理,而如Apache等,会先看该文件是否存在,若存在,则再决定该如何处理。
(2)Nginx 00%截断漏洞
受Nginx 00%截断漏洞影响的Nginx版本为0.5、0.6、0.7~0.7.65、0.8~0.8.37,等等,这是一个很经典的漏洞。很多网站也都因为这个漏洞而被入侵。漏洞形成的原因也很简单,由于Nginx是由C语言写的,在C语言中,\0就是终止符,所以当用户在上传test1.jpg%00.php时,文件系统会认为读取的为test1.jpg,从而绕过检测。
2.1.2 PHP安全
PHP是开发网站时使用得比较多的语言,因此正确配置PHP环境也非常重要,下面以PHP 7.4w为例,介绍一下PHP常见的安全配置(以下设置均在php.ini配置文件中进行)。
(1)关闭PHP版本信息
为了防止黑客获取服务器中PHP版本的信息(例如显示X-Powered-By:PHP/5.3.7),最好关闭显示PHP版本信息,配置如下:
expose_php = off
这样,在执行telnet domain 80的时候,将无法看到相关信息。
(2)关闭PHP提示错误功能
同样,基于不必要的提示信息越少越好的原则,建议关掉PHP提示错误,在配置文件中进行如下设置:
display_errors = OFF
(3)设置记录错误日志
在关闭PHP提示错误功能后,需要将错误信息记录下来,便于排查服务器运行的原因,可以进行如下设置:
log_errors = On
同时设置日志位置:
error_log = /usr/local/apache2/logs/php_error.log
需要注意的是,该文件必须是Web服务器用户可写的。
(4)设置PHP脚本能访问的目录
使用open_basedir选项能够控制PHP脚本只能访问指定的目录,这样能够避免PHP脚本访问不应该访问的文件,一定程度上限制了phpshell的危害范围,一般可以设置为只能访问网站目录:
open_basedir = /usr/www
(5)关闭危险函数
禁止一些危险的系统命令函数,例如system(),或者能够查看PHP信息的phpinfo()函数等:
disable_functions = system, passthru, exec, shell_exec, popen, phpinfo, escapeshellarg, escapeshellcmd, proc_close, proc_open
如果要禁止任何文件和目录的操作,那么可以关闭很多文件操作:
disable_functions = chdir, chroot, dir, getcwd, opendir, readdir, scandir, fopen, unlink, delete, copy, mkdir, rmdir, rename, file, file_get_contents, fputs, fwrite, chgrp,chmod, chown
需要注意的是,这只能禁止系统内部(内置)函数,并不能禁止用户自定义的函数。
更多安全配置可以参考https://www.php.net/manual/zh/security.php。
2.1.3 Tomcat安全
Tomcat作为Java开发者所喜爱的Web服务器,也有很广泛的应用,笔者简单介绍一下相关安全建议:
·修改Tomcat的默认口令。
·升级到最新稳定版,出于稳定性考虑,不建议进行跨版本升级。
·服务降权,不要使用root用户启动Tomcat,使用普通用户启动Tomcat。
·更改Tomcat的AJP管理端口,默认为8009,允许配置范围在8000~8999。
·更改Tomcat的默认管理端口,默认为8005,此端口有权停止Tomcat服务,允许配置范围在8000~8999。
·将Tomcat应用根目录配置为Tomcat安装目录以外的目录。
·隐藏Tomcat的版本信息。
·关闭war自动部署功能。