保护 Nginx 代理

保护 Nginx 代理

我正在使用 Nginx 作为 Java Web 服务的代理。

我的配置如下:

location /webservice {
    proxy_read_timeout 240;
    proxy_connect_timeout 240;
    proxy_pass      http://127.0.0.1:8080/;
}

在我的日志中我看到很多这样的条目:

xx.xx.xx.xx - - [18/Oct/2011:02:44:23 +0000] "GET http://l04.member.in2.yahoo.com/config/[email protected]&passwd=password HTTP/1.0" 200 9 "-" "Mozilla/4.0 (compatible; MSIE 5.0; Series60/2.8 Nokia6630/4.06.0 Profile/MIDP-2.0 Configuration/CLDC-1.1)"

我已经做了一些测试,就我所见,我的代理不是将请求转发到外部网站,我想阻止所有这些请求和/或返回 200 以外的状态代码。

我已经这样做了:

if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; }

阻止 CONNECT 尝试。任何想法(除了 IP 阻止)都将不胜感激。

答案1

Nginx 将接受连接并根据 server_name 的匹配情况(根据 Host 标头进行检查)处理这些连接。Nginx 带有一个默认服务器块,配置为匹配所有 Hosts。这允许处理到达服务器的任何请求。

我喜欢设置一个服务器块来检查空的 Host 标头,并配置默认服务器以返回 403 错误(例如,如果您尝试通过其 IP 地址访问我的服务器)。然后每个虚拟主机都会获得自己的配置(即任何有效主机都与配置匹配,所有其他主机要么命中默认服务器块,要么命中空主机块)。

检查空主机的服务器:

server {
    listen       80;
    server_name  "";
    return       444;
}

在所有未配置的主机上抛出 403 的服务器:

server {
        listen       80;
        server_name  _;
        root /path/to/error/files;
        error_page 403 /403.html;
                location  /403.html {
                allow all;
        }
        deny all;
}

需要注意的是,上面的 listen 指令不是必需的(nginx 默认监听 80 端口) - 但是我的 nginx 在 varnish 后面运行,所以实际上并不监听 80 端口。

在您的情况下,您将添加第三个服务器来处理您的反向代理请求:

server {
server_name mydomain.com;
...your other blocks...
}

您可以通过多种方式测试您的配置(我相信还有更多,但目前想到的就这些):

(下面我使用 google.com 作为我的测试域名,请将其更改为您选择的网站):

一次性指定整个请求:

telnet mydomain.com 80
GET http://google.com

分别指定请求和主机头:

telnet mydomain.com 80
GET / HTTP/1.1
Host: google.com

在您的主机文件中设置一个条目(在您的服务器上):

127.0.0.1 google.com

使用 curl 尝试获取页面:

curl google.com

(在这种情况下,hosts 文件告诉您的服务器可以在您的机器上找到 google.com - 这会将请求发送给 nginx - 测试完成后删除该条目。)

编辑: 上述情况似乎造成了意想不到的后果,即无效请求导致 400 错误。如果感兴趣,您可以通过将“info”参数添加到 error_log 指令来确定导致此问题的根本原因。就我而言,以下原因与我看到的 400 错误有关:

使用带有单行 GET 请求的 telnet(没有主机头):

client sent invalid request while reading client request line

随机请求(非标准):

client sent invalid method while reading client request line

使用 telnet,等待时间过长:

client timed out (110: Connection timed out) while reading client request headers

其他常见原因包括:

client sent invalid host header while reading client request headers
recv() failed (104: Connection reset by peer) while reading client request line
client closed prematurely connection while reading client request line

使用 curl 会产生预期的 444 错误。我猜想有效请求中有一些额外的语法。无论如何,据我所知,400 错误是在 444 错误之前处理的,因此对于真正无效的请求,这些错误很可能不会消失。

虽然我能够使用 telnet 成功获取 444 错误,但它需要稍微修改我的配置:

server {
    listen       80 default;
    server_name  _ "";
    return       444;
}

请注意,在上面的内容中,“未指定的服务器名称”(下划线)和空白主机(双引号)并未明确定义默认服务器,因此必须在侦听行中添加“默认”。

Telnet 输出:

telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
Host: google.com

访问日志输出:

127.0.0.1 - - [19/Oct/2011:00:51:16 -0400] "GET / HTTP/1.1" 444 0 "-" "-" "-"

答案2

我建议你减少提交的标头的大小(网址长度)。

请查看客户端标头缓冲区大小large_client_header_buffers

限制客户端 URI 是防止扫描仪或损坏的客户端发送可能导致缓冲区溢出的大型请求的常用方法。

因此,如果您设置了large_client_header_buffers 1 1knginx 服务,则将不会接受大于 (1x1K=1K) 1 千字节数据(包括 cookie)的 URI。

ignore_invalid_headers off此外,如果您不希望收到任何定制的标题,您可以进行设置。

相关内容