Premessa: se a parte hwupgrade c’è un forum più specializzato su questi temi.. fatemelo sapere.
Detto questo.
Oggi ho avuto uno incontro scontro in cui io sostengo una cosa, un mio collega un’altra.
Cerco di esporre i fatti nel modo più preciso possibile.
Server web linux su apache in DMZ (chiamiamolo FRANCO)
Reverse proxy che risponde all’url https://pippo.example.com e manda la richiesta a FRANCO
Il reverse proxy ha impostato questo nella sua configurazione
proxy_set_header X-Forwarded-For $remote_addr;
Per quello che si capisce il comando dice "Passa a FRANCO un header con il parametro X-Forwarded-For e valore l’ip dell’utente remoto.
Ora ci sono in realtà 3 personaggi
QUI dice che che il campo X-Forwarded-For indica l’indirizzo ip della rete privata dell’utente
QUO dice che quel campo è manipolabile dall’utente e quindi può mettere quello che vuole
QUA dice che che quel valore è l’ip dell’utente (o al massimo un altro proxy in mezzo) e non si può toccare e quindi è affidabile (ovviamente escludiamo il caso in cui si riesca a manipolare il pacchetto TCP)
E’ un po’ che non smanetto su apache ma se non ricordo male, impostare proxy_set_header X-Forwarded-For $remote_addr; sulla configurazione del reverse proxy sovrascrive completamente qualsiasi header X-Forwarded-For pre-esistente e lo imposta al valore di $remote_addr, che è l’indirizzo IP effettivo della connessione TCP ricevuta dal reverse proxy.
Qui dice cazzate.
Quo avrebbe ragione ma impostarlo nel reverse proxy sovrascrive qualsiasi cosa un utente abbia mandato. Quindi in questo caso, non c’e’ quel rischio.
Qua ha ragione ma occhio perche’ se c’e’ un altro proxy tra chi fa la richiesta e il reverse proxy, ricevete l’ip del proxy.
Ripeto, occhio perche’ son tipo boh, 10 anni che non tocco apache
però il reverse proxy, NGINX in questo, caso azzera quello che riceve dal client (lo manipola) e ci pensa lui a riscrivere il valore
QUA da una mezza verità:
$remote_addr sarebbe l’IP sorgente della connessione TCP
non è falsificabile a livello HTTP, se escludiamo lo spoofing TCP/IP
l’affidabilità ce l’hai solo fino a NGINX (reverse proxy)
Se la chiamata è diretta si vede l’IP reale dell’utente
Se entrano in gioco una qualsiasi di queste variabili:
NAT
CDN
un qualsiasi proxy
altre tipologie di NAT etc
allora quello che si vede con $remote_addrnon è l’IP dell’utente finale, ma dell’ultimo hop della chiamata
Io avevo capito che e’ tutto apache, semplicemente hanno quel reverse proxy configurato. Comunque credo che quell’header alla fine funzioni alla stessa maniera sia per apache che nginx.
Premetto che io sono colui che sostiene che - escludendo spoofing a livello tcp - il valore é valido (faccio qua) e usabile.
Il reverse proxy é nginx, mentre il server web é apache.
Andando piu nel profondo, anche facessero spoofing a livello tcp e mettessero un ip nella classe 192.168.0.0/16 , alla peggio il pacchetto di ritorno resta nella rete (direi che al limite rischio un ddos)
Mi inserisco, secondo MDN x-forwarded-for non è proprio standard (come, se non ricordo male) tutti gli header x-*
Quindi non ha una semantica ben definita, secondo MDN fra l’altro potrebbe essere una lista di ip non un solo valore.
Quindi quello che può succedere è che al proxy nginx arrivi una richiesta con già l’ header settato a cui lui dovrebbe poi aggiungere il suo record
A proxy IP address. If a request goes through multiple proxies, the IP addresses of each successive proxy are listed. This means that the rightmost IP address is the IP address of the most recent proxy and the leftmost IP address is the address of the originating client (assuming well-behaved client and proxies).
Quindi è almeno in parte forgiabile
Quindi in realtà hanno torto tutti e tre, perché danno per scontato che ci siano 3 personaggi mentre invece ce ne possono essere N.
L’unico IP su cui pippo ha visibilità è quello subito dietro di sé e su cui può garantire la provenienza.
Che è quello che dice @The.End , solo l’ultimo hop.
Se tutta la catena di proxy è onesta, tramite X-Forwarded-For puoi risalire all’indirizzo IP pubblico da cui è uscita la richiesta, che però non è nemmeno detto sia l’IP del client perchè poi ci sono i NAT.
Comunque non hai garanzia che sia onesta.
Il mio scopo finale è poter identificare se la richiesta arriva dall’interno della mia rete (quindi con un ip nella classe 192.168.0.0/16) oppure da fuori per far agire in modo diverso l’applicativo web
Beh l’unica soluzione brutta ma sicura e semplice che mi viene in mente allora e’
due versioni dell’app, una per uso interno, una esterno.
Una la metti su una macchina/VM/Container/Triciclo accessibile solo via rete interna (o vpn se proprio) e una accessibile da interno ed esterno. cicciosuperplus.com per quella pubblica, internal.cicciosuperplus.com per quella interna. Avete qualcuno che si occupa della parte di infra? Mi vien da pensare di no se devi chiedere pareri su NGI
Devi andare giu’ di un livello insomma. A livello di webserver/app logic non credo tu possa avere una certezza ragionevole a giudicare da quanto questo punto sembra importante.
In questo modo se sei nella rete interna vai dalla rete privata, se sei da fuori risponde con ip pubblico.
Però a quanto pare è una cosa da non fare altrimenti esplode il mondo…
Diciamo che abbiamo idee moolto diverse.. ma molto molto..