互联网安全建设从0到1
上QQ阅读APP看书,第一时间看更新

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自动部署功能。