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

验证nginx是否在本地使用代理协议正常工作,nginx,proxy-protocol,Nginx,Proxy Protocol,环境 我已经在AWS经典负载平衡器上设置了代理协议支持,如图所示,它将流量重定向到后端(配置了)实例 一切都很好,我可以从开放的互联网上访问我的网站 现在,因为我的nginx配置是在AWS中完成的,所以我想在实例开始服务于通过AWS生命周期挂钩可以实现的流量之前做一些检查 问题 在启用代理协议之前,我曾经检查我的nginx实例是否正常,ModSecurity通过检查来自该命令的403响应来工作 $ curl -ks "https://localhost/foo?username=1'%20or%

环境

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

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

现在,因为我的nginx配置是在AWS中完成的,所以我想在实例开始服务于通过AWS生命周期挂钩可以实现的流量之前做一些检查

问题

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

$ curl -ks "https://localhost/foo?username=1'%20or%20'1'%20=%20'"
启用代理协议后,我不能再这样做了,因为命令失败,出现了下面的错误,这是预期的

#curl-khttps://localhost -五
*即将连接()到本地主机端口443(#0)
*正在尝试::1。。。
*已连接到本地主机(::1)端口443(#0)
*使用certpath:sql:/etc/pki/nssdb初始化NSS
*NSS错误-5938(文件的结束错误)
*遇到文件结尾
*正在关闭连接0
curl:(35)遇到文件结尾
#cat/var/logs/nginx/error.log

2017/10/26 07:53:08[错误]45#45:*5348断头:���4"�U�8ۭ代理协议在流式传输之前附加一个纯文本行

$ curl localhost:81
curl: (52) Empty reply from server
上面是一个例子,但这是第一件事。现在,如果我有一个NGINX在SSL和http上使用
proxy\u协议进行监听,那么它希望首先看到这一行,然后看到任何其他内容

如果你真的这么做了

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

$ printf "PROXY TCP4 127.0.0.1 127.0.0.1 0 80\r\nGET /test/abc\r\n\r\n" | nc localhost 81
You can reach API /test/abc and args_given = ,
如果我这样做

printf "PROXY TCP4 127.0.0.1 127.0.0.1 0 8080\r\nGET /test/abc\r\n\r\n" | openssl s_client -connect localhost:8080
它起作用了。因为我能够发送它接受的代理协议

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

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

curl "http://localhost/foo?username=1'%20or%20'1'%20=%20'"`
这是因为客户端尝试先进行握手,而不是先发送代理协议再进行握手

所以你可能的解决方案是

  • 在LB上终止SSL,然后使用proxy_协议在nginx上处理http,并使用我发布的nc命令选项
  • 添加一个
    listen127.0.0.1:
    并使用相同的方法执行测试。这仍然是安全的,因为您只收听localhost
  • 添加另一个SSL端口并使用
    listen 127.0.0.1:443 SSL
    listen:443 SSL proxy_协议

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

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

    #!/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.1\r\nHost: api.example.com\r\nUser-Agent: curl7.0\r\nAccept: */*\r\n\r\n')
            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)
    

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

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

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


    添加另一个没有proxy_协议的侦听端口,并让curl检查端口remove proxy_protocol for localhost是否使用支持proxy_协议的客户端。@Tanhongta出于安全原因,我无法使用另一个端口。我正在尝试寻找一些支持代理协议和SSL的客户端,是否有可能调用http而不是https?那么我有一个可能的答案solution@TarunLalwani是的,我知道它可以与http一起工作,但我们的安全团队不想打开其他端口,也不想打开任何额外的端口。这是我最后的办法;如果我找不到其他任何东西,我可能会打开一些随机端口,使其仅可用于此主机的IP+
    监听127.0.0.1:443 ssl
    
    curl -ks "https://localhost/foo?username=1'%20or%20'1'%20=%20'"