nginx 安全配置文档
1.配置文档中有多处明确写出了nginx的配置文件路径,该路径是测试环境中的路径,线上系统的nginx配置文件与文档中所写的路径可能不一样,在进行相关配置时,应以线上配置文件的实际路径为准。
线上系统nginx的安装目录在:/usr/local/nginx,默认配置文件在/usr/local/nginx/conf/nginx.conf,此外也引用了/usr/local/nginx/conf/conf.d目录下的配置文件。
2.本文档仅包括了用于提升安全的配置方法。
3.在遵从本文档的方法进行配置前,请做好相关配置文件的备份,以便在配置失败时可以回退到变更前状态。
1.新安装,选用安全稳定版本
编号: |
Nginx_Sec_001 |
适用: |
LINUX下新安装或者升级nginx服务器 |
配置要求: |
1.安装包要求从nginx官方网站获取,官方网站地址:http://nginx.org/。 2.安装包优先选用稳定版(stable)最新版,如果要跨大版本升级nginx,则要求在测试环境测试不存在兼容性问题后才在生产环境进行部署。 3.要求对下载的源码安装包文件进行完整性验证。
具体方法参考“备注”处的方法。 |
安全增强说明: |
1.从官方网站下载安装包及对安装包进行指纹验证可以最大程度确保安装文件未被篡改; 2.使用最新版本,最大避免旧版版中已发现安全漏洞的威胁,使用稳定版可以确保功能稳定。 |
备注: |
完整性验证方法: (1)每个nginx源码包都有一个签名文件,从官网访问下载nginx源码包的同时也下载该源码包的签名文件到同一目录,该签名文件是nginx官方使用pgp私钥对源码包进行签名得到,该文件后缀.为.asc,获取pgp签名文件方法:
(2)nginx源码包使用的是pgp签名,进行签名验证时需要到GnuPG程序,如果没有安装该工具,可以使用yum install gnupg进行安装。 (3)获取pgp签名文件的公钥ID,执行:# sudo gpg --verify nginx-1.11.3.tar.gz.asc gpg: Signature made Tue 26 Jul 2016 09:59:49 PM CST using RSA key ID A1C052F8 gpg: Can't check signature: No public key (4)根据ID号从公钥服务器中下载公钥,如下: #sudo gpg --keyserver hkp://keys.gnupg.net --recv-keys A1C052F8 gpg: requesting key A1C052F8 from hkp server keys.gnupg.net gpg: /root/.gnupg/trustdb.gpg: trustdb created gpg: key A1C052F8: public key "Maxim Dounin <mdounin@mdounin.ru>" imported gpg: key A1C052F8: public key "Maxim Dounin <mdounin@mdounin.ru>" imported gpg: no ultimately trusted keys found gpg: Total number processed: 2 gpg: imported: 2 (RSA: 2) (5)利用公钥验证nginx源码包和签名文件,如下,说明文件没有被篡改: # sudo gpg --verify nginx-1.11.3.tar.gz.asc gpg: Signature made Tue 26 Jul 2016 09:59:49 PM CST using RSA key ID A1C052F8 gpg: Good signature from "Maxim Dounin <mdounin@mdounin.ru>" gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. Primary key fingerprint: B0F4 2533 73F8 F6F5 10D4 2178 520A 9993 A1C0 52F8 |
2.使用普通账号运行nginx服务
编号: |
Nginx_Sec_002 |
适用: |
LINUX下新安装部署或已上线nginx服务器 |
配置要求: |
nginx服务器的work进程不能使用root账号运行,要求以普通账号运行,具体方法参考“备注”处的方法。 |
安全增强说明: |
防范或降低攻击者通过上传webshell来获取到的执行权限 |
备注: |
配置普通账号运行nginx服务方法: 1.nginx(worker进程)默认以nobody运行,创建普通账号nginx,使用nginx账号来运行 # sudo groupadd -g 1001 nginx #创建nginx组 # sudo useradd -s /sbin/nologin -M -g nginx -u 1001 nginx #创建nginx用户并加入到nginx组,不创建家目录,不允许nginx账号登录。 说明:GID和UID定义为1000,避免与nis系统上的账号的ID冲突。 2.以普通账号nginx来运行Nginx,两个方法: 方法1:如果是新安装nginx,编译时添加--user=nginx --group=nginx参数; 方法2:已完成nginx的安装,通过修该配置文件来指定,如下: 1)# sudo vim /usr/local/nginx/conf/nginx.conf 2)将#user nobody;改成user nginx nginx; 3)测试配置文件是否正确,执行命令# sudo /usr/local/nginx/sbin/nginx –t 4)在3)步骤测试配置无错误后重启Nginx服务器,执行命令# sudo /usr/local/nginx/sbin/nginx -s reload 5)查看work进程账号,确认该进程账号为nginx,执行命令# sudo ps -aux |grep nginx Warning: bad syntax, perhaps a bogus '-'? See /usr/share/doc/procps-3.2.8/FAQ root 30153 0.0 0.1 17976 1604 ? Ss 22:53 0:00 nginx: master process /usr/local/nginx/sbin/nginx nginx 30245 0.0 0.1 18404 1528 ? S 23:05 0:00 nginx: worker process 3.修改nginx根目录的用户与用户组: 1)chown –R ngin.nginx nginx根目录
注意:设置nginx根目录的用户和用户组为nginx后,且安全加固中将umask设置成027后,nginx安装目录的权限为750,普通用户无法访问该目录,此时需要nginx的安装目录的权限应该是755。 |
3.隐藏nginx的版本信息
编号: |
Nginx_Sec_003 |
适用: |
LINUX下新安装部署或已上线nginx服务器 |
配置要求: |
要求隐藏nginx的版本信息, 具体方法参考“备注”处的方法。 |
安全增强说明: |
绝大多数漏洞扫描工具通过获取目标web服务器的版本号来判断该web服务器是否存在安全漏洞,隐藏版本号后可以最大减少恶意攻击者通过漏扫工具来收集漏洞信息。 |
备注: |
隐藏nginx版本信息方法: 1.编辑nginx配置文件,在http块中添加 server_tokens off; 2.重启nginx服务即可。 |
4.禁止目录列表
编号: |
Nginx_Sec_004 |
适用: |
LINUX下新安装部署或已上线nginx服务器 |
配置要求: |
要求禁止nginx服务器目录列表功能,默认已禁止目录列表功能。具体方法参考“备注”处的方法。 |
安全增强说明: |
1.当目标web服务器允许目录时,只要访问目标web服务器的目录,如果该目录下没有设置默认访问的文件,则会同时将该目录的所有文件列出来,如下:
2.禁止目录列表功能可以避免因暴露目标网站的目录结构和敏感文件,最终造成敏感信息丢失。 |
备注: |
在nginx配置文件的location,server 或 http块中都允许设置autoindex on;确认nginx没有启用目录列表功能,即同时检查这几个地方没有配置参数autoindex on; 说明: 禁止目录列表后,url访问目录应该是403错误,如下:
|
5.日志规范
编号: |
Nginx_Sec_005 |
适用: |
LINUX下新安装部署或已上线nginx服务器 |
配置要求: |
要求nginx服务器同时启用访问日志和错误日志的记录,具体方法参考“备注”处的方法。 |
安全增强说明: |
nginx访问日志记录了客户端的请求行为,通过对访问日志的分析能够发现潜在的攻击行为;nginx的错误日志反映了nginx 服务器的健康状况,通过分析或者监控nginx的报错信息能够及时发现nginx存在故障问题。 |
备注: |
1.设置访问日志(access_log),日志的格式定义如下: log_format access '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent "$http_referer" ' '"$http_user_agent" $http_x_forwarded_for'; 各个变量的说明: $remote_user :用来记录客户端用户名称; $time_local :用来记录访问时间与时区; $request :用来记录请求的url与http协议; $status :用来记录请求状态;成功是200, $body_bytes_sent:记录发送给客户端文件主体内容大小; $http_referer :用来记录从那个页面链接访问过来的; $http_user_agent:记录客户端浏览器的相关信息; $http_x_forwarded_for:用以记录原始客户端IP地址,如果原始客户端原始请求发送到nginx前没有经过任何代理,则该变量的值为-。 2.生成的访问日志格式如下: 效果: 192.168.12.92 - - [12/Aug/2016:20:14:41 +0800] "GET /index.html HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0" – 3.错误日志的级别要求定义为warn,如下 error_log logs/error.log warn; 注意:如果更改日志文件的默认路径,则nginx运行账号需要具有新路劲下日志文件的读写权限。
说明:错误日志级别包括: debug, info, notice, warn, error, crit, alert, or emerg.默认是error级别. 当前3.0系统线上环境nginx编译时将access日志和error日志存在/var/log/nginx目录下。 |
6.限制不安全请求方法
编号: |
Nginx_Sec_006 |
适用: |
LINUX下新安装部署或已上线nginx服务器 |
配置建议: |
建议拒绝接受除POST和GET,HEAD以外的请求方法,具体方法参考“备注”处的方法。 |
安全增强说明: |
http定义了8种请求方法,其中PUT、DELETE等请求方法是不安全的,限制不安全的请求方法降低目标网站文件被恶意篡改的风险。 |
备注: |
配置拒绝除get,head和post方法以外的请求方法: 编辑Nginx配置文件如下: server{ ... ... if ($request_method !~ ^(GET|HEAD|POST)$) { return 444; } ... ... 注:非标准的444错误代码可以强制关闭服务器与客户端的连接而不返回任何响应信息给客户端。
http的8种请求方式: GET:当浏览器要从服务器读取指定文档。Get方法要求服务器将URL定位的资源放在响应报文的正文中,回传给浏览器。 HEAD:使用post方法,浏览器只读取请求文件的头部信息,而不是文件的正文; POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。 PUT:从客户端传送的数据取代(替换)指定文件的内容; DELETE:请求服务器删除指定文件; TRACE:回显服务器收到的请求,主要用于测试或诊断; OPTIONS:1)获取服务器支持的HTTP请求方法;2)用来检查服务器的性能; CONNECT: HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。 |
7.禁用SSL/TSL不安全协议和弱加密算法
编号: |
Tomcat_Sec_007 |
适用: |
使用提供HTTPS方式访问的Tomcat服务器 |
配置要求: |
当nginx使用到https访问时,要求禁止使用SSLV1.0、SSLV2.0,SSLV3.0不安全协议,建议也不要使用TLSv1.0协议,要求禁止使用以下不安全加密算法:
具体配置方法参考“备注”处的方法。 |
安全增强说明: |
降低由于使用不安全协议和弱加密导致被中间人攻击,最终造成敏感信息泄露的风险。 |
备注: |
在nginx配置文件中的ssl_protocols和ssl_ciphers做如下配置: ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH:!kEDH:!kECDH; ssl_prefer_server_ciphers on; 保存配置文件并重启nginx服务即可。
最终支持的加密协议和加密套件如下:
优先使用说明: 加密协议 优先使用顺序TLSv1.2,TLSv1.1,TLS1.0。其中TLS1.0也被认为是不安全协议,建议不使用。 加密套件: 密钥交换算法,优先使用顺序:ECDHE(支持正向安全,2048位,防止中间人攻击),DHE,RSA(无法防止中间人攻击),不要使用1024位的DH。 认证算法,优先使用RSA, ECDSA 对称加密算法,优先使用AES_256_GCM,AES_128_GCM,AES_256_CBC,AES_128_CBC,3DES_EDE_CBC 散列算法,优先使用顺序SHA_256,SHA1 |
8.自定义缓冲区
编号: |
Nginx_Sec_008 |
适用: |
LINUX下新安装部署或已上线nginx服务器 |
配置建议: |
此方法可用于在遭受攻击时用于减轻攻击的防范手段,平时不强制要求配置,如要配置,相关参数则需要根据实际情况来定,具体配置方法如下: http{ ... ... server{ ... ... client_body_buffer_size 16K; client_header_buffer_size 1k; large_client_header_buffers 4 8k; client_max_body_size 1m; |
安全增强说明: |
主要用于防范或者减轻缓冲区溢出攻击。 |
备注: |
语法: client_body_buffer_size size; 默认: client_body_buffer_size 8k|16k; 上下文: http, server, location 参数使用说明: 设置缓冲区(buffer)大小,用于存放所读取客户端的请求体,在请求体(request body)大于buffer,那么整个请求体或者请求体的一部分会写到临时文件(a temporary file)。默认情况下:buffer大小等于两个内存页,在 x86, other 32-bit platforms, and x86-64这些平台它的大小是8K,64-bit平台通常是16k. -------------------------------------------------------------------------------------------------- 语法: client_header_buffer_size size; 默认: client_header_buffer_size 1k; 上下文: http, server 参数使用说明: 设置缓冲区(buffer)大小,用于存放所读取客户端的请求头,在大多数的请求中1k大小的buffer已经足够。但是,如果一个请求头包括很长的cookies或者来自WAP客户端,配置1k可能是不适合的,如果分配的buffer无法容纳 request_line/request_header ,那么则根据large_client_header_buffers配置的参数来分配large_buffer。 ------------------------------------------------------------------------------------------------------------------ 语法: large_client_header_buffers number size; 默认: large_client_header_buffers 4 8k; 上下文: http, server 参数使用说明: 设置单个buffers的大小以及buffers最大个数用于存放所读取客户端的大请求头(reading large client request header),先根据client_header_buffer_size配置的值分配一个buffer,如果分配的buffer无法容纳 request_line/request_header,那么就会再次根据large_client_header_buffers配置的参数分配large_buffer,如果large_buffer还是无法容纳,那么就会返回414(处理request_line)/400(处理request_header)错误。 ------------------------------------------------------------------------------------------------------------------ 语法: client_max_body_size size; 默认: client_max_body_size 1m; 上下文: http, server, location 参数使用说明: Sets the maximum allowed size of the client request body(请求体), specified in the “Content-Length” request header field(请求体的大小在请求头Content-Length字体写明,单位字节). If the size in a request exceeds the configured value, the 413 (Request Entity Too Large) error is returned to the client(如果请求体大小大于该设定值,则给客户端返回413错误). Please be aware that browsers cannot correctly display this error(但浏览器不能正确显示该错误). Setting size to 0 disables checking of client request body size.(设置值为0时,不限制请求体大小) 该参数用于设置nginx允许客户端请求体的最大值,请求体的大小在请求头Content-Length字体写明,单位字节。如果亲请求体的大小超过了配置的值,则向客户端返回413错误,但需要注意的是浏览器不能正确显示该错误,如果该参数值设置0,则不限制请求体大小。 |
9.设置连接超时时间
编号: |
Nginx_Sec_009 |
适用: |
LINUX下新安装部署或已上线nginx服务器 |
配置建议: |
此方法可用于在遭受攻击时用于减轻攻击的防范手段,平时不强制要求配置,如要配置,相关参数则需要根据实际情况来定,具体配置方法如下:
http { ... ... client_body_timeout 10; client_header_timeout 30; keepalive_timeout 30 30; send_timeout 10; |
安全增强说明: |
主要用于防范或者减轻慢连接攻击。 |
备注: |
语法: client_body_timeout time; 默认: client_body_timeout 60s; 上下文: http, server, location 参数使用说明: 设置读取客户端的请求体(request body.)超时时间,该超时时间为在两个连续的读取操作间的超时时间,而不是整个请求体的传输超时时间。如果在这个时间内客户端没有响应(transmit anything),nginx将向客户端返回408请求超时错误。
注意:只有请求体需要被1次以上读取时,该超时时间才会被设置。 --------------------------------------------------------------------------------------------------- 语法: client_header_timeout time; 默认: client_header_timeout 60s; 上下文: http, server 参数使用说明: 设置读取客户端请求头的超时时间,如果在该时间内客户端没有传输完整个请求头(the entire header),nginx将返回408(请求超时)错误。 ------------------------------------------------------------------------------------------------------------------- 语法: keepalive_timeout timeout [header_timeout]; 上下文:http, server, location 参数使用说明: 第一个参数的值指定了客户端与服务器长连接的超时时间,超过这个时间,服务器将关闭连接。值为0时,关闭客户端的会话保持连接,(即关闭长连接). 第二个参数的值(可选)指定了应答头中Keep-Alive: timeout=time的time值,这个值可以使一些浏览器知道什么时候关闭连接,以便服务器不用重复关闭,如果不指定这个参数,nginx不会在应答头中发送Keep-Alive信息。 ---------------------------------------------------------------------------------------------------------------- 语法: send_timeout time; 默认: send_timeout 60s; 上下文: http, server, location 参数使用说明: 该指令指定了发送给客户端应答后的超时时间,Timeout是指没有进入完整established状态,只完成了两次握手,如果超过这个时间客户端没有任何响应,nginx将关闭连接。 |
10.限制并发连接
编号: |
Nginx_Sec_010 |
适用: |
LINUX下新安装部署或已上线nginx服务器 |
配置建议: |
此方法可用于在遭受攻击时用于减轻攻击的防范手段,平时不强制要求配置,如要配置,相关参数则需要根据实际情况来定,具体配置方法如下: 1.在nginx.conf里的http{}里加上如下代码: limit_conn_zone $binary_remote_addr zone=perip:10m; limit_conn_zone $server_name zone=perserver:10m; 2.在需要限制并发数和下载带宽的网站配置server{}里加上如下代码: #每IP最大并发为2。 limit_conn perip 2; 限制单一虚拟服务器,最大只接受20个并发 limit_conn perserver 20; limit_rate 100k; |
安全增强说明: |
主要用以防范或者减轻DDOS攻击。 |
备注: |
语法: limit_conn_zone key zone=name:size; 默认: — 上下文: http 参数使用说明: 定义一个用于存放key变量,大小为szie名称为name的zone,key的值可以是特定变量的任何非空值(空值将不会被考虑)。 例如: limit_conn_zone $binary_remote_addr zone=perip:10m; 定义一个大小为10m字节,名称为perip的zone,该zone用于二进制来储存客户端的IP地址; Ipv4地址对应的 $binary_remote_addr 变量的大小为 4 bytes ,IPv6 地址对应的是16字节。. -------------------------------------------------------------------------------------------------- 语法: limit_conn zone number; 默认: — 上下文: http, server, location 使用参数说明: Zone变量是一个需要引起的zone,zone在前面的limit_conn_zone命令中已经定义好,使用limit_conn_zone名义中定义的zone名称即可引用,number参数用于定义一个数字,并应用到该zone,说明对该zone做并发连接数限制,最大并发连接数为number定义的值,如果客户端并发连接请求大于该值,则向客户端返回503错误(服务暂时不可用)。 例如: limit_conn_zone $binary_remote_addr zone=addr:10m; server { location /download/ { limit_conn addr 1; }
在同一时间(at a time),一个IP仅允许一个连接。 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 语法: limit_rate rate; 默认: limit_rate 0; 上下文: http, server, location, if in location 参数使用说明 限制响应传输给客户端的速率(下载速度),rate指定多少字节每秒,值为0时不限速。注意,这里是对连接限速,而不是对IP限速。如果一个IP允许两个并发连接,那么这个IP就是限速limit_rate×2。 |