Un serveur WebSocket exposé sur l'internet public est une cible tentante. Le protocole n'impose aucune limite de taille de message, de sorte qu'une seule connexion peut tenter de faire tomber tout le processus avec une trame conçue à dessein, et le handshake de mise à niveau est un endroit facile pour sonder une validation négligée. La dernière version de sgcWebSockets embarque un ensemble de protections qui ferment ces portes par défaut, afin que votre serveur reste en ligne même sous un trafic hostile.
Tout ce qui suit s'applique aux trois serveurs WebSocket : TsgcWebSocketServer, TsgcWebSocketHTTPServer et le TsgcWebSocketServer_HTTPAPI basé sur http.sys. L'édition .NET hérite des mêmes protections, car elle s'appuie sur la même bibliothèque native.
Une seule limite qui bloque trois attaques mémoire
L'ajout majeur est une unique propriété, MaxMessageSize, qui limite la taille maximale d'un message entrant. Sa valeur par défaut est de 64 MB, ce qui est généreux pour presque toutes les applications, et vous pouvez l'augmenter ou la diminuer, ou la définir à 0 pour désactiver la limite.
Cette seule propriété protège contre trois techniques différentes d'épuisement de la mémoire qui se terminent toutes de la même manière, avec un serveur à court de RAM :
- Trames surdimensionnées. Un client déclare une longueur de charge utile énorme. Le serveur rejette désormais la trame avant de commencer à en lire le corps.
- Fragmentation sans fin. Un client ouvre un message fragmenté et ne le termine jamais, diffusant des trames de continuation à l'infini. Le serveur plafonne désormais la taille totale réassemblée sur l'ensemble des fragments.
- Bombes de compression. Une minuscule trame per-message-deflate qui se décompresse en gigaoctets. Le serveur arrête désormais la décompression dès que la sortie décompressée atteint la limite.
Dans tous les cas, la connexion est fermée proprement avec le close code WebSocket 1009 (Message Too Big), et la mémoire du serveur ne dépasse jamais le plafond.
oServer := TsgcWebSocketServer.Create(nil);
oServer.Port := 80;
// accept messages up to 16 MB, reject anything larger with close 1009
oServer.MaxMessageSize := 16 * 1024 * 1024;
oServer.Active := True;
Analyse sûre de la longueur des trames
Les trames WebSocket peuvent transporter un champ de longueur 64-bit. Selon la RFC 6455, le bit le plus significatif de ce champ doit être à zéro. sgcWebSockets rejette désormais une trame dont la longueur 64-bit a le bit de poids fort activé au lieu de lui faire confiance, de sorte que la limite de taille ci-dessus ne peut pas être contournée par un entier qui déborde. Ce contrôle est toujours actif et ne dépend pas de MaxMessageSize.
Des handshakes plus stricts
Deux nouvelles options sous SecurityOptions renforcent la mise à niveau WebSocket elle-même, et toutes deux sont activées par défaut.
EnforceWebSocketVersion répond à tout handshake qui demande une version autre que 13 par 426 Upgrade Required et un en-tête Sec-WebSocket-Version: 13, au lieu de finaliser la mise à niveau. ValidateWebSocketKey rejette, par 400 Bad Request, tout handshake dont la Sec-WebSocket-Key est absente ou n'est pas un nonce base64 valide de 16 octets. Ces deux contrôles ne s'appliquent qu'au chemin RFC 6455, de sorte que les clients plus anciens utilisant des spécifications héritées ne sont pas affectés.
oServer := TsgcWebSocketServer.Create(nil);
oServer.SecurityOptions.EnforceWebSocketVersion := True; // 426 on a wrong version
oServer.SecurityOptions.ValidateWebSocketKey := True; // 400 on a malformed key
// lock the server to your own site while you are at it
oServer.SecurityOptions.OriginsAllowed := 'https://app.example.com';
oServer.Active := True;
Comment cela s'articule avec le pare-feu
Ces protections se situent au niveau de la couche protocole, à l'intérieur de l'analyseur de trames, c'est-à-dire exactement là où surviennent les attaques mémoire. C'est la partie que les composants Firewall et RateLimiter ne peuvent pas atteindre, car ils ne voient un message qu'une fois celui-ci décodé. Les deux couches se complètent : continuez à utiliser le pare-feu et le limiteur de débit pour le filtrage IP, les limites de débit de connexion et de message et la politique d'origine, et laissez les nouvelles limites intégrées protéger l'analyseur lui-même. Pour un serveur public, nous recommandons de définir MaxMessageSize à votre maximum réel, de verrouiller OriginsAllowed sur votre frontal et de plafonner MaxConnections.
Mise à niveau
Les nouvelles protections sont actives dès la mise à jour, avec des valeurs par défaut sûres, de sorte que la plupart des serveurs bénéficient du renforcement de la mémoire et du handshake sans la moindre modification de code. Si votre application échange légitimement des messages de plus de 64 MB, augmentez MaxMessageSize en conséquence. Le code client existant n'est pas affecté.
Mettez à jour depuis la page de téléchargement de sgcWebSockets, ou récupérez-le via GetIt ou votre compte enregistré.
Des questions, des retours ou besoin d'aide pour la migration ? Contactez-nous, vous recevrez une réponse des personnes qui ont écrit le code.
