sgcWebSockets의 HTTP 서버 강화

· 컴포넌트

WebSocket 서버는 거의 항상 HTTP도 함께 처리합니다. 소켓을 여는 페이지를 제공하고, 상태 점검에 응답하며, API를 호스팅하거나 프런트엔드로 리디렉션합니다. 그 HTTP 표면에는 잘 알려진 고유의 공격 부류가 있으며, 최신 sgcWebSockets는 그중 가장 중요한 것들을 기본적으로 차단합니다. 이는 Indy 기반 TsgcWebSocketHTTPServer와 Windows http.sys 기반 TsgcWebSocketServer_HTTPAPI 두 HTTP 서버 모두에 적용됩니다.

경로 탐색이 봉쇄됩니다

DocumentRoot를 설정하여 정적 파일을 제공하는 경우, 서버는 이전에 문서 루트와 요청 경로를 결합하여 파일 경로를 구성했습니다. GET /../../../../windows/win.ini 같은 요청이나 URL 인코딩 형태인 /..%2f..%2f...는 웹 루트를 벗어나 임의의 파일을 읽을 수 있었습니다. 이제 서버는 해석된 경로를 정규화하여 DocumentRoot 내부에 머무를 때에만 제공합니다. 벗어나는 것은 모두 거부됩니다. 이 기능은 HTTP/1.x와 HTTP/2 경로 모두에서 항상 활성화되어 있으며 별도 설정이 필요 없습니다.

요청 본문 제한

HTTP 요청 본문에는 내장된 크기 제한이 없어서 클라이언트가 거대한 Content-Length를 선언하고 기가바이트 단위로 스트리밍하여 서버 메모리를 소진시킬 수 있습니다. 새로운 MaxRequestBodySize 속성이 이를 제한합니다. 기본값은 64 MB이며, 더 큰 값을 선언하는 요청은 본문이 버퍼링되기 전에 413으로 거부됩니다. 대용량 업로드를 위해 값을 늘리거나, 0으로 설정하여 제한을 해제할 수 있습니다.

oServer := TsgcWebSocketHTTPServer.Create(nil);
oServer.Port := 80;
oServer.MaxRequestBodySize := 16 * 1024 * 1024;  // 16 MB, reject larger with 413
oServer.Active := True;

더 엄격한 요청 파싱으로 스머글링 차단

HTTP 요청 스머글링은 한 요청이 끝나고 다음 요청이 시작되는 지점에 대해 서버들이 서로 다르게 판단하는 점을 악용하며, 일반적으로 Content-LengthTransfer-Encoding: chunked 헤더를 함께 보내는 방식입니다. 기본적으로 활성화된 새로운 StrictRequestParsing 속성은 이러한 모호한 요청을 400으로 거부하고 더 엄격한 청크 인코딩 검증을 적용하므로, 프런트엔드 프록시와 서버가 동기화에서 어긋날 수 없습니다.

oServer := TsgcWebSocketHTTPServer.Create(nil);
oServer.StrictRequestParsing := True;   // default: reject Content-Length + Transfer-Encoding
oServer.MaxRequestBodySize := 64 * 1024 * 1024;
oServer.Active := True;

HTTP/2 Rapid Reset 방어

HTTP/2 Rapid Reset 공격(CVE-2023-44487)은 스트림을 열고 즉시 RST_STREAM으로 취소하는 동작을 빠른 루프로 반복하여, 클라이언트에게는 거의 비용이 들지 않으면서 서버가 무제한의 요청 작업을 수행하도록 강제합니다. 이제 HTTP/2 서버는 단일 연결이 보낼 수 있는 리셋과 제어 프레임의 수를 제한하고, 100개의 동시 스트림이라는 유한한 기본값을 제공하며, 남용하는 연결을 GOAWAY 프레임으로 닫습니다. HTTP/2는 옵트인 방식이므로 활성화한 경우에만 해당되지만, 활성화했다면 이 방어는 자동으로 작동합니다.

더 깨끗한 응답 헤더

애플리케이션이 요청의 영향을 받는 데이터, 예를 들어 리디렉션 대상이나 엔티티 태그로 응답 헤더를 구성할 때, 그 값에 몰래 삽입된 캐리지 리턴이나 라인 피드가 응답을 분할하고 추가 헤더를 주입할 수 있습니다. 이제 http.sys 서버는 Location, Server, ETag 같은 응답 헤더 값에서 CRLF를 제거하므로, 하나의 값이 더 이상 두 개의 헤더가 될 수 없습니다.

방화벽의 역할

이러한 보호 기능은 서버 자체의 HTTP 파서와 파일 서버에 위치하며, 이는 FirewallRateLimiter 컴포넌트가 도달할 수 없는 계층입니다. IP 필터링, 속도 제한, 출처 정책에는 계속 방화벽을 사용하고, 파싱과 정적 서비스는 내장 방어 기능이 보호하도록 하십시오. 공개 서버의 경우, 실제로 파일을 제공할 때에만 DocumentRoot를 설정하고, MaxRequestBodySize를 실제 최대값에 맞게 조정하며, MaxConnections를 제한하는 것도 권장합니다.

업그레이드

새로운 보호 기능은 업데이트하는 즉시 안전한 기본값으로 활성화되므로, 대부분의 서버는 코드 변경 없이 강화 효과를 얻습니다. 애플리케이션이 64 MB보다 큰 요청 본문을 허용한다면 MaxRequestBodySize를 그에 맞게 늘리십시오. 기존 클라이언트는 영향을 받지 않습니다.

sgcWebSockets 다운로드 페이지에서 업데이트하거나 GetIt 또는 등록된 계정을 통해 받으십시오.

질문, 피드백 또는 마이그레이션 도움이 필요하신가요? 문의하기를 이용하시면 코드를 작성한 사람들로부터 답변을 받으실 수 있습니다.