验证nginx是否在本地使用代理协议正常工作



环境

我已经在AWS经典负载均衡器上设置了代理协议支持,如图所示,它将流量重定向到后端nginx(使用ModSecurity配置)实例。

一切都很好,我可以从开放的互联网上访问我的网站。

现在,由于我的nginx配置是在AWS用户数据中完成的,我想在实例开始提供流量之前进行一些检查,这可以通过AWS生命周期挂钩实现。

问题

在启用代理协议之前,我曾检查我的nginx实例是否正常,ModSecurity通过检查来自该命令的403响应来工作

$ curl -ks "https://localhost/foo?username=1'%20or%20'1'%20=%20'"

启用代理协议后,我不能再这样做了,因为命令失败,并出现以下错误,这是该链接所预期的。

# curl -k https://localhost -v
* About to connect() to localhost port 443 (#0)
*   Trying ::1...
* Connected to localhost (::1) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* NSS error -5938 (PR_END_OF_FILE_ERROR)
* Encountered end of file
* Closing connection 0
curl: (35) Encountered end of file
# cat /var/logs/nginx/error.log
2017/10/26 07:53:08 [error] 45#45: *5348 broken header: "���4"�U�8ۭ򫂱�u��%d�z��mRN�[e��<�,�
�+̩�    �0��/̨��98k�̪32g�5=�/<
" while reading PROXY protocol, client: 172.17.0.1, server: 0.0.0.0:443

除了curl之外,我还有什么其他选项可以通过编程检查nginx?也许是其他语言的东西?

您可以使用--haproxy-protocolcurl选项,该选项将额外的代理协议信息添加到请求中。

curl --haproxy-protocol localhost

因此:

curl -ks "https://localhost/foo?username=1'%20or%20'1'%20=%20'"

代理协议在流式传输任何之前附加一行纯文本

PROXY TCP4 127.0.0.1 127.0.0.1 0 8080

上面是一个例子,但这是第一件事。现在,如果我有一个NGINX在SSL和http上使用proxy_protocol进行侦听,那么它希望首先看到这一行,然后看到任何其他东西

所以如果做

$ curl localhost:81
curl: (52) Empty reply from server

在nginx日志中

web_1  | 2017/10/27 06:35:15 [error] 5#5: *2 broken header: "GET / HTTP/1.1

如果我做

$ printf "PROXY TCP4 127.0.0.1 127.0.0.1 0 80rnGET /test/abcrnrn" | nc localhost 81
You can reach API /test/abc and args_given = ,

它有效。由于我能够发送代理协议,它接受

现在在SSL的情况下,如果我使用以下

printf "PROXY TCP4 127.0.0.1 127.0.0.1 0 8080rnGET /test/abcrnrn" | openssl s_client -connect localhost:8080

它仍然会出错

web_1  | 2017/10/27 06:37:27 [error] 5#5: *1 broken header: ",(��   @_5���_'���/��ߗ

这是因为客户端尝试先进行握手,而不是先发送代理协议,然后与握手

所以你可能的解决方案是

  1. 终止LB上的SSL,然后使用proxy_procol在nginx上处理http,并使用我发布的nc命令选项
  2. 添加一个listen 127.0.0.1:<randomlargeport>并使用它执行测试。这仍然是安全的,因为您只监听localhost
  3. 添加另一个SSL端口并使用listen 127.0.0.1:443 ssllisten <private_ipv4>:443 ssl proxy_protocol

根据我的选择,所有解决方案都按优先顺序排列,您可以自己选择

感谢Tarun的详细解释。我在团队中进行了讨论,最终在端口80上创建了另一个nginx虚拟主机,并使用它检查ModSecurity,如下所示。

curl "http://localhost/foo?username=1'%20or%20'1'%20=%20'"`

不幸的是,bash版本在我的情况下不起作用,所以我编写了python3代码:

#!/usr/bin/env python3
import socket
import sys
def check_status(host, port):
'''Check app status, return True if ok'''
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(3)
s.connect((host, port))
s.sendall(b'GET /status HTTP/1.1rnHost: api.example.comrnUser-Agent: curl7.0rnAccept: */*rnrn')
data = s.recv(1024)
if data.decode().endswith('OK'):
return True
else:
return False
try:
status = check_status('127.0.0.1', 80)
except:
status = False
if status:
sys.exit(0)
else:
sys.exit(1)

相关内容

  • 没有找到相关文章

最新更新