---
title: "Blindare un server e mettere un WAF davanti alla tua app"
description: "erpc worker blinda un server dalla prima distribuzione e una tabella in erpc.toml mette un WAF davanti a un'API pubblica. Cosa fa e cosa non fa."
canonical: "https://erpc.global/it/doc/erpc-cli/worker-firewall-and-waf/"
locale: "it"
---

# Blindare un server e mettere un WAF davanti alla tua app

Dalla prima distribuzione, `erpc worker` lascia entrare via SSH solo dal tuo indirizzo e scarta ogni altra connessione in entrata. Una tabella `[waf]` mette un proxy di filtraggio davanti alla tua API.

Questa pagina descrive ERPC CLI `v0.1.0-rc.4`, una versione pre-release.

## Il firewall

Una distribuzione imposta il firewall del server prima del primo avvio dell'app:

- SSH solo da `firewall.ssh_allow` e dall'indirizzo da cui parte la distribuzione;
- ogni altra connessione in entrata scartata, tranne `run.port` da `firewall.app_allow`; per un'app dietro un WAF, al suo posto la porta del WAF, e solo dove il WAF sul server esegue già le regole che `[waf]` ora definisce ([più avanti](https://erpc.global/it/doc/erpc-cli/worker-firewall-and-waf/#mettere-un-waf-davanti-alla-tua-app)).

Ogni modifica viene applicata sotto un timer di rollback di 120 secondi e viene mantenuta solo quando una nuova connessione riesce a entrare, così una modifica sbagliata non può chiuderti fuori.

L'allowlist però sopravvive all'indirizzo da cui è stata creata: se il tuo indirizzo di casa cambia, per rientrare passi dal supporto ERPC per un server ERPC, o dalla console del provider per un server tuo. Prima di fidarti di un indirizzo di casa, tieni in `firewall.ssh_allow` un secondo indirizzo da cui puoi raggiungere il server (un ufficio, un'uscita VPN).

Se il tuo indirizzo cambia, aggiungi tutti gli indirizzi fissi usati dai tuoi amministratori:

```bash
erpc worker firewall allow --to ssh 203.0.113.10 198.51.100.7
```

| Comando | Cosa fa |
| --- | --- |
| `erpc worker firewall list` | Mostra chi può raggiungere il server: `erpc.toml` accanto alla tabella del server |
| `erpc worker firewall allow --to ssh\|app <addresses>` | Lascia entrare gli indirizzi e applica la modifica. SSH è consentito da singoli indirizzi; una rete è accettata solo con `--to app` |
| `erpc worker firewall deny --to ssh\|app <addresses>` | Smette di lasciarli entrare |
| `erpc worker firewall sync` | Riporta il firewall del server a ciò che dice `erpc.toml` |

## Mettere un WAF davanti alla tua app

Aggiungi una tabella a `erpc.toml`:

```toml
[waf]
port = 8080
```

`erpc worker deploy` esegue quindi un reverse proxy HTTP sul server, in un'unità systemd tutta sua (`erpc-waf-<app>-<env>`): un utente dinamico senza privilegi, senza chiavi, senza secret e senza nulla del worker, limitato a 1 GiB di memoria. Resta in ascolto su `waf.port`, legge ogni richiesta prima dell'app, rifiuta ciò che le sue regole indicano e inoltra il resto all'app su `127.0.0.1:<run.port>`.

- **L'app resta sul loopback.** La sua porta non viene mai aperta dall'esterno. `erpc worker api` e l'health check raggiungono l'app sul loopback, senza passare dal WAF.
- **Chi può connettersi lo decide comunque la lista del firewall**, e la porta del WAF è l'unico punto in cui quella lista può dire tutti:

  ```sh
  erpc worker firewall allow --to app 0.0.0.0/0     # and ::/0
  ```

  Se nella lista non c'è nessuno, il WAF è in ascolto e nessuno viene lasciato entrare, e la distribuzione lo segnala.
- **La porta viene aperta solo quando il WAF è in ascolto su di essa**, mai prima. Una distribuzione il cui WAF non si avvia fallisce e ne spiega il motivo, con l'app ancora in esecuzione.
- **Quando modifichi `[waf]`,** la porta non viene aperta a nessuno in più finché una distribuzione non ha messo in atto le nuove regole.
- **Togliere `[waf]`** da `erpc.toml` e distribuire rimuove il WAF dal server.

## Impostazioni del WAF

Solo `port` è obbligatoria. Ogni chiave, con il suo valore predefinito:

```toml
[waf]
port = 8080          # the public port, 1024 or above; the app keeps [run] port
methods = ["GET", "POST", "PUT", "DELETE"]
allow_paths = []     # every path
deny_paths = []
max_body_bytes = 1048576
max_header_bytes = 16384
rate = { per_second = 50, burst = 100 }
max_connections_per_address = 32
ban = { after = 100, window_secs = 60, for_secs = 600 }
block_probes = true
header_timeout_secs = 10
body_timeout_secs = 30
upstream_timeout_secs = 30
new_connections = { per_second = 50, burst = 100 }
```

| Chiave | Cosa fa | Cosa riceve ciò che viene rifiutato |
| --- | --- | --- |
| `methods` | I metodi inoltrati, in maiuscolo (al massimo 16; mai `CONNECT`) | 405, con `Allow` |
| `allow_paths` | I percorsi inoltrati; se non ne elenchi nessuno, tutti i percorsi. Un pattern è un singolo percorso, oppure tutto ciò che sta sotto un prefisso quando termina con `*`: `/api/*` è `/api` e tutto ciò che sta sotto. Confrontato con il percorso dopo la decodifica percentuale, distinguendo maiuscole e minuscole | 404 |
| `deny_paths` | I percorsi rifiutati, scritti allo stesso modo e controllati per primi | 403 |
| `max_body_bytes` | Il corpo di richiesta più grande, fino a 64 MiB | 413 |
| `max_header_bytes` | La dimensione massima di riga di richiesta e header insieme, da 1024 a 65536 | 431 |
| `rate` | Le richieste al secondo da un indirizzo, e quante insieme prima che il limite si applichi | 429, con `Retry-After` |
| `max_connections_per_address` | Le connessioni che un indirizzo mantiene contemporaneamente | La connessione viene chiusa, senza risposta |
| `ban` | Dopo `after` richieste bloccate entro `window_secs`, l'indirizzo viene rifiutato per `for_secs` (fino a 30 giorni) | Le sue connessioni vengono chiuse, senza risposta |
| `block_probes` | Rifiuta ciò che chiedono gli scanner (`/.env`, `/.git`, `/wp-login.php` e simili) | 403 |
| `header_timeout_secs` | Quanto tempo ha un client per inviare l'intestazione di una richiesta, da 1 a 120. È anche quanto viene atteso un client che si è fermato a metà di un corpo, o che ha smesso di ricevere la risposta | 408 per l'intestazione; 400 per un corpo interrotto; la connessione chiusa per una risposta non ricevuta |
| `body_timeout_secs` | Quanto può durare in tutto il corpo di una richiesta, da 1 a 600, senza contare il tempo in cui il WAF attende l'app | 408 |
| `upstream_timeout_secs` | Quanto tempo ha l'app per accettare la connessione e iniziare a rispondere, da 1 a 600 | 504; 502 quando l'app non è in ascolto |
| `new_connections` | Il limite proprio del firewall sulle nuove connessioni TCP al secondo da un indirizzo verso la porta del WAF, scartate da nftables prima che il proxy le veda. Mentre l'insieme di indirizzi di nftables è pieno, un indirizzo che non vi compare non viene conteggiato, quindi questo limite non gli si applica finché l'insieme non ha di nuovo spazio; i limiti propri del proxy (`rate`, `max_connections_per_address`, `ban`) continuano ad applicarsi | Il pacchetto viene scartato |

`rate`, `max_connections_per_address`, `ban` e `new_connections` si disattivano con `false` (`ban = false`), e una chiave omessa assume il suo valore predefinito. `erpc worker check` dice cosa farà la tabella `[waf]`, e cosa c'è di sbagliato, prima di qualsiasi distribuzione.

## Cosa fa il WAF senza bisogno di impostazioni

- Una richiesta che non si legge come un'unica richiesta HTTP/1 non ambigua riceve 400, e lo stesso vale per un percorso che non è in forma normale.
- Una richiesta di cambio di protocollo (`Upgrade`) riceve 501.
- Ogni rifiuto conta per il ban, e ogni rifiuto chiude la sua connessione.
- Un indirizzo è un indirizzo IPv4, oppure un `/64` IPv6.
- Il WAF non inoltra gli header della connessione tra il client e il proxy (`Connection` e gli header che nomina, `Keep-Alive`, `Proxy-Authenticate`, `Proxy-Authorization`, `Proxy-Connection`, `TE`, `Trailer`), `Expect`, gli header il cui nome contiene un trattino basso, né gli header `Forwarded`, `X-Real-IP` e `X-Forwarded-Proto` inviati dal client stesso. Imposta `X-Real-IP` sull'indirizzo da cui è arrivata la connessione e aggiunge quell'indirizzo in fondo a `X-Forwarded-For`; solo l'ultima voce di `X-Forwarded-For` è dichiarata dal proxy.

## Vedere cosa fa il WAF

| Comando | Mostra |
| --- | --- |
| `erpc worker status` | La porta del WAF, dove inoltra, da quando, e i conteggi da allora |
| `erpc worker firewall list` | Chi può raggiungere la porta del WAF, e cosa è stato bloccato, per regola |
| `erpc worker logs --waf` | Ogni richiesta bloccata: la regola, lo stato, l'indirizzo del client, il metodo e i primi 200 byte del target |

Una richiesta inoltrata non lascia alcuna riga di log, e nessun header o corpo viene mai registrato nel log; la query di una richiesta bloccata sì, fin dove arrivano i 200 byte. Ciò che un client invia non può scrivere sul tuo terminale: il WAF scrive il suo journal in ASCII stampabile.

## Cosa non fa il WAF

- **Niente TLS.** Parla HTTP/1.1 in chiaro sulla sua porta.
- **Niente HTTP/2:** gli risponde 400.
- **Niente WebSocket**, né alcun altro `Upgrade`: 501.
- **Nessuna ispezione dei corpi.** Un corpo viene misurato, mai letto. L'elenco delle sonde è breve ed è un filtro contro il rumore, non una garanzia: l'app controlla comunque il proprio input.
- **Nessuna autenticazione.** Chi può chiamare l'app spetta all'app deciderlo, e alla lista del firewall.
- **Un indirizzo è un client.** I client dietro uno stesso NAT, proxy o CDN condividono un limite di richieste e un ban; un client con molti indirizzi ha altrettanti limiti di richieste.
- **Ban e conteggi vengono dimenticati** quando il WAF si riavvia.
- **Ricorda al massimo 8192 indirizzi** e mantiene al massimo 1024 connessioni contemporaneamente.
- **È in ascolto solo su IPv4,** quindi una voce IPv6 in `app_allow` per ora non raggiunge nulla.
- **Un percorso viene confrontato come i byte in cui si decodifica.** Un'app che legge i percorsi in modo più permissivo (ignorando maiuscole e minuscole, i parametri `;`, decodificando due volte) può essere raggiunta con un nome che `deny_paths` non copre. `allow_paths` non ha questa lacuna: ciò che non è elencato non viene inoltrato.
- **Un lettore lento viene servito fino alla fine.** Un client che continua a ricevere una risposta, per quanto lentamente, viene servito fino alla fine.
- **Un flood può interrompere un upload di grandi dimensioni.** Il WAF gira su un solo thread, quindi un flood può interrompere un upload di grandi dimensioni con 408. Un'app che accetta corpi grandi aumenta `body_timeout_secs` insieme a `max_body_bytes`.

[La guida del worker](https://github.com/elsoul/erpc-cli/blob/v0.1.0-rc.4/docs/worker.md) contiene ogni regola, compreso quando una modifica ad `app_allow` viene trattenuta fino alla distribuzione successiva.
