Socket-peer eller vidarebefordrad rubrik: vilken adress ska du lita på?
Socket-peeren och en vidarebefordrad rubrik är olika bevis. Jämför vad var och en bevisar, och lita på rubriken bara genom en proxykedja som du kontrollerar.
En begäran som kommer in till din applikation bär två slags adressbevis: peeren som öppnade nätverksanslutningen, och ett HTTP-fält som hävdar adressen till en tidigare klient. De svarar på olika frågor. Socket-peeren observeras, medan rubriken hävdas av den som skrev den, och ingen av dem bör tyst ersätta den andra i en logg eller en åtkomstregel. Jämförelsen nedan håller dem åtskilda och visar sedan det enda arrangemanget där rubriken blir användbar.
Beskriv vägen innan du jämför något:
Client -> approved reverse proxy -> application originI det arrangemanget är socket-peeren för ursprunget normalt proxyn, och en vidarebefordringshuvud kan bära proxyns påstående om klienten. Dess värde kommer från den kontrollerade relationen till den proxyn, inte från rubrikens namn.
Två slags adressbevis
Socket-peeren är ett faktum om en enda TCP-anslutning: något slutförde en handskakning från den adressen. Det är inte nödvändigtvis människan, enheten eller kontot du bryr dig om, eftersom en VPN eller en Tor-utgång legitimt kan vara källan en tjänst observerar. Den är ändå den enda adressen som värden själv verifierade, och det är hela dess värde.
Ett vidarebefordringsfält är metadata om en kedja. X-Forwarded-For, X-Real-IP och det standardiserade fältet Forwarded kan skrivas av vilken klient som helst som når en slutpunkt som ekar dem, så deras tillförlitlighet beror helt på vem som fick tillstånd att sätta dem.
Behåll båda i begärans kontext under olika namn. En applikation som skriver över peeren med rubriken förlorar förmågan att senare rekonstruera ett förtroendefel, och det är precis då du behöver den.
En rubrik omdirigerar aldrig anslutningen
Att skriva en adress i ett vidarebefordringsfält ändrar inte källan för TCP-anslutningen som kommer till servern, och ändrar inte routingen någonstans längs vägen. Vanlig VPN-routing eller käll-NAT levererar trafik helt utan någon HTTP-rubrik. På samma sätt skriver en transitgateway inte om ett korrekt skyddat HTTPS-utbyte utan att ändra arrangemanget för TLS-slutpunkten.
Det omvända felet är lika vanligt: HTTPS gör inte en klientlevererad vidarebefordrad rubrik sann. Det skyddar transporten av ett falskt påstående precis lika bra som av ett sant.
Om en kollega föreslår en rubrikändring för att lösa ett routingproblem har diagnosen redan gått fel. Reparera vägen, eller reparera proxykonfigurationen som skriver rubriken.
Namnge proxyn som får hävda
Två regler gör ett vidarebefordringsfält användbart, och båda är konfiguration och inte kod. Kasten normaliserar eller kastar bort allt som kommer utifrån, enligt sitt eget dokumenterade beteende för dessa fält. Sedan tar ursprunget en ersättningsadress från den proxysökväg du namngav och inte från någon annanstans. Den andra regeln gäller bara så länge klienter inte kan nå ursprunget på annat sätt, eftersom ett ursprung som svarar på både direkta och proxade begäranden inte vet vilken av dem det betjänar.
NGINX-modulen för riktig IP visar uppdelningen tydligt. set_real_ip_from namnger avsändarna vars påstående räknas, och real_ip_header säger vilket fält som bär det; den första utför förtroendet, den andra säger bara var man ska titta.
set_real_ip_from 10.20.0.0/24;
real_ip_header X-Forwarded-For;
# real_ip_recursive off - take the rightmost value in the field
# real_ip_recursive on - walk the list back past every trusted address
Ett rubrikvalsdirektiv i sig självt fastställer fortfarande ingenting om vem som skickade värdet.
Transportsäkerhet måste löpa hela vägen mellan de komponenter du litar på. En kant som normaliserar korrekt förlorar det värdet i det ögonblick ett oskyddat hopp längre ned låter någon annan redigera påståendet medan det reser.
Hantera kedjor med flera hopp medvetet
Flera proxyservrar kräver en uttrycklig kedjemodell. Ta inte det vänstra eller högra kommaavskilda värdet för att en bloggpost gjorde det; ta reda på vilken av dina proxyservrar som lägger till, vilken som ersätter och vilken som bevarar det inkommande fältet. NGINX kan till exempel gå igenom listan baklänges mot sin betrodda mängd och stanna vid den första adressen som det inte äger, och det är den produktens regel, inte en lag som varje ramverk följer. Läs dokumentationen för din egen proxy med samma två frågor: vilket värde väljer den, och vilka avsändare tror den på?
Skriv ned kedjan: hoppordning, vilket hopp som sätter fältet och vilket hopp som tar bort inkommande kopior. Håll sedan den anteckningen bredvid proxykonfigurationen, inte bara i biljetten. Testa det sedan genom att skicka en begäran med en förfalskad rubrik genom den godkända valideringsprocessen och bekräfta att ursprunget ignorerar den.
När du lägger till ett hopp, granska det dokumentet. En ny lastbalanserare som sätts in framför den betrodda proxyn kan ändra vilken adress som vinner utan att någon redigerar applikationen.
Behåll båda observationerna i loggen
Där diagnostik är tillåten, logga anslutningens peer och den normaliserade klientadressen som två separata fält, och lägg bara till de vidarebefordringsmetadata som syftet faktiskt behöver. Bevisa sedan driftsättningen med två begäranden: en via proxyn som borde registrera båda värdena förnuftigt, och ett försök direkt till ursprunget som måste avvisas.
Kom ihåg vad paret betyder. Rubriken lägger till kontext som tillhandahålls av en komponent du valde att lita på; peeren förblir den enda adressen som din värd faktiskt såg. Ingen av dem är bevis för individuell identitet, och en design som behandlar någon av dem som bevis kommer att ha fel om någon.