我如何安全地在Flask中使用用户的真实IP地址(使用mod_wsgi)? [英] How do I safely get the user's real IP address in Flask (using mod_wsgi)?

查看:1624
本文介绍了我如何安全地在Flask中使用用户的真实IP地址(使用mod_wsgi)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在mod_wsgi / Apache上安装了应用程序安装程序,需要记录用户的IP地址。 request.remote_addr返回127.0.0.1和此修复程序尝试更正但我发现Django删除了类似的代码出于安全原因。

有没有更好的方法来安全地获取用户的真实IP地址?

编辑:也许我失去了一些明显的东西。我申请了 werkzeug's / Flask's fix ,但似乎没有当我尝试一个带有改变标题的请求时有所作为:

run.py:

  from werkzeug.contrib.fixers import ProxyFix 
app.wsgi_app = ProxyFix(app.wsgi_app)
app.run()
pre>

view.py:

  for request in request.access_route :
print ip#打印1.2.3.4和my.ip.address

如果我启用了ProxyFix,也会出现相同的结果。我觉得我错过了一些完全明显的东西。你可以使用 pocoo.org/docs/wrappers/#werkzeug.wrappers.BaseRequest.access_routerel =noreferrer> request.access_route 属性仅当您定义列表 代理。
$ b $ access_route 属性使用 X-Forwarded-For 标题,回落到 REMOTE_ADDR WSGI变量;后者是好的,因为你的服务器决定这一点;几乎任何人都可以设置 X-Forwarded-For ,但是如果你信任一个代理来正确设置值,那么使用第一个(从最后)这是不是受信任的:

  trusted_proxies = {'127.0.0.1'}#define your own set 
route = request.access_route + [request.remote_addr]

remote_addr = next((addr for addr in reverse(route)
if addr not in trusted_proxies),request.remote_addr )

这样,即使有人欺骗 X-Forwarded-For 头文件与 fake_ip1,fake_ip2 ,代理服务器将添加,spoof_machine_ip 到最后,上面的代码会将 remote_addr 设置为 spoof_machine_ip ,不管有多少可信代理除了最外层的代理。

这是您的链接文章所谈到的白名单方法(简要地说,Rails使用它)以及
$ b $

b

您的ProxyFix方法工作得很好,但您误解了它的作用。它仅设置 request.remote_addr ; request.access_route 属性不变( X-Forwarded-For 标题不是 由中间件调整)。 ,我会非常警惕的盲目计数代理。



对中间件应用相同的白名单的方法如下: p>

  class WhitelistRemoteAddrFix(object):
这个中间件可以应用于将HTTP代理支持添加到
应用程序不是用HTTP代理设计的,
只从`X-Forwarded`头文件中设置`REMOTE_ADDR`

代理对一组可信的代理

'REMOTE_ADDR'的原始值作为`werkzeug.whitelist_remoteaddr_fix.orig_remote_addr`存储在WSGI环境
中。
$ b $:param应用程序:WSGI应用程序
:param trusted_proxies:可以被信任的一组代理ip地址。


def __init __(self,app,trusted_proxies =()):
self .app = app
self.trusted_proxies = frozenset(trusted_proxies)

def get_remote_addr(self,remo te_addr,forwarded_for):

X-Forwarded-For的给定ips列表中选择新的远程地址。挑选第一个不可信的IP地址。


如果remote_addr在self.trusted_proxies中:
返回next((IP为ip在反向(forwarded_for)
如果ip不在self.trusted_proxies中) ,
remote_addr)

def __call __(self,environ,start_response):
getter = environ.get
remote_addr = getter('REMOTE_ADDR')
forwarded_for = getter('HTTP_X_FORWARDED_FOR','').split(',')
environ.update({
'werkzeug.whitelist_remoteaddr_fix.orig_remote_addr':remote_addr,
})
forwarded_for = [x for x in [x.strip()for x in forwarded_for]如果x]
remote_addr = self.get_remote_addr(remote_addr,forwarded_for)
如果remote_addr不是None:
environ ['REMOTE_ADDR'] = remote_addr
返回self.app(environ,start_response)

明确的说:这个中间件也是, only 设置 request.remote_addr ; request.access_route 不受影响。


I have a flask app setup on mod_wsgi/Apache and need to log the IP Address of the user. request.remote_addr returns "127.0.0.1" and this fix attempts to correct that but I've found that Django removed similar code for security reasons.

Is there a better way to safely get the user's real IP address?

EDIT: Maybe I'm missing something obvious. I applied werkzeug's/Flask's fix but it doesn't seem to make a difference when I try a request with altered headers:

run.py:

    from werkzeug.contrib.fixers import ProxyFix
    app.wsgi_app = ProxyFix(app.wsgi_app)
    app.run()

view.py:

for ip in request.access_route:
        print ip # prints "1.2.3.4" and "my.ip.address"

This same result happens if I have the ProxyFix enabled or not. I feel like I'm missing something completely obvious

解决方案

You can use the request.access_route attribute only if you define a list of trusted proxies.

The access_route attribute uses the X-Forwarded-For header, falling back to the REMOTE_ADDR WSGI variable; the latter is fine as your server determines this; the X-Forwarded-For could have been set by just about anyone, but if you trust a proxy to set the value correctly, then use the first one (from the end) that is not trusted:

trusted_proxies = {'127.0.0.1'}  # define your own set
route = request.access_route + [request.remote_addr]

remote_addr = next((addr for addr in reversed(route) 
                    if addr not in trusted_proxies), request.remote_addr)

That way, even if someone spoofs the X-Forwarded-For header with fake_ip1,fake_ip2, the proxy server will add ,spoof_machine_ip to the end, and the above code will set the remote_addr to spoof_machine_ip, no matter how many trusted proxies there are in addition to your outermost proxy.

This is the whitelist approach your linked article talks about (briefly, in that Rails uses it), and what Zope implemented over 11 years ago.

Your ProxyFix approach works just fine, but you misunderstood what it does. It only sets request.remote_addr; the request.access_route attribute is unchanged (the X-Forwarded-For header is not adjusted by the middleware). However, I'd be very wary of blindly counting off proxies.

Applying the same whitelist approach to the middleware would look like:

class WhitelistRemoteAddrFix(object):
    """This middleware can be applied to add HTTP proxy support to an
    application that was not designed with HTTP proxies in mind.  It
    only sets `REMOTE_ADDR` from `X-Forwarded` headers.

    Tests proxies against a set of trusted proxies.

    The original value of `REMOTE_ADDR` is stored in the WSGI environment
    as `werkzeug.whitelist_remoteaddr_fix.orig_remote_addr`.

    :param app: the WSGI application
    :param trusted_proxies: a set or sequence of proxy ip addresses that can be trusted.
    """

    def __init__(self, app, trusted_proxies=()):
        self.app = app
        self.trusted_proxies = frozenset(trusted_proxies)

    def get_remote_addr(self, remote_addr, forwarded_for):
        """Selects the new remote addr from the given list of ips in
        X-Forwarded-For.  Picks first non-trusted ip address.
        """

        if remote_addr in self.trusted_proxies:
            return next((ip for ip in reversed(forwarded_for)
                         if ip not in self.trusted_proxies),
                        remote_addr)

    def __call__(self, environ, start_response):
        getter = environ.get
        remote_addr = getter('REMOTE_ADDR')
        forwarded_for = getter('HTTP_X_FORWARDED_FOR', '').split(',')
        environ.update({
            'werkzeug.whitelist_remoteaddr_fix.orig_remote_addr': remote_addr,
        })
        forwarded_for = [x for x in [x.strip() for x in forwarded_for] if x]
        remote_addr = self.get_remote_addr(remote_addr, forwarded_for)
        if remote_addr is not None:
            environ['REMOTE_ADDR'] = remote_addr
        return self.app(environ, start_response)

To be explicit: this middleware too, only sets request.remote_addr; request.access_route remains unaffected.

这篇关于我如何安全地在Flask中使用用户的真实IP地址(使用mod_wsgi)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆