sgcIndy 2026.6 richtet seine Aufmerksamkeit auf die Server-Seite. Diese Version ergänzt die TLS-, TCP- und HTTP-Server-Komponenten um eine Reihe optionaler Sicherheitshärtungs-Optionen und schließt damit mehrere bekannte Angriffsklassen, gegen die sich der zugrunde liegende Indy-Code nie abgesichert hat: einen Zertifikatsprüfungs-Callback, der im Fehlerfall offen bleibt, langsam tröpfelnde Slowloris-Verbindungen, unbegrenzte Request-Bodys und Header sowie HTTP Request Smuggling. Außerdem liefert sie die ersten ML-KEM-768 Post-Quantum-Primitive zur Schlüsselkapselung.
Jeder neue Schutzmechanismus verwendet standardmäßig das bisherige Verhalten, sodass bestehende Anwendungen unberührt bleiben, bis Sie ihn einschalten. Dieser Beitrag geht jeden einzelnen mit fertigen, direkt einfügbaren Delphi-Snippets durch.
Gehärtete TLS-Server
Die wichtigste Korrektur betrifft den OpenSSL-Peer-Verifizierungs-Callback. Im Standard-Indy kann der Verify-Callback im Fehlerfall offen bleiben: Wenn ein Server ein Client-Zertifikat anfordert, wurde die endgültige Entscheidung vom Benutzer-Callback bestimmt und das eigene Urteil von OpenSSL ignoriert, sodass ein Callback, der Erfolg zurückgab, ein abgelaufenes, selbstsigniertes oder nicht vertrauenswürdiges Zertifikat akzeptierte. Das neue Flag TIdSSLOptions.StrictVerify erzwingt das OpenSSL-Ergebnis, sodass ein eigener OnVerifyPeer-Handler die Entscheidung nur weiter einschränken, niemals jedoch lockern kann.
Drei weitere Flags aktivieren OpenSSL-Optionen, die in den Headern zwar bereits deklariert, von der Bibliothek aber nie angewendet wurden: DisableCompression entschärft CRIME, DisableRenegotiation blockiert die vom Client initiierte Renegotiation (einen CPU-asymmetrischen DoS) ab OpenSSL 1.1.0h, und ServerCipherPreference sorgt dafür, dass die Cipher-Reihenfolge des Servers die Aushandlung gewinnt statt der des Clients.
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;
Setzen Sie VerifyMode auf [sslvrfPeer, sslvrfFailIfNoPeerCert] zusammen mit StrictVerify, wenn Sie mutual TLS möchten, das ein unbekanntes Client-Zertifikat tatsächlich ablehnt.
Slowloris stoppen
Ein Slowloris-Client öffnet viele Verbindungen und tröpfelt jeweils ein Byte nach dem anderen, ohne die Anfrage je abzuschließen, um jeden Worker-Thread zu blockieren. Die naheliegende Abwehr sieht wie ein Lese-Timeout aus, doch es gibt eine erwähnenswerte Feinheit: Der ReadTimeout von Indy ist ein Inaktivitäts-Timeout. Jedes eintreffende Byte setzt ihn zurück, sodass ein Client, der alle paar Sekunden ein Byte sendet, die Verbindung für immer am Leben hält.
2026.6 fügt TIdIOHandler über SetReadDeadline eine echte Gesamt-Lesefrist hinzu. Sie wird bei jedem Lesevorgang geprüft und greift daher auch dann, wenn weiterhin Bytes eintröpfeln. Der HTTP-Server verdrahtet dies automatisch über die neue Eigenschaft RequestReadTimeout, die die Zeit zum Empfang der Request-Zeile und der Header begrenzt und bei jeder Keep-Alive-Anfrage zurückgesetzt wird.
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;
Für einen eigenen TIdTCPServer können Sie dieselbe Frist von Hand um Ihre Leseschleife herum anwenden. Übergeben Sie 0, um sie zu löschen.
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;
Request-Limits für HTTP-Server
Ein HTTP-Server, der alles liest, was ein Client deklariert, ist ein leichtes Ziel für Speichererschöpfung. Eine einzelne Anfrage kann Content-Length: 2000000000 ankündigen, woraufhin der Server versucht, zwei Gigabyte zu puffern, oder einen endlosen chunked Body streamen oder Millionen von Header-Bytes senden. 2026.6 fügt TIdCustomHTTPServer drei Obergrenzen und eine Smuggling-Prüfung hinzu.
MaxRequestBodySize begrenzt die Content-Length und den aufsummierten chunked Body und antwortet mit 413 Payload Too Large, wenn die Grenze überschritten wird. MaxHeaderTotalSize begrenzt die gesamten Header-Bytes und antwortet mit 431 Request Header Fields Too Large. StrictRequestParsing lehnt Anfragen ab, die absichtlich mehrdeutig sind, etwa eine Nachricht, die sowohl Content-Length als auch Transfer-Encoding: chunked trägt (der klassische Request-Smuggling-Vektor), oder eine negative Chunk-Größe, und antwortet mit 400 Bad Request. Die Schleife für chunked Trailer-Header ist nun ebenfalls begrenzt, sodass ein Angreifer eine Verbindung nicht mehr mit einem unendlichen Strom von Trailer-Zeilen offen halten kann.
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
Auf der reinen TCP-Ebene begrenzt TIdIOHandler.MaxInputBufferSize den kumulativen Eingabepuffer für jedes auf dem IOHandler aufbauende Protokoll, was verhindert, dass ein längenpräfixierter Lesevorgang oder eine überlange Zeile den Puffer unbegrenzt anwachsen lässt.
// inside OnConnect / OnExecute of any Indy server
AContext.Connection.IOHandler.MaxInputBufferSize := 1024 * 1024; // 1 MB cap
Optional per Design
Keine dieser Optionen ändert das Standardverhalten. Die Felder sind alle standardmäßig deaktiviert (0 für die Größen- und Timeout-Limits, False für die booleschen Flags), sodass sich ein Projekt, das auf 2026.6 aktualisiert, genauso verhält wie unter 2026.5. Sie aktivieren genau die Schutzmechanismen, die Ihr Deployment benötigt, und derselbe Code kompiliert über Delphi 7 bis RAD Studio 13 und Free Pascal hinweg.
Ebenfalls in dieser Version
2026.6 führt die ersten ML-KEM-768 Post-Quantum-Primitive zur Kapselung und Entkapselung ein, verfügbar ab OpenSSL 3.5. Sie stellen eine einfache TBytes-API bereit, sodass Sie einen Post-Quantum-Schlüsselkapselungsschritt neben dem klassischen ECDH-Austausch in einen hybriden Handshake einbauen können.
Auf der Build-Seite schlägt die Kompilierung von C++Builder-Paketen nicht mehr mit dem MSBuild-Fehler MSB1008 fehl, wenn RAD Studio in einem Pfad mit Leerzeichen installiert ist. Der Parameter DCC_BpiOutput wird nun in Anführungszeichen gesetzt.
Aktualisierung
2026.6 ist ein nahtloses Upgrade. Es gibt keine Breaking Changes und nichts zu migrieren, weil jeder neue Schutzmechanismus optional ist. Sehen Sie sich die obigen Snippets an und aktivieren Sie die Optionen, die zu Ihrem Server passen.
sgcIndy ist kostenlos. Laden Sie den aktuellen Build von esegece.com/products/sgcindy/download herunter.
Fragen, Feedback oder Hilfe bei der Härtung Ihres Servers? Kontaktieren Sie uns, Sie erhalten eine Antwort von den Menschen, die den Code geschrieben haben.
