We schreven eerder over het beveiligen van de HTTP-server. Dit artikel is de andere helft van het verhaal. Een client wordt normaal gesproken behandeld als de vertrouwde kant van het gesprek, maar dat is hij niet: hij verstuurt uw API-sleutels, hij volgt elke redirect die de externe host teruggeeft, hij leest de volledige response in het geheugen, en hij bewaart alle cookies die de response hem vraagt te bewaren. Een vijandig of simpelweg gecompromitteerd endpoint kan al die vier gedragingen tegen u keren.
sgcWebSockets 2026.7 voegt een reeks schakelaars aan de clientzijde toe die elk van die gaten dichten. Ze staan allemaal standaard uit, dus een upgrade verandert niets aan een bestaande toepassing totdat u besluit ze in te schakelen. Ze zijn beschikbaar op de low level HTTP-client, op elke kant-en-klare REST- en AI-client, en op de HTTP/2- en HTTP/3-clients.
Inloggegevens die een redirect volgen
Het klassieke lek aan de clientzijde. U roept een API aan met een Authorization-header, de server antwoordt met een 302 die naar een andere host wijst, en de client herhaalt het verzoek daar braaf, inclusief header en cookies. Uw bearer-token is zojuist overhandigd aan een machine waarmee u nooit van plan was te praten. De redirect hoeft niet eens kwaadaardig te zijn, een aanvaller die een open redirect op de legitieme host kan beïnvloeden is al genoeg.
StripAuthOnCrossHostRedirect verwijdert de Authorization- en Cookie-headers zodra een redirect de oorspronkelijke host verlaat. Het verzoek volgt de redirect nog steeds, het komt alleen zonder uw inloggegevens aan.
uses
sgcHTTP_Client;
var
oHTTP: TsgcIdHTTP;
begin
oHTTP := TsgcIdHTTP.Create(nil);
try
oHTTP.StripAuthOnCrossHostRedirect := True;
oHTTP.Request.CustomHeaders.Values['Authorization'] := 'Bearer ' + vToken;
vResponse := oHTTP.Get('https://api.example.com/v1/account');
finally
oHTTP.Free;
end;
end;
Redirects die downgraden naar gewoon HTTP
Het tweede redirect-probleem. U begint op https://, de server antwoordt met een Location die met http:// begint, en de client herhaalt het verzoek vrolijk in platte tekst. Alles op het pad kan nu de body lezen en de response herschrijven. Dit is precies de downgrade die HSTS in browsers moet voorkomen, en tot nu toe had de HTTP-client daar geen equivalent voor.
NoInsecureRedirect weigert een redirect die het verzoek van HTTPS naar HTTP zou verplaatsen. De redirect wordt afgewezen in plaats van gevolgd.
oHTTP.NoInsecureRedirect := True;
// A 302 from https://api.example.com to http://api.example.com
// is now blocked instead of silently downgraded.
vResponse := oHTTP.Get('https://api.example.com/v1/data');
De twee redirect-schakelaars staan los van elkaar, en in de praktijk wilt u ze allebei. Zet de eerste aan en een redirect naar een andere host draagt uw token niet meer mee. Zet de tweede aan en een redirect kan uw transportbeveiliging niet meer wegnemen.
Responses zonder groottelimiet
Een standaard HTTP-client leest alles wat de server stuurt. Als de server een responsbody van tien gigabyte stuurt, of een chunked response waarin één enkele chunk een lengte van twee gigabyte aankondigt, probeert de client daar ruimte voor te reserveren. Dat is een denial of service van één regel tegen uw eigen proces, en de aanvaller hoeft daarvoor niets te breken, alleen uw verzoek te beantwoorden met meer data dan u verwachtte.
Twee limieten sluiten dit af. MaxResponseSize begrenst de totale grootte van een responsbody, en MaxChunkSize begrenst één chunk van een chunked response. Beide nemen nul als "onbeperkt", wat de standaard is, dus er verandert niets totdat u ze instelt. Wanneer een limiet wordt overschreden, wordt het lezen afgebroken en een exception opgeworpen, de client laat de buffer niet verder groeien.
uses
sgcHTTP_Client;
var
oHTTP: TsgcIdHTTP;
begin
oHTTP := TsgcIdHTTP.Create(nil);
try
oHTTP.MaxResponseSize := 10 * 1024 * 1024; // 10 MB total, 0 = unlimited
oHTTP.MaxChunkSize := 1024 * 1024; // 1 MB per chunk, 0 = unlimited
vResponse := oHTTP.Get('https://api.example.com/v1/report');
finally
oHTTP.Free;
end;
end;
Kies een getal dat weerspiegelt wat het endpoint daadwerkelijk hoort terug te geven. Als u een JSON-API aanroept die met een paar kilobytes antwoordt, is een limiet van een paar megabytes ruim voldoende en verandert een onbegrensde leesactie alsnog in een begrensde.
Cookies die een heel TLD claimen
Een response kan een cookie sturen met een Domain-attribuut. Niets in het wire-formaat verhindert dat die Domain=com of Domain=co.uk claimt. Een client die dat accepteert, is nu bereid de cookie naar elke host onder dat suffix te sturen, wat het cookie-equivalent is van een loper uitdelen. Browsers weigeren dit al jaren met behulp van de Public Suffix List.
RejectPublicSuffixCookies brengt dezelfde regel naar de component. Een cookie waarvan het domein een publiek suffix is in plaats van een echt registreerbaar domein, wordt weggegooid. Let op: als u dit inschakelt, wordt ook cookiebeheer op de client ingeschakeld, want een cookiejar is wat er gefilterd wordt.
oHTTP.RejectPublicSuffixCookies := True;
// Set-Cookie: session=abc; Domain=co.uk -> rejected
// Set-Cookie: session=abc; Domain=example.co.uk -> accepted
2026.7 lost ook twee gerelateerde cookie- en redirect-bugs op die stilletjes fout waren. Relatieve Location-headers worden nu correct omgezet naar absolute URL's, een 307- of 308-redirect behoudt nu de request-methode en de body zoals de specificatie vereist, en een cookie waarvan de vervaldatum niet geparseerd kan worden, wordt behandeld als een sessiecookie in plaats van te worden weggegooid. Max-Age wint nog steeds van Expires wanneer beide aanwezig zijn.
Een grote body uploaden: Expect: 100-continue en chunked requests
Niet elke nieuwe optie gaat over aanvallen, twee ervan gaan over het niet verspillen van bandbreedte. Als u een grote body POST naar een endpoint dat hem toch gaat weigeren (verkeerde inloggegevens, verkeerd contenttype, een quotum dat al is opgebruikt), is het standaardgedrag om eerst de hele body over de lijn te duwen en daarna de 401 te lezen.
UseExpect100Continue stuurt de request-headers met een Expect: 100-continue en wacht tot de server aangeeft dat hij de body wil ontvangen. Als de server in plaats daarvan met een definitieve status antwoordt, stuurt u de payload nooit. Als er helemaal geen groen licht komt, wordt de body alsnog verstuurd, zodat een server die de header negeert gewoon blijft werken.
UseChunkedTransferEncoding dekt het omgekeerde geval af, een upload waarvan u de grootte niet vooraf kent. De body wordt in chunks verstuurd in plaats van met een vaste Content-Length, zodat u hem kunt streamen vanuit een generator, een compressor of een pipe zonder eerst alles te bufferen.
uses
Classes, sgcHTTP_Client;
var
oHTTP: TsgcIdHTTP;
oBody: TStream;
begin
oHTTP := TsgcIdHTTP.Create(nil);
try
oHTTP.UseExpect100Continue := True; // ask before uploading
oHTTP.UseChunkedTransferEncoding := True; // size not known up front
oBody := TFileStream.Create('large_upload.bin', fmOpenRead or fmShareDenyWrite);
try
vResponse := oHTTP.Post('https://api.example.com/v1/upload', oBody);
finally
oBody.Free;
end;
finally
oHTTP.Free;
end;
end;
Dezelfde schakelaars op de kant-en-klare API-clients
Het interessante deel is waar deze properties zich bevinden. Ze worden opnieuw beschikbaar gesteld op TsgcHTTPAPI_client, de basisklasse van elke kant-en-klare REST-client in de bibliotheek. Dat betekent dat u ze rechtstreeks instelt op de component die u al gebruikt, zonder het low level HTTP-object eronder te hoeven aanspreken.
Dat geldt voor de AI- en LLM-clients (OpenAI, Anthropic, Gemini, DeepSeek, Grok, Mistral, Ollama), de OAuth2-client, Google Cloud, WhatsApp, AWS SQS en WebPush, en de Amazon AWS- en Google Cloud API-units.
uses
sgcHTTP_API_OpenAI;
var
oOpenAI: TsgcHTTP_API_OpenAI;
begin
oOpenAI := TsgcHTTP_API_OpenAI.Create(nil);
try
oOpenAI.StripAuthOnCrossHostRedirect := True; // never leak the API key
oOpenAI.NoInsecureRedirect := True; // never fall back to http
oOpenAI.RejectPublicSuffixCookies := True;
oOpenAI.MaxResponseSize := 32 * 1024 * 1024;
oOpenAI.MaxChunkSize := 1024 * 1024;
// ... use the client as usual
finally
oOpenAI.Free;
end;
end;
Een API-sleutel die naar een LLM-provider wordt gestuurd is precies het soort inloggegeven dat u niet mee wilt laten reizen met een redirect weg van het domein van de provider, dus dit is de plek waar het inschakelen van de schakelaars u niets kost en veel oplevert.
HTTP/2 en HTTP/3
De HTTP/2-client krijgt dezelfde bescherming via zijn options-object, TsgcWSHTTP2Client_Options, en de HTTP/3-client stelt de responslimiet rechtstreeks beschikbaar.
uses
sgcHTTP;
var
oHTTP2: TsgcHTTP2Client;
begin
oHTTP2 := TsgcHTTP2Client.Create(nil);
try
oHTTP2.HTTP2Options.StripAuthOnCrossHostRedirect := True;
oHTTP2.HTTP2Options.NoInsecureRedirect := True;
oHTTP2.HTTP2Options.MaxResponseSize := 10 * 1024 * 1024;
finally
oHTTP2.Free;
end;
end;
// HTTP/3
oHTTP3.MaxResponseSize := 10 * 1024 * 1024;
Eén regel voor een veilige TLS-basis
Niets van het bovenstaande helpt als de TLS-laag niets verifieert. sgcWebSockets 2026.7 voegt daar een preset voor toe. Elk TLS-options-object in de bibliotheek, zowel op WebSocket- als op HTTP-componenten, publiceert een Preset-property van het type TsgcTLSPreset. Die staat standaard op tlspCustom, waarmee alles behouden blijft wat u handmatig hebt geconfigureerd.
Als u hem op tlspSecureDefaults zet, worden certificaatverificatie, TLS 1.2 of hoger, en hostnaamverificatie in één regel ingeschakeld.
uses
sgcWebSocket_Types;
begin
oHTTP.TLSOptions.Preset := tlspSecureDefaults;
// certificate verification on, TLS 1.2+, hostname verification on
end;
Combineer de preset met de redirect-schakelaars en de responslimieten en u hebt een client die verifieert met wie hij praat, weigert te downgraden, zijn inloggegevens niet aan een derde partij afgeeft, en niet gedwongen kan worden onbegrensd geheugen te reserveren.
.NET
De managed editie levert dezelfde bescherming in 2026.7. Het verwijderen van inloggegevens bij redirects, de blokkade van HTTPS-downgrades, de limieten per chunk en op de totale response, het weigeren van cookies voor publieke suffixen, Expect: 100-continue en chunked request-bodies zijn er allemaal, inclusief de set HTTP/2-clients. Dezelfde namen, C#-schrijfwijze.
client.StripAuthOnCrossHostRedirect = true;
client.NoInsecureRedirect = true;
client.RejectPublicSuffixCookies = true;
client.MaxResponseSize = 10 * 1024 * 1024;
client.MaxChunkSize = 1024 * 1024;
Beschikbaarheid
De beveiligingsopties voor de HTTP-client zijn beschikbaar in sgcWebSockets 2026.7 in Delphi 7 tot en met 13 en C++Builder (Win32/Win64, Linux64, macOS, Android en iOS), en in de .NET-editie. Alles wat hier beschreven is, is optioneel en staat standaard uit, dus een upgrade is een drop-in.
Klanten met een actief abonnement kunnen de nieuwe build downloaden in het klantengedeelte. Trialgebruikers kunnen het bijgewerkte installatieprogramma ophalen op esegece.com/products/websockets/download.
Vragen, feedback of hulp bij het bepalen welke van deze schakelaars uw toepassing zou moeten inschakelen? Neem contact op, u krijgt antwoord van de mensen die de code hebben geschreven.
