Reforçando a Segurança do Servidor WebSocket no sgcWebSockets

· Componentes

Um servidor WebSocket exposto à internet pública é um alvo tentador. O protocolo não possui um limite de tamanho de mensagem integrado, então uma única conexão pode tentar derrubar todo o processo com um único frame malicioso, e o handshake de upgrade é um lugar fácil para sondar validações descuidadas. A versão mais recente do sgcWebSockets traz um conjunto de proteções que fecham essas portas por padrão, de modo que o seu servidor permaneça no ar mesmo sob tráfego hostil.

Tudo o que segue abaixo se aplica aos três servidores WebSocket: TsgcWebSocketServer, TsgcWebSocketHTTPServer e o TsgcWebSocketServer_HTTPAPI baseado em http.sys. A edição .NET herda as mesmas proteções, porque é executada sobre a mesma biblioteca nativa.

Um limite que interrompe três ataques de memória

A principal novidade é uma única propriedade, MaxMessageSize, que limita o tamanho que uma mensagem de entrada pode ter. O valor padrão é 64 MB, que é generoso para praticamente todas as aplicações, e você pode aumentá-lo ou reduzi-lo, ou defini-lo como 0 para desativar o limite.

Essa única propriedade defende contra três técnicas diferentes de esgotamento de memória que terminam todas da mesma forma, com o servidor sem RAM:

Em todos os casos a conexão é fechada de forma limpa com o close code WebSocket 1009 (Message Too Big), e a memória do servidor nunca ultrapassa o limite.

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;

Análise segura do comprimento dos frames

Os frames WebSocket podem carregar um campo de comprimento de 64-bit. Conforme a RFC 6455, o bit mais significativo desse campo deve ser zero. O sgcWebSockets agora rejeita um frame cujo comprimento de 64-bit tem o bit alto definido em vez de confiar nele, de modo que o limite de tamanho acima não pode ser burlado com um inteiro que sofre overflow. Essa verificação está sempre ativa e não depende de MaxMessageSize.

Handshakes mais rigorosos

Duas novas opções em SecurityOptions reforçam o próprio upgrade WebSocket, e ambas estão habilitadas por padrão.

EnforceWebSocketVersion responde a qualquer handshake que solicite uma versão diferente de 13 com 426 Upgrade Required e um cabeçalho Sec-WebSocket-Version: 13, em vez de concluir o upgrade. ValidateWebSocketKey rejeita, com 400 Bad Request, qualquer handshake cuja Sec-WebSocket-Key esteja ausente ou não seja um nonce base64 válido de 16 bytes. Ambas as verificações se aplicam somente ao caminho da RFC 6455, então clientes mais antigos em especificações legadas não são afetados.

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;

Como isso se integra ao firewall

Essas proteções residem na camada de protocolo, dentro do parser de frames, que é exatamente onde os ataques de memória acontecem. Essa é a parte que os componentes Firewall e RateLimiter não conseguem alcançar, porque eles veem uma mensagem somente depois que ela foi decodificada. As duas camadas se complementam: continue usando o firewall e o rate limiter para filtragem de IP, limites de taxa de conexão e de mensagem e política de origem, e deixe que os novos limites integrados protejam o próprio parser. Para um servidor público, recomendamos definir MaxMessageSize com o seu máximo real, travar OriginsAllowed no seu front end e limitar MaxConnections.

Atualizando

As novas proteções ficam ativas assim que você atualiza, com valores padrão seguros, de modo que a maioria dos servidores ganha o reforço de memória e de handshake sem uma única alteração de código. Se a sua aplicação legitimamente troca mensagens maiores que 64 MB, aumente MaxMessageSize de acordo. O código de cliente existente não é afetado.

Atualize na página de download do sgcWebSockets, ou obtenha-o através do GetIt ou da sua conta registrada.

Dúvidas, feedback ou ajuda com a migração? Entre em contato, você receberá uma resposta das pessoas que escreveram o código.