sgcIndy 2026.6 centra su atención en el lado del servidor. Esta versión añade un conjunto de opciones de refuerzo de seguridad opcional a los componentes de servidor TLS, TCP y HTTP, cerrando una serie de clases de ataque bien conocidas frente a las que el código subyacente de Indy nunca protegía: una devolución de llamada de verificación de certificados que fallaba en abierto, conexiones Slowloris de goteo lento, cuerpos y cabeceras de solicitud sin límite, y el request smuggling HTTP. También incorpora las primeras primitivas poscuánticas de encapsulación de claves ML-KEM-768.
Cada nueva protección toma como valor predeterminado el comportamiento anterior, de modo que las aplicaciones existentes no se ven afectadas hasta que las actives. Esta entrada repasa cada una con fragmentos de Delphi listos para pegar.
Servidores TLS reforzados
La corrección más importante está en la devolución de llamada de verificación del par de OpenSSL. En el Indy original, la devolución de llamada de verificación puede fallar en abierto: cuando un servidor solicita un certificado de cliente, la decisión final la dirigía la devolución de llamada del usuario e ignoraba el veredicto del propio OpenSSL, por lo que una devolución de llamada que devolviera éxito aceptaba un certificado caducado, autofirmado o no confiable. El nuevo indicador TIdSSLOptions.StrictVerify impone el resultado de OpenSSL, de manera que un manejador OnVerifyPeer personalizado solo puede restringir más la decisión, nunca relajarla.
Otros tres indicadores conectan opciones de OpenSSL que las cabeceras ya declaraban pero que la biblioteca nunca aplicaba: DisableCompression mitiga CRIME, DisableRenegotiation bloquea la renegociación iniciada por el cliente (un DoS asimétrico en CPU) en OpenSSL 1.1.0h y posteriores, y ServerCipherPreference hace que el orden de cifrado del servidor gane la negociación en lugar del orden del cliente.
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;
Establece VerifyMode en [sslvrfPeer, sslvrfFailIfNoPeerCert] junto con StrictVerify cuando quieras un TLS mutuo que realmente rechace un certificado de cliente desconocido.
Detener Slowloris
Un cliente Slowloris abre muchas conexiones y va soltando un byte cada vez, sin completar nunca la solicitud, para mantener ocupado cada hilo de trabajo. La defensa natural parece un tiempo de espera de lectura, pero hay un matiz que conviene conocer: el ReadTimeout de Indy es un tiempo de espera de inactividad. Cada byte que llega lo reinicia, así que un cliente que envía un byte cada pocos segundos mantiene la conexión viva para siempre.
2026.6 añade un verdadero plazo total de lectura a TIdIOHandler mediante SetReadDeadline. Se comprueba en cada lectura, por lo que se dispara incluso mientras siguen goteando bytes. El servidor HTTP lo conecta automáticamente a través de la nueva propiedad RequestReadTimeout, que limita el tiempo para recibir la línea de solicitud y las cabeceras y se reinicia por cada solicitud 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;
Para un TIdTCPServer personalizado puedes aplicar el mismo plazo a mano alrededor de tu bucle de lectura. Pasa 0 para borrarlo.
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;
Límites de solicitud para servidores HTTP
Un servidor HTTP que lee lo que sea que un cliente declare es un blanco fácil para el agotamiento de memoria. Una sola solicitud puede anunciar Content-Length: 2000000000 y el servidor intentará almacenar dos gigabytes en búfer, o transmitir un cuerpo chunked sin fin, o enviar millones de bytes de cabecera. 2026.6 añade tres topes y una comprobación de smuggling a TIdCustomHTTPServer.
MaxRequestBodySize limita el Content-Length y la suma del cuerpo chunked y responde 413 Payload Too Large cuando se supera. MaxHeaderTotalSize limita el total de bytes de cabecera y responde 431 Request Header Fields Too Large. StrictRequestParsing rechaza solicitudes ambiguas a propósito, como un mensaje que lleva a la vez Content-Length y Transfer-Encoding: chunked (el vector clásico de request smuggling) o un tamaño de chunk negativo, respondiendo 400 Bad Request. El bucle de cabeceras de tráiler chunked también está ahora acotado, así que un atacante ya no puede mantener una conexión abierta con un flujo infinito de líneas de tráiler.
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
En la capa TCP en bruto, TIdIOHandler.MaxInputBufferSize acota el búfer de entrada acumulado para cualquier protocolo construido sobre el IOHandler, lo que impide que una lectura con prefijo de longitud o una línea sobredimensionada hagan crecer el búfer sin límite.
// inside OnConnect / OnExecute of any Indy server
AContext.Connection.IOHandler.MaxInputBufferSize := 1024 * 1024; // 1 MB cap
Opcional por diseño
Ninguna de estas opciones cambia el comportamiento predeterminado. Todos los campos están desactivados por defecto (0 para los límites de tamaño y de tiempo de espera, False para los indicadores booleanos), así que un proyecto que se actualiza a 2026.6 se comporta exactamente igual que en 2026.5. Habilitas exactamente las protecciones que tu despliegue necesita, y el mismo código compila en Delphi 7 hasta RAD Studio 13 y Free Pascal.
También en esta versión
2026.6 introduce las primeras primitivas poscuánticas de encapsulación y desencapsulación ML-KEM-768, disponibles en OpenSSL 3.5 y posteriores. Exponen una API sencilla de TBytes para que puedas incorporar un paso poscuántico de encapsulación de claves en un handshake híbrido junto al intercambio ECDH clásico.
En el lado de la compilación, la compilación de paquetes de C++Builder ya no falla con el error de MSBuild MSB1008 cuando RAD Studio está instalado en una ruta que contiene espacios. El parámetro DCC_BpiOutput ahora va entrecomillado.
Actualización
2026.6 es una actualización directa. No hay cambios incompatibles ni nada que migrar, porque cada nueva protección es opcional. Revisa los fragmentos anteriores y habilita las opciones que se adapten a tu servidor.
sgcIndy es gratuito. Descarga la última compilación desde esegece.com/products/sgcindy/download.
¿Preguntas, comentarios o ayuda para reforzar tu servidor? Ponte en contacto, recibirás una respuesta de las personas que escribieron el código.
