sgcIndy 2026.6: rafforzamento della sicurezza dei server per TLS, TCP e HTTP

· Versioni

sgcIndy 2026.6 rivolge la propria attenzione al lato server. Questa versione aggiunge un insieme di opzioni di rafforzamento della sicurezza opzionali ai componenti server TLS, TCP e HTTP, chiudendo una serie di ben note classi di attacco contro cui il codice Indy sottostante non si è mai protetto: un callback di verifica del certificato che fallisce in modo permissivo, le connessioni Slowloris a goccia lenta, i corpi e gli header delle richieste senza limiti e il request smuggling HTTP. Introduce inoltre le prime primitive di incapsulamento della chiave post-quantistico ML-KEM-768.

Ogni nuova protezione mantiene per impostazione predefinita il comportamento precedente, quindi le applicazioni esistenti non sono interessate finché non le si attiva. Questo articolo illustra ciascuna di esse con frammenti Delphi pronti da incollare.

Server TLS rafforzati

La correzione più importante riguarda il callback di verifica del peer di OpenSSL. Nell'Indy originale, il callback di verifica può fallire in modo permissivo: quando un server richiede un certificato client, la decisione finale era guidata dal callback dell'utente e ignorava il verdetto di OpenSSL stesso, quindi un callback che restituiva successo accettava un certificato scaduto, autofirmato o non attendibile. Il nuovo flag TIdSSLOptions.StrictVerify applica il risultato di OpenSSL, quindi un gestore OnVerifyPeer personalizzato può solo limitare ulteriormente la decisione, mai allentarla.

Altri tre flag collegano opzioni di OpenSSL che gli header avevano già dichiarato ma che la libreria non applicava mai: DisableCompression mitiga CRIME, DisableRenegotiation blocca la rinegoziazione avviata dal client (un DoS asimmetrico sulla CPU) su OpenSSL 1.1.0h e versioni successive, e ServerCipherPreference fa sì che l'ordine dei cifrari del server prevalga nella negoziazione invece di quello del client.

uses
  IdHTTPServer, IdSSLOpenSSL;

var
  oServer: TIdHTTPServer;
  oSSL: TIdServerIOHandlerSSLOpenSSL;
begin
  oServer := TIdHTTPServer.Create(nil);
  oSSL := TIdServerIOHandlerSSLOpenSSL.Create(oServer);

  oSSL.SSLOptions.CertFile    := 'server.pem';
  oSSL.SSLOptions.KeyFile     := 'server.key';
  oSSL.SSLOptions.SSLVersions := [sslvTLSv1_2, sslvTLSv1_3];

  // opt-in hardening, every flag defaults to False
  oSSL.SSLOptions.StrictVerify           := True;  // enforce the OpenSSL verdict
  oSSL.SSLOptions.DisableCompression     := True;  // CRIME
  oSSL.SSLOptions.DisableRenegotiation   := True;  // renegotiation DoS
  oSSL.SSLOptions.ServerCipherPreference := True;  // server picks the cipher

  oServer.IOHandler := oSSL;
  oServer.Active := True;
end;

Imposta VerifyMode su [sslvrfPeer, sslvrfFailIfNoPeerCert] insieme a StrictVerify quando desideri un TLS mutuo che rifiuti effettivamente un certificato client sconosciuto.

Fermare Slowloris

Un client Slowloris apre molte connessioni e invia un byte alla volta, senza mai completare la richiesta, per bloccare ogni thread di lavoro. La difesa naturale sembra essere un timeout di lettura, ma c'è una sottigliezza che vale la pena conoscere: il ReadTimeout di Indy è un timeout di inattività. Ogni byte che arriva lo reimposta, quindi un client che invia un byte ogni pochi secondi mantiene la connessione attiva all'infinito.

2026.6 aggiunge una vera scadenza totale di lettura a TIdIOHandler tramite SetReadDeadline. Viene verificata a ogni lettura, quindi scatta anche mentre i byte continuano ad arrivare a goccia. Il server HTTP la collega automaticamente attraverso la nuova proprietà RequestReadTimeout, che limita il tempo per ricevere la riga di richiesta e gli header e si reimposta per ogni richiesta keep-alive.

uses
  IdHTTPServer;

var
  oServer: TIdHTTPServer;
begin
  oServer := TIdHTTPServer.Create(nil);
  oServer.DefaultPort := 8080;

  // close any client that has not finished sending the request
  // line and headers within 5 seconds, even if it keeps dripping bytes
  oServer.RequestReadTimeout := 5000;

  oServer.Active := True;
end;

Per un TIdTCPServer personalizzato puoi applicare la stessa scadenza manualmente attorno al tuo ciclo di lettura. Passa 0 per azzerarla.

procedure TForm1.ServerExecute(AContext: TIdContext);
var
  vLine: string;
begin
  // bound the whole request to 5 seconds of total read time
  AContext.Connection.IOHandler.SetReadDeadline(5000);
  try
    vLine := AContext.Connection.IOHandler.ReadLn;
    // ... handle the request ...
  finally
    AContext.Connection.IOHandler.SetReadDeadline(0);
  end;
end;

Limiti delle richieste per i server HTTP

Un server HTTP che legge tutto ciò che un client dichiara è un facile bersaglio per l'esaurimento della memoria. Una singola richiesta può annunciare Content-Length: 2000000000 e il server tenterà di bufferizzare due gigabyte, oppure di trasmettere un corpo chunked infinito, oppure di inviare milioni di byte di header. 2026.6 aggiunge tre limiti e un controllo dello smuggling a TIdCustomHTTPServer.

MaxRequestBodySize limita il Content-Length e il corpo chunked sommato e risponde 413 Payload Too Large quando viene superato. MaxHeaderTotalSize limita il totale dei byte degli header e risponde 431 Request Header Fields Too Large. StrictRequestParsing rifiuta le richieste deliberatamente ambigue, come un messaggio che trasporta sia Content-Length sia Transfer-Encoding: chunked (il classico vettore di request smuggling) oppure una dimensione di chunk negativa, rispondendo 400 Bad Request. Anche il ciclo dei trailer-header chunked è ora limitato, quindi un attaccante non può più tenere aperta una connessione con un flusso infinito di righe trailer.

oServer.MaxRequestBodySize := 10 * 1024 * 1024;  // 10 MB, else 413
oServer.MaxHeaderTotalSize := 64 * 1024;         // 64 KB, else 431
oServer.StrictRequestParsing := True;            // reject CL+TE smuggling, else 400

Al livello TCP grezzo, TIdIOHandler.MaxInputBufferSize limita il buffer di input cumulativo per qualsiasi protocollo costruito sull'IOHandler, il che impedisce a una lettura con prefisso di lunghezza o a una riga di dimensioni eccessive di far crescere il buffer senza limiti.

// inside OnConnect / OnExecute of any Indy server
AContext.Connection.IOHandler.MaxInputBufferSize := 1024 * 1024;  // 1 MB cap

Opzionale per impostazione predefinita

Nessuna di queste opzioni modifica il comportamento predefinito. I campi sono tutti disattivati per impostazione predefinita (0 per i limiti di dimensione e timeout, False per i flag booleani), quindi un progetto che viene aggiornato a 2026.6 si comporta esattamente come faceva su 2026.5. Abiliti con precisione le protezioni di cui ha bisogno la tua distribuzione, e lo stesso codice compila su Delphi 7 fino a RAD Studio 13 e Free Pascal.

Anche in questa versione

2026.6 introduce le prime primitive di incapsulamento e decapsulamento post-quantistico ML-KEM-768, disponibili su OpenSSL 3.5 e versioni successive. Espongono una semplice API TBytes in modo da poter aggiungere un passaggio di incapsulamento della chiave post-quantistico in un handshake ibrido accanto al classico scambio ECDH.

Sul versante della compilazione, la compilazione dei pacchetti C++Builder non fallisce più con l'errore MSBuild MSB1008 quando RAD Studio è installato in un percorso che contiene spazi. Il parametro DCC_BpiOutput è ora racchiuso tra virgolette.

Aggiornamento

2026.6 è un aggiornamento drop-in. Non ci sono modifiche che rompono la compatibilità e nulla da migrare, perché ogni nuova protezione è opzionale. Esamina i frammenti riportati sopra e abilita le opzioni adatte al tuo server.

sgcIndy è gratuito. Scarica l'ultima build da esegece.com/products/sgcindy/download.

Domande, feedback o aiuto per rafforzare il tuo server? Contattaci, riceverai una risposta dalle persone che hanno scritto il codice.