È possibile utilizzare l'request.access_route
attribute solo se si definisce un elenco di fiducia proxy.
L'attributo access_route
utilizza lo X-Forwarded-For
header, ritornando alla variabile WSGI REMOTE_ADDR
; il secondo va bene come il tuo server determina questo; il X-Forwarded-For
avrebbe potuto essere fissato dalla quasi chiunque, ma se vi fidate un proxy per impostare correttamente il valore, quindi utilizzare il primo (dalla fine) che è non attendibile:
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)
In questo modo, anche se qualcuno contraffa l'intestazione X-Forwarded-For
con fake_ip1,fake_ip2
, il server proxy aggiungerà ,spoof_machine_ip
alla fine e il codice precedente imposterà lo remote_addr
in spoof_machine_ip
, indipendentemente dal numero di proxy fidati che ci sono in aggiunta al proxy più esterno.
Questo è l'approccio di whitelist di cui parla il tuo articolo collegato (brevemente, nel fatto che Rails lo utilizza), e cosa Zope implemented over 11 years ago.
L'approccio ProxyFix funziona correttamente, ma hai frainteso ciò che fa. È solo set request.remote_addr
; l'attributo request.access_route
non è stato modificato (l'intestazione X-Forwarded-For
è non regolata dal middleware). Tuttavia,, sarei molto cauto nel contare ciecamente i proxy.
Applicando lo stesso approccio whitelist al middleware sarà simile:
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)
essere espliciti: questo middleware anche solo set request.remote_addr
; request.access_route
rimane inalterato.
Immagino di essere solo confuso perché il cosiddetto "ProxyFix" non ha risolto il problema. Dovrei preoccuparmi di ProxyFix? –
grazie ancora Martijn! –