如何在nginx代理后面的金字塔服务器中获取客户端的真实IP

问题描述 投票:0回答:5

我有一个金字塔应用程序,在某些地方使用

request.environ['REMOTE_ADDR']

该应用程序由端口 6543 上的 Python Paste 提供服务,并且侦听端口 80 的 nginx 服务器将请求转发到 Paste 服务器。

nginx 配置的灵感来自 Pyramid 食谱:

server {

    listen   80; ## listen for ipv4
    listen   [::]:80 default ipv6only=on; ## listen for ipv6

    server_name  localhost;

    access_log  /var/log/nginx/localhost.access.log;

    location / {

        proxy_set_header        Host $host;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto $scheme;
        proxy_pass http://127.0.0.1:6543;

    }

在 Pyramid 应用程序中,变量 request.environ['REMOTE_ADDR'] 现在始终等于 127.0.0.1。 我看到了一些解决这个问题的策略,但我不知道是否有推荐的方法来做到这一点。

这是我正在考虑的:

  • 如果需要,添加一个 NewRequest 订阅者来替换 request.environ['REMOTE_ADDR']:

    if 'HTTP_X_REAL_IP' in event.request.environ:
        event.request.environ['REMOTE_ADDR'] = event.request.environ['HTTP_X_REAL_IP']

  • 在到达 Pyramid 层之前使用 wsgi 中间件修改 request.environ。

  • 还有其他事

您使用哪种策略来部署 Pyramid 应用程序? 如果我有两个 nginx 代理会发生什么? (第一个服务于 LAN,第二个服务于直接连接到互联网的机器)。

python deployment nginx pyramid wsgi
5个回答
7
投票

如果您通过

paste.deploy.config.PrefixMiddleware
在 WSGI 管道中使用
use = egg:PasteDeploy#prefix
,它将自动将
X-Forwarded-For
转换为
REMOTE_ADDR
。它对于反向代理的其他属性也很有用,例如,它会将
X-Forwarded-Proto
转换为
wsgi.url_scheme
,以确保如果用户使用 https 访问,则生成的 URL 也是 https。

http://pythonpaste.org/deploy/class-paste.deploy.config.PrefixMiddleware.html


2
投票

我在 nginx 后面使用 gevent 服务器,并使用

request.client_addr
来获取客户端的 IP 地址。


1
投票

如果您没有 WSGI pipline,或者不想使用

paste
,则添加事件处理程序:

config.add_subscriber(reverseProxyProtocolCorrection,'pyramid.events.NewRequest')

事件处理程序可以这样读:

def reverseProxyProtocolCorrection(event):
    event.request.scheme = 'https' if event.request.headers['X-Forwarded-Proto']=='https' else 'http'
    event.request.remote_addr=parseXForward(event.request.headers['X-Forwarded-For'],event.request.remote_addr)

并确保您的代理设置了标头


0
投票

即使接受的答案(基于

paste.deploy.config.PrefixMiddleware
)大部分是正确的,PasteDeploy包内有一个
大问题
。它将
request.remote_addr
替换为链中的第一个 IP。在另一侧,代理服务器通常将新 IP 附加到右侧。我将使用 AWS 负载均衡器 作为示例。

假设正确的客户端全局 IP 是

1.1.1.1
。但客户端正在添加
X-Forwarded-For
标头,其值为
192.168.1.10
。通过负载均衡器后,将附加实际 IP,结果标头将如下所示:

X-Forwarded-For 192.168.1.10,1.1.1.1

PasteDeploy
正在使用第一个IP,因此
192.168.1.10
将被添加为客户端远程地址。如果您的逻辑基于客户端 IP,那么什么可能会导致潜在的漏洞。 最后添加的 IP 应在负载均衡器后面使用,以确保它是最后一跳的真实全局 IP。

基于

PasteDeploy
我创建了自己的具有正确行为的金字塔中间件。

the_middleware.py
存储在项目根目录中的文件如下所示:

class ALBFilterMiddleware:
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        if 'HTTP_X_FORWARDED_FOR' in environ:
            # add LAST IP in chain
            environ['REMOTE_ADDR'] = [
                x.strip(' ') for x in environ.pop('HTTP_X_FORWARDED_FOR').split(',')
            ][-1]
        if 'HTTP_X_FORWARDED_SCHEME' in environ:
            environ['wsgi.url_scheme'] = environ.pop('HTTP_X_FORWARDED_SCHEME')
        elif 'HTTP_X_FORWARDED_PROTO' in environ:
            environ['wsgi.url_scheme'] = environ.pop('HTTP_X_FORWARDED_PROTO')
        return self.app(environ, start_response)


def alb_filter_factory(global_conf, **app_conf):
    def filter(app):
        return ALBFilterMiddleware(app)
    return filter

应用程序 INI 配置应如下所示:

; this entrypoint will be used when you build app
; application = get_app('app.ini', 'the_entrypoint_name')
[pipeline:the_entrypoint_name]
pipeline = the_middleware_name your_app

[app:your_app]
use = call:app_file_with_main_func:main

[filter:the_middleware_name]
; the_middleware.py
use = call:the_middleware:alb_filter_factory

-2
投票

在 nginx 中:

location / {
    proxy_pass http://yourapp;
        proxy_redirect     off;
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $remote_addr;
        }

在 php 中我这样做:

        if($_SERVER["HTTP_X_FORWARDED_FOR"]){
        $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
    }else{
        $ip = $_SERVER["REMOTE_ADDR"];
      } 

也许在Python中是类似的,$ip是你的真实ip

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.