原文地址: https://github.com/yandex/gixy

概要

Gixy是一个分析Nginx配置的工具。Gixy的主要目标是防止安全性错误配置并自动进行缺陷检测。
目前支持的Python版本为2.7和3.5+。

免责声明:Gixy仅在GNU/Linux上经过良好测试,其他操作系统可能存在一些问题。

目前在Gixy可以找到以下问题:

[add_header_multiline]多行响应头

您应该避免使用多行响应头,原因如下:

如何发现

配置错误的示例:

# http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header
add_header Content-Security-Policy "
default-src: 'none';
script-src data: https://yastatic.net;
style-src data: https://yastatic.net;
img-src data: https://yastatic.net;
font-src data: https://yastatic.net;";
# https://www.nginx.com/resources/wiki/modules/headers_more/
more_set_headers -t 'text/html text/plain'
'X-Foo: Bar multiline';

如何解决

唯一的解决方案是永远不要使用多行响应头。

[add_header_redefinition]通过add_header指令重新定义响应头

不幸的是,许多人不知道指令的继承是如何工作的。大多数情况下,这会导致add_header在尝试在嵌套级别添加新响应头时滥用指令。Nginx 文档中提到了此功能:

There could be several add_header directives. These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level.

逻辑非常简单:如果您在一个级别(例如,在server部分)设置了响应头,然后在较低的级别location(比方说)中设置了其他的响应头,那么第一个响应头将被丢弃。
这很容易检查:

如何解决

有几种方法可以解决这个问题:

[alias_traversal]通过配置错误的alias遍历路径

alias指令用于替换指定位置的路径。例如,配置如下:

location /i/ {
alias /data/w3/images/;
}

/i/top.gif的请求下,会发送/data/w3/images/top.gif文件。
但是,如果location不以目录分隔符(即/)结尾,则:

location /i {
alias /data/w3/images/;
}

在/ i .. / app/config.py的请求下,会发送/ data/w3/app/config.py文件。
换句话说,错误的alias配置可以允许攻击者读取存储在目标文件夹之外的文件。

如何解决

这很简单:

[host_spoofing]伪造请求报文的HOST头

通常,位于nginx后面的应用程序需要正确的Host头来生成URL(重定向、资源、邮件中的链接等)。欺骗此协议头,可能导致从网络钓鱼到SSRF等各种问题。

注意:您的应用程序也可以使用X-Forwarded-Host协议头来实现此功能。在这种情况下,您必须确保协议头设置正确;

如何发现

大多数情况下它使用$http_host变量代替$host
而且它们是完全不同的:

[http_splitting]HTTP Splitting

HTTP Splitting - 使用不正确验证的输入进行攻击。它通常针对位于Nginx(HTTP请求拆分)或其用户(HTTP响应拆分)的Web应用程序。
当攻击者将新行字符\n或\r\n插入到Nginx创建的请求或响应中时,就会创建该漏洞。

如何发现

你应该时刻注意:

server {
listen 80 default;
location ~ /v1/((?<action>[^.]*)\.json)?$ {
add_header X-Action $action;
return 200 "OK";
    }
}

利用点:

GET /v1/see%20below%0d%0ax-crlf-header:injected.json HTTP/1.0
Host: localhost
HTTP/1.1 200 OK
Server: nginx/1.11.10
Date: Mon, 13 Mar 2017 21:21:29 GMT
Content-Type: application/octet-stream
Content-Length: 2
Connection: close
X-Action: see below
x-crlf-header:injected
OK

正如您所看到的,攻击者可以添加响应头x-crlf-header: injected,可能的原因是:

如何解决

[origins]referrer/origin验证问题

使用正则表达式验证RefererOrigin协议头并不罕见,通常需要设置X-Frame-Options协议头(ClickJacking保护)或跨源资源共享。
这种配置中最常见的错误是:

如何发现

如何解决

[ssrf]服务器端请求伪造

服务器端请求伪造攻击,迫使服务器执行任意请求(在我们的例子中来自Nginx)。当攻击者控制代理服务器的地址(proxy_pass指令的第二个参数),这是可能发生的。

如何发现

有两种类型的错误会使服务器容易受到攻击:

缺乏internal指令

经典的错误配置是缺乏internal指令,这使SSRF成为可能:

location ~ /proxy/(.*)/(.*)/(.*)$ {
proxy_pass $1://$2/$3;
}

攻击者可以完全控制代理地址,这样就可以代表Nginx发送请求。

不安全的内部重定向

假设您在您的配置中有内部位置,并且该位置使用一些请求数据作为代理服务器的地址。
例如:

location ~* ^/internal-proxy/(?<proxy_proto>https?)/(?<proxy_host>.*?)/(?
<proxy_path>.*)$ {
internal;
proxy_pass $proxy_proto://$proxy_host/$proxy_path ;
proxy_set_header Host $proxy_host;
}

根据Nginx文档,内部请求如下:

  • requests redirected by the error_page, index, random_index, and try_files directives;
  • requests redirected by the “X-Accel-Redirect” response header field from an upstream server;
  • subrequests formed by the “include virtual” command of the ngx_http_ssi_module module and by the ngx_http_addition_module module directives;
  • requests changed by the rewrite directive

因此,任何不安全重写会导致攻击者发起内部请求并控制被代理服务器的地址。
错误的配置如下:

rewrite ^/(.*)/some$ /$1/ last;
location ~* ^/internal-proxy/(?<proxy_proto>https?)/(?<proxy_host>.*?)/(?
<proxy_path>.*)$ {
internal;
    proxy_pass $proxy_proto://$proxy_host/$proxy_path ;
    proxy_set_header Host $proxy_host;
}

如何解决

在编写此类配置时,您应该遵循以下几个规则:

[valid_referers]valid_referers为none

模块ngx_http_referer_module允许阻止对具有错误Referer值的请求的服务访问。它通常用于设置X-Frame-Options header(点击劫持保护),但可能还有其他情况。
配置该模块的典型问题:

为什么使用none是不好的

根据文档

none-请求头中缺少“Referer”字段;

不过,重要的是要记住,任何资源都可以让用户的浏览器在没有Referer请求头的情况下发起请求。例如:

源链接

Hacking more

...