Durante l’esposizione di un web server su internet, l’utilizzo di un reverse proxy è una buona pratica per incrementare la sicurezza del servizio, la sua scalabilità e per risparmiare IP pubblici.
Nonostante i vantaggi dell’utilizzo di un reverse proxy, come HAProxy o Nginx, siano innumerevoli, questa pratica introduce un problema, poiché gli IP sorgente delle richieste per i web servers risulteranno essere quelli dei reverse proxies e non quelli dei clients.
Per ovviare questa problematica è possibile utilizzare un protocollo apposito chiamato Proxy Protocol (fuori dallo scopo di questa guida), oppure è possibile servirsi di un header nelle richieste HTTP per far comunicare dai reverse proxies ai web servers gli IP sorgente.
Tipicamente per la preservazione dell’IP sorgente viene scelto l’header X-Forwarded-For, tuttavia essendo solamente una convenzione, è possibile decidere di avvalersi un header diverso, ad esempio CloudFlare utilizza CF-Connecting-IP.
L’impiego di questo tipo di headers ha il vantaggio che permette di salvare l’IP corretto delle richieste nei logs ed in alcuni casi permette di utilizzare l’autenticazione tramite IP o altre funzionalità applicative che richiedono che il web server sia a conoscenza dell’IP corretto dei clients.
Per fa sì che l’utilizzo degli headers per la preservazione degli IP sia sicuro è necessario che essi vengano considerati validi solamente se vengono ricevuti da hosts considerati affidabili (i reverse proxies).
APACHE2
Apache2 mette a disposizione un modulo, chiamato mod_remoteip, che è in grado di sostituire l’IP sorgente delle richieste con l’IP specificato nell’header X-Forwarded-For (o analoghi) se esso viene ricevuto da un host “fidato”.
Più nello specifico, il modulo mod_remoteip utilizza l’IP ricevuto nell’header specificato con la direttiva RemoteIPHeader se esso viene ricevuto da un host autorizzato tramite le direttive RemoteIPInternalProxy, RemoteIPInternalProxyList, RemoteIPTrustedProxy e RemoteIPTrustedProxyList, altrimenti utilizza l’IP sorgente della richiesta.
Tramite questo modulo è possibile utilizzare l’effettivo IP del client, inviato dai reverse proxies, per i logs e per l’autenticazione tramite IP (vedi mod_authz_host).
Innanzitutto è necessario abilitare il modulo:
0 |
a2enmod remoteip
|
Successivamente, è necessario creare un formato per i logs che sfrutti mod_remoteip per decidere quale IP utilizzare, per farlo è sufficiente sostituire nel formato “%h” con “%a”.
Aggiungere il formato dei logs alla lista dei formati (tipicamente nel file /etc/apache2/apache2.conf):
LogFormat “%a %l %u %t \”%r\” %>s %b \”%{Referer}i\” \”%{User-Agent}i\”” remote_combined
Modificare il formato da utilizzare per i logs, tipicamente esso viene specificato nella configurazione del VHOST nel file /etc/apache2/sites-available/nome_vhost.conf :
0
1
|
ErrorLog ${APACHE_LOG_DIR}/nome_vhost-error.log
CustomLog ${APACHE_LOG_DIR}/nome_vhost-access.log remote_combined
|
Aggiungere alla configurazione del server (tipicamente nel file etc/apache2/apache2.conf) o nella configurazione del VHOST il nome dell’header da utilizzare per la preservazione degli IP:
0 |
RemoteIPHeader X-Forwarded-For
|
In seguito, è necessario aggiungere nella configurazione del server (tipicamente nel file /etc/apache2/apache2.conf) o nella configurazione del VHOST gli IP autorizzati dei reverse proxies.
Le liste di IP e FQDN autorizzati sono di due tipo InternalProxy o TrustedProxy; il primo tipo è autorizzato ad inserire nell’header RemoteIPHeader anche IP privati, il secondo tipo, invece, può inserire nell’header solamente IP pubblici.
Esempio #1:
Per aggiungere una lista di InternalProxy scritta in un file aggiungere la seguente configurazione:
0 |
RemoteIPInternalProxyList "/etc/apache2/trusted-proxies.lst"
|
Sostituire /etc/apache2/trusted-proxies.lst con il path del file.
Specificare nel file la lista degli IP o degli FQDN dei reverse proxies (eg. /etc/apache2/trusted-proxies.lst):
0
1
2
3
|
# Reverse Proxies
192.168.1.10
10.0.2.0/24
gateway.localdomain
|
Esempio #2:
Per aggiungere una lista di TrustedProxy specificando una subnet aggiungere la seguente configurazione:
0 |
RemoteIPTrustedProxy 10.0.2.16/28
|
Le direttive possibili per specificare gli IP dei reverse proxies sono:
– RemoteIPInternalProxy
– RemoteIPInternalProxyList
– RemoteIPTrustedProxy
– RemoteIPTrustedProxyList
Infine, verificare la configurazione e se non sono presenti errori riavviare il web server:
0
1
|
apachectl configtest
systemctl restart apache2.service
|
Ref: Apache Web Site
NGINX
Nginx, analogamente ad Apache2, mette a disposizione un modulo per la presenvazione dell’IP che permette di sostituire l’IP delle richieste con quello specificato nell’header X-Forwarded-For (o analoghi) se la richiesta viene ricevuta da un host “fidato”.
Il modulo di Nginx è chiamato ngx_http_realip_module e non viene compilato di default, per abilitarlo è necessario aggiungere l’opzione –with-http_realip_module alla configurazione; nel caso in cui si utilizzasse la versione precompilata del web server (tramite pacchetto della propria distribuzione), è possibile che esso sia abilitato di default (come avviene su Debian).
Per verificare se il modulo è abilitato è possibile eseguire il seguente comando e verificare che l’opzione –with-http_realip_module sia presente:
0 |
nginx -V
|
Per configurare il modulo aggiungere la seguente configurazione nel file /etc/nginx/conf.d/ip-preservation.conf:
0
1
2
3
4
|
# IP address preservation
real_ip_header X-Forwarded-For;
real_ip_recursive on;
set_real_ip_from 10.10.10.10;
set_real_ip_from 10.10.10.11;
|
Sostituire gli “10.10.10.10” e “10.10.10.11” con gli IP dei reverse proxies; è possibile autorizzare uno o più IP aggiungendo una o più direttive set_real_ip_from.
È possibile utilizzare un header diverso da X-Forwarded-For modificando la direttiva real_ip_header.
Per non effettuare la modifica globalmente è possibile aggiungere la configurazione precedente nella sezione location relativa al servizio per cui si vuole configurare il modulo.
Infine verificare la configurazione e se non sono presenti errori riavviare il web server:
0
1
|
nginx -t
systemctl restart nginx.service
|
Ref: Nginx Web Site
IIS
IIS non mette a disposizione un modulo per la preservazione dell’IP, perciò la soluzione più semplice per registrare l’IP sorgente delle richieste nei logs è quella di aggiungere il campo dell’header nel formato utilizzato.
La procedura descritta in questo paragrafo è stata testata su IIS 10.
Accedere a Internet Information Service (IIS) Manager:
Nel menù sulla sinistra selezionare il server e successivamente cliccare su Logging:
Cliccare su Select Fields…:
Assegnare un nome al campo (può essere uguale al nome dell’header), inserire il nome dell’header da utilizzare e confermare cliccando su Ok su entrambe le finestre aperte:
Cliccare sul nome del server per tornare nella home e confermare di voler salvare le modifiche:
Infine, riavviare il servizio cliccando su Restart nel menù sulla destra:
TOMCAT
Tomcat integra la funzionalità di presenvazione dell’IP tramite il suo porting del modulo “mod_remoteip” di Apache2 chiamato RemoteIpValve.
Il porting funziona in modo analogo al modulo di Apache2, ad eccezione del fatto che per indicare gli IP dei reverse proxies viene utilizzata una java.util.regex.
Per abilitare la funzionalità è necessario localizzare la configurazione di Tomcat che tipicamente è salvata nel file $APP_ROOT/conf/server.xml, dove $APP_ROOT è la directory della web application.
Nel file è necessario aggiungere la seguente configurazione:
0 |
<Valve className="org.apache.catalina.valves.RemoteIpValve" remoteIpHeader="x-forwarded-for" proxiesHeader="x-forwarded-by" requestAttributesEnabled="true" internalProxies="10\.10\.10\.32|192\.168\.44\.55"/>
|
Prima di aggiungere la precedente configurazione assicurarsi che non sia già presente la direttiva Valve con className uguale a org.apache.catalina.valves.RemoteIpValve nel file.
È possibile modificare la regex utilizzata da internalProxies oppure da trustedProxies per indicare gli IP dei reverse proxies; la differenza tra le due direttive è la stessa tra RemoteIPInternalProxy e RemoteIPTrustedProxy di mod_remoteip (vedi il paragrafo relativo ad Apache2).
Per indicare l’header da utilizzare per la preservazione dell’IP è possibile modificare il valore della direttiva remoteIpHeader.
Infine, riavviare il servizio della web application per applicare le modifiche.
Ref: Tomcat Web Site
VARNISH
Varnish non modifica l’header utilizzato per la preservazione dell’IP a meno che non venga espressamente configurato per farlo.
È possibile salvare il contenuto dell’header nei logs modificando le opzioni di avvio del servizio, così facendo Varnish inserirà nei logs sia l’IP sorgente della richiesta che il contenuto dell’header, come nell’esempio in seguito:
0 |
86.10.11.12, 192.168.1.10 - - [07/Jul/2024:17:00:24 +0200] "GET http://www.pizza.it/ HTTP/1.1" 200 2743 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0"
|
Se si utilizza systemd per la gestione dei servizi è possibile visualizzare il path dello unit file di Varnish tramite il seguente comando:
0 |
systemctl status varnishncsa.service | grep 'vendor preset' | cut -d '(' -f2 | cut -d ';' -f1
|
Modificare nello unit file la riga relativa alla direttiva ExecStart aggiungendo il formato dei logs desiderato:
0 |
ExecStart=/usr/bin/varnishncsa -a -w /var/log/varnish/varnishncsa.log -F '%%{X-Forwarded-For}i %%l %%u %%t "%%r" %%s %%b "%%{Referer}i" "%%{User-agent}i"' -D
|
È possibile sostituire X-Forwarded-For con il nome di un altro header che si vuole loggare.
Il simbolo % viene utilizzato da systemd per le espansioni, perciò è necessario raddoppiarlo.
Ricaricare i servizi e riavviare Varnish:
0
1
|
systemctl daemon-reload
systemctl restart varnishncsa.service
|
Ref: Varnish Web Site
0 Comments