Come ottenere il vero IP di un client in un server piramidico dietro un proxy Nginx
-
28-10-2019 - |
Domanda
Ho un'applicazione piramidale che utilizza request.environ['REMOTE_ADDR']
in alcuni posti.
L'applicazione è servita da Python Incolla sulla porta 6543 e un server Nginx che ascolta sulla porta 80 è le richieste di inoltro al server incolla.
La configurazione Nginx è ispirata al libro di cucina 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;
}
Nell'applicazione Pyramid la richiesta variabile.Environ ['remote_addr'] è sempre uguale a 127.0.0.1. Vedo alcune strategie per risolvere questo problema, ma non so se esiste un modo consigliato per farlo.
Ecco cosa sto prendendo in considerazione:
Aggiungi un abbonato NewRequest che sostituisce la richiesta.Environ ['remote_addr'] se necessario:
if 'HTTP_X_REAL_IP' in event.request.environ: event.request.environ['REMOTE_ADDR'] = event.request.environ['HTTP_X_REAL_IP']
Utilizzare un middleware WSGI per modificare la richiesta. Environ prima di colpire il livello piramide.
qualcos'altro
Quale strategia usi per la distribuzione di applicazioni piramide? Cosa succederà se ho due proxy Nginx? (Il primo servizio della LAN e una seconda una macchina direttamente connessa a Internet).
Soluzione
Se usi il paste.deploy.config.PrefixMiddleware
nella tua pipeline WSGI via use = egg:PasteDeploy#prefix
, tradurrà automaticamente X-Forwarded-For
in REMOTE_ADDR
. È anche ottimo per le altre proprietà del tuo proxy inverso, ad esempio si tradurrà X-Forwarded-Proto
in wsgi.url_scheme
Per garantire che se l'utente visita con HTTPS, gli URL generati sono anche HTTPS.
http://pythonpaste.org/deploy/class-pate.deploy.config.prefixmiddleware.html
Altri suggerimenti
Uso Gevent Server dietro Nginx e uso request.client_addr
Per ottenere l'indirizzo IP di un client.
Se non si dispone di una pipline WSGI o non si desidera utilizzare paste
, quindi aggiungi un gestore di eventi:
config.add_subscriber(reverseProxyProtocolCorrection,'pyramid.events.NewRequest')
Il gestore di eventi può leggere come:
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)
e assicurati che il tuo proxy imposti le intestazioni
in 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;
}
in php lo faccio:
if($_SERVER["HTTP_X_FORWARDED_FOR"]){
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
}else{
$ip = $_SERVER["REMOTE_ADDR"];
}
Forse in Python è simile, $ ip è il tuo vero IP