Reti e web
TCP/IP e porte: come i servizi restano in ascolto sulla tua macchina
Una porta è un ingresso numerato della tua macchina. Come TCP e UDP usano le porte e come avviare, trovare e testare un server locale su 127.0.0.1.
Leggi uno scambio HTTP reale riga per riga: metodi, URL, header, classi di codici di stato e cookie, provati con curl su un server locale.
HTTP è il protocollo con cui browser, app e API si scambiano messaggi. RFC 9110 definisce il significato dei messaggi: metodi, codici di stato, campi header e così via. RFC 9112 definisce come appaiono i messaggi HTTP/1.1 in testo semplice su una connessione TCP. La panoramica di MDN è un'introduzione più breve, orientata al browser, e si legge bene insieme alle RFC.
Lo schema è semplice. Un client invia una richiesta e un server restituisce una risposta. Lo scambio lo inizia sempre il client. L'HTTP in chiaro non cifra niente e non ricorda chi sei da una richiesta all'altra. La cifratura arriva da TLS, trattato nel prossimo articolo. La memoria tra le richieste arriva da cookie e token, di cui parliamo più avanti.
La maggior parte dei comportamenti web che studierai passa per HTTP. Un form invia un valore nel corpo, un'API si fida di un header, un redirect porta l'utente altrove e una cache conserva la copia sbagliata di una pagina. Quando in seguito userai un proxy come OWASP ZAP per ispezionare il traffico, vedrai questi stessi messaggi. Se non sai leggere una richiesta grezza, l'output del proxy è difficile da usare.
Una richiesta HTTP/1.1 è testo semplice in questa forma:
GET / HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: curl/8.12.1
Accept: */*La prima riga è la riga di richiesta: il metodo, il target della richiesta e la versione del protocollo. Ogni riga successiva è un campo header, scritto come name: value. Una riga vuota chiude la sezione degli header. Se il messaggio ha un corpo, viene dopo quella riga vuota. In rete ogni riga termina con CRLF (un ritorno carrello e un avanzamento riga), che gli editor ti nascondono.
Una risposta ha la stessa struttura, con una riga di stato in cima: versione, codice di stato e reason phrase.
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 15
<h1>hello</h1>Il metodo dichiara cosa vuole il client. RFC 9110 definisce GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS e TRACE. PATCH viene da RFC 5789.
Quando leggi il traffico contano due proprietà:
Queste proprietà sono promesse sul significato. Quello che succede davvero lo decide comunque il server. Un handler GET che cancella un record viola il contratto, e chi fa una revisione di sicurezza cerca proprio quell'errore.
Prendi l'URL http://127.0.0.1:8000/missing?lang=en#top e dividilo in parti:
http, che dice al client quale protocollo usare.127.0.0.1:8000, l'host e la porta opzionale./missing.lang=en, dopo il ?.top, dopo il #.Il client non invia al server né lo schema né il frammento. La riga di richiesta contiene il path e la query. L'authority va nell'header Host. HTTP/1.1 richiede Host perché molti siti possono condividere un indirizzo IP, e il server usa quell'header per decidere quale sito deve rispondere.
I nomi degli header non distinguono tra maiuscole e minuscole, quindi Content-Type e content-type sono lo stesso campo (RFC 9110, sezione 5.1). Per i valori il discorso cambia: molti distinguono tra maiuscole e minuscole, quindi non dare per scontato il contrario.
Gli header di richiesta che vedrai più spesso:
Host: obbligatorio in ogni richiesta HTTP/1.1. RFC 9112, sezione 3.2, dice che un server deve rispondere 400 quando manca.User-Agent: il software client.Accept: i media type che il client sa gestire.Cookie: i cookie che il browser rimanda al server.Authorization: le credenziali, spesso un bearer token.Content-Type e Content-Length: descrivono il corpo, quando c'è.Gli header di risposta che vedrai più spesso:
Content-Type: il media type del corpo, per esempio text/html.Content-Length: la dimensione del corpo in byte.Date: l'orologio del server, in GMT.Server: il nome del software. Molti server lo mostrano. Gli ambienti di produzione spesso lo nascondono.Last-Modified: l'ultima modifica della risorsa da parte del server.Set-Cookie: chiede al browser di salvare un cookie.Gli header sono dati controllati da chi li invia. Un browser invia quello che invia il suo software, e uno script o un proxy può inviare quello che vuole. X-Forwarded-For è l'esempio classico: lo aggiunge un proxy, ma può inviarlo anche un client. Non fidarti mai di un header solo perché sembra ufficiale.
Un codice di stato ha tre cifre. La prima indica la classe, come definito in RFC 9110, sezione 15:
| Classe | Significato | Esempi |
|---|---|---|
| 1xx | Informativo. La richiesta è stata ricevuta e l'elaborazione continua | 100 Continue |
| 2xx | Successo | 200 OK, 201 Created, 204 No Content |
| 3xx | Reindirizzamento. Il client deve fare un altro passo | 301 Moved Permanently, 304 Not Modified |
| 4xx | Errore del client. La richiesta ha un problema | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 405 Method Not Allowed |
| 5xx | Errore del server. Il server non è riuscito a gestire una richiesta valida | 500, 501 Not Implemented, 502, 503 |
Anche quando un client non riconosce un codice specifico, può regolarsi sulla classe. Un 4xx significa che la richiesta va cambiata. Un 5xx significa che la stessa richiesta potrebbe funzionare più tardi.
Due codici si confondono spesso. Un 401 significa che alla richiesta mancano credenziali valide. Un 403 significa che il server ha capito la richiesta e la rifiuta, anche con le credenziali.
La reason phrase, per esempio Not Found, è testo scelto dal server. RFC 9112, sezione 4, dice che i client dovrebbero ignorarla. Basa la logica sul numero, mai sulle parole.
I cookie non fanno parte di RFC 9110. Sono definiti in RFC 6265. Il ciclo funziona così:
Set-Cookie: session=abc123; Path=/; HttpOnly; Secure; SameSite=Lax.Cookie: session=abc123.Un cookie di sessione è un identificatore assegnato dal server. Non è una password e non è riservato all'utente. Chi possiede il valore di solito può agire come quella sessione finché non scade o non viene revocata. HttpOnly tiene il valore lontano dagli script della pagina. Secure lo permette solo su HTTPS. SameSite limita quando il browser lo invia nelle richieste cross-site. Gli articoli sulla sicurezza web tornano su questi attributi.
Ti servono curl e Python 3. Windows 11 con Git Bash include curl, e la maggior parte dei sistemi Linux e macOS lo ha già. Il server è http.server, integrato in Python. Eseguilo solo sulla tua macchina, in ascolto su 127.0.0.1, e non esporlo mai su una rete.
L'output seguente viene dall'esecuzione di questi comandi su Windows 11 con Git Bash, curl 8.12.1 e Python 3.12.10. Su questa macchina python3 non era nel path di Git Bash, quindi il server è stato avviato con il percorso completo dell'eseguibile di Python 3.12. Usa python3, py -3 o python a seconda del tuo sistema. Date, orari e stringhe di versione saranno diversi. L'indicatore di avanzamento di curl è stato tolto dall'output qui sotto, e i corpi HTML lunghi sono accorciati.
Nel primo terminale:
mkdir httplab && cd httplab && echo '<h1>hello</h1>' > index.html
python3 -m http.server 8000 --bind 127.0.0.1Lascia aperto questo terminale. Il server scrive una riga di log per richiesta, quindi in questo terminale compare ogni richiesta che invii nei passi successivi.
Nel secondo terminale:
curl -v http://127.0.0.1:8000/Output:
* Trying 127.0.0.1:8000...
* Connected to 127.0.0.1 (127.0.0.1) port 8000
* using HTTP/1.x
> GET / HTTP/1.1
> Host: 127.0.0.1:8000
> User-Agent: curl/8.12.1
> Accept: */*
>
* Request completely sent off
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.12.10
< Date: Sun, 08 Nov 2026 08:16:48 GMT
< Content-type: text/html
< Content-Length: 15
< Last-Modified: Sun, 08 Nov 2026 08:13:48 GMT
<
<h1>hello</h1>
* shutting down connection #0Leggilo in questo ordine:
* sono le note di curl sulla connessione.> sono quello che curl ha inviato. Curl ha aggiunto da solo Host, User-Agent e Accept.< sono quello che il server ha restituito.> vuota chiude gli header di richiesta. La riga < vuota chiude gli header di risposta.<h1>hello</h1> è il corpo. Content-Length: 15 corrisponde al file, perché echo ha aggiunto un a capo dopo il tag.HTTP 1.0, assume close after body mostra una discrepanza. Curl ha chiesto HTTP/1.1, ma il server ha risposto con HTTP/1.0. Il server semplice di Python parla HTTP/1.0, quindi curl chiude la connessione dopo aver letto il corpo.curl -i http://127.0.0.1:8000/missingIl flag -i stampa gli header di risposta insieme al corpo. Output, con il corpo HTML accorciato:
HTTP/1.0 404 File not found
Server: SimpleHTTP/0.6 Python/3.12.10
Date: Sun, 08 Nov 2026 08:16:49 GMT
Connection: close
Content-Type: text/html;charset=utf-8
Content-Length: 335
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error response</title>
</head>
<body>
<h1>Error response</h1>
<p>Error code: 404</p>
<p>Message: File not found.</p>
<p>Error code explanation: 404 - Nothing matches the given URI.</p>
</body>
</html>Guarda il primo terminale. Ha registrato:
127.0.0.1 - - [08/Nov/2026 05:16:49] code 404, message File not found
127.0.0.1 - - [08/Nov/2026 05:16:49] "GET /missing HTTP/1.1" 404 -Il codice di stato è 404, della classe di errori del client: il path non corrisponde a nessuna risorsa. La reason phrase File not found è una formulazione del server. Il corpo è una pagina HTML generata dal server per l'errore. Qualsiasi stato può avere qualsiasi corpo, quindi leggi entrambi.
La riga di log indica 05:16 e l'header Date indica 08:16. Il log usa l'ora locale e l'header usa GMT, quindi i due differiscono per il fuso orario locale.
curl -i -X POST http://127.0.0.1:8000/Output, con il corpo HTML accorciato:
HTTP/1.0 501 Unsupported method ('POST')
Server: SimpleHTTP/0.6 Python/3.12.10
Date: Sun, 08 Nov 2026 08:16:49 GMT
Connection: close
Content-Type: text/html;charset=utf-8
Content-Length: 357
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error response</title>
</head>
<body>
<h1>Error response</h1>
<p>Error code: 501</p>
<p>Message: Unsupported method ('POST').</p>
<p>Error code explanation: 501 - Server does not support this operation.</p>
</body>
</html>La riga di log dice code 501, message Unsupported method ('POST'). Il flag -X cambia solo il metodo. Curl ha inviato gli stessi header di prima.
Il server semplice non ha alcun handler POST, quindi 501 Not Implemented è la risposta onesta. RFC 9110, sezione 15.6.2, definisce 501 per un server che non gestisce la funzionalità richiesta. Un'applicazione reale che conosce la risorsa ma rifiuta POST su quella risorsa risponderebbe invece, di norma, 405 Method Not Allowed. Una risposta 405 deve includere un header Allow che elenca i metodi accettati dalla risorsa.
curl -I http://127.0.0.1:8000/index.htmlOutput:
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.12.10
Date: Sun, 08 Nov 2026 08:16:50 GMT
Content-type: text/html
Content-Length: 15
Last-Modified: Sun, 08 Nov 2026 08:13:48 GMT
Il flag -I invia una richiesta HEAD. Lo stato e gli header coincidono con quelli restituiti da GET, ma non segue alcun corpo. Content-Length indica ancora 15, perché descrive la rappresentazione che GET restituirebbe. RFC 9110, sezione 9.3.2, definisce questo comportamento. Il log mostra "HEAD /index.html HTTP/1.1" 200 -.
HEAD è utile quando vuoi controllare se un file esiste, quanto è grande o quando è cambiato l'ultima volta, senza scaricarlo.
curl -v -H 'Cookie: session=demo123' http://127.0.0.1:8000/Le righe rilevanti dell'output:
> GET / HTTP/1.1
> Host: 127.0.0.1:8000
> User-Agent: curl/8.12.1
> Accept: */*
> Cookie: session=demo123
>
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.12.10
< Date: Sun, 08 Nov 2026 08:18:28 GMT
< Content-type: text/html
< Content-Length: 15
< Last-Modified: Sun, 08 Nov 2026 08:13:48 GMT
< Qui la riga del corpo è omessa. Il server ha risposto con lo stesso 200 di prima, perché non ha alcuna logica sui cookie e ignora l'header. È il senso dell'esercizio. Il browser invia i cookie, ma cosa significano lo decide il server. Un server che non imposta mai un cookie non farà niente con quello che gli invii.
Premi Ctrl+C nel primo terminale quando hai finito.
Host, User-Agent, Cookie e X-Forwarded-For arrivano tutti dal lato client. Validali sul server.127.0.0.1.-X cambi gli header. Cambia solo il metodo. Gli header si aggiungono con -H.Content-Length e Transfer-Encoding.:8000 dell'URL.Un proxy come ZAP mostra questi stessi messaggi, quindi questo articolo fa da base a quelli successivi sulle vulnerabilità web. Anche l'API di NotHoly su api.notholy.com/v1 è un'API HTTP con corpi JSON, servita su TLS, quindi gli header e i codici di stato visti sopra valgono quando la chiami.
Reti e web
Una porta è un ingresso numerato della tua macchina. Come TCP e UDP usano le porte e come avviare, trovare e testare un server locale su 127.0.0.1.
Reti e web
TLS 1.3 dà a HTTPS riservatezza, integrità e autenticazione del server. Impara l'handshake, le catene di certificati e ciò che il lucchetto non dimostra.
Reti e web
Come il DNS trasforma i nomi in indirizzi: resolver, server autoritativi, cache e TTL, i record A, AAAA, CNAME, MX e TXT e una query sicura da provare.