保护Nginx代理

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

我的configuration如下所示:

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)" 

我已经做了一些testing,据我可以看到我的代理转发请求到外部网站, 我想要阻止这些请求所有在一起和/或返回200以外的状态代码。

我已经这样做了:

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

阻止CONNECT尝试。 任何想法(超越IP阻止)将不胜感激。

Nginx会接受连接,并根据匹配的server_name(这将检查主机头)来处理它们。 Nginx带有一个默认的服务器模块,configuration为匹配所有的主机。 这允许处理到达服务器的任何请求。

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

检查空主机的服务器:

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

在所有未configuration的主机上抛出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... } 

你可以用不同的方式testing你的configuration(我相信还有更多,但是现在想起来):

(我在下面使用google.com作为testing域,将其更改为您select的站点):

一次指定整个请求:

 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 

(在这种情况下,主机文件告诉你的服务器,google.com可以在你的机器上find – 它向nginx请求 – 在完成testing后删除条目。)

编辑:看来,上述意想不到的结果是无效的请求导致400错误。 如果感兴趣,可以通过在error_log指令中添加'info'参数来确定这个根本原因。 就我而言,以下原因与我所看到的400个错误有关:

使用Telnet和单行GET请求(并且没有主机头):

 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错误。 我想有一个有效的请求有一些额外的语法。 无论如何,从我的理解来看,在444之前处理了400个错误,所以很可能这些错误不会因为真正的无效请求而消失。

我能够成功地使用telnet获得444错误,但它需要修改我的configuration一点:

 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 "-" "-" "-" 

我会build议你减less你提交的标题 (url长度)的大小。

请看看client_header_buffer_size和large_client_header_buffers

限制客户端URI是保持扫描器或破坏客户端发送可能导致缓冲区溢出的大量请求的常用方法。

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

另外ignore_invalid_headers off如果您不希望收到任何自定义标题ignore_invalid_headers off则可以将ignore_invalid_headers off设置为ignore_invalid_headers off