Repository navigation
fix(websocket): validate WebSocket frame headers - #925
Open
zhouyunding wants to merge 1 commit into
Open
zhouyunding wants to merge 1 commit into
zhouyunding wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Addresses #896 (server side).
libhv's WebSocket parser accepted protocol-violating frames and delivered them to the application layer. Measured against a 57-case probe (41 frames that RFC 6455 requires a server to reject, 16 that must pass): the baseline accepted 55/57 violating frames; only the two control-frame rules added by #904 were enforced.
Root cause
websocket_parser.cassembles frame flags and dispatches payloads without validating:The RSV bits were folded into the internal flags before any validation could see them, so RSV-marked frames were delivered as ordinary messages.
Approach and trade-offs
nfeed != len), which makes the existing public call sites (HttpHandler.cpp,WebSocketClient.cpp) fail closed and close the connection.HttpHandler.cpp:208server side,WebSocketClient.cpp:149client side), before anyFeedRecvDatacall.Behavior changes (disclosure)
nfeed != lenas an error and close, so this is fail-closed in practice.http/WebSocketParser.cpp). Semantic interaction with open PR Add HTTP gzip/zstd compression and WebSocket permessage-deflate support #819: this PR rejects RSV1 unconditionally, which is correct while no extension is negotiated; if permessage-deflate (Add HTTP gzip/zstd compression and WebSocket permessage-deflate support #819) lands, RSV1 handling will need to be gated on successful extension negotiation.Test evidence (before / after, same probe)
Probe of 57 frames (41 must-reject, 16 must-accept), run against baseline
060a4b6and this commitfc9d417:consumed < len, 0 delivered); 16/16 must-accept frames delivered with correct payload (extended lengths, fragmentation, interleaved PING).PASS: 10 WebSocket parser tests.hv::WebSocketServerwith raw TCP clients: unmasked / RSV / reserved-opcode frames →msgs=0and connection closed by peer; valid frames still echoed.unittest/websocket_parser_test.cpp'smaingained an optional single-test-name argument used for the per-group RED/GREEN reproduction; running it without arguments behaves exactly as before.Environment: Windows 11, MinGW UCRT64 (gcc 16.2.0), CMake Release. Not covered locally: ASan/UBSan (no sanitizer runtime in MinGW), Linux/macOS/MSVC builds (left to CI), the TLS/wss path, and fuzzing.
AI disclosure
This change was prepared with AI assistance: an AI agent wrote the implementation and tests under human direction, and independent AI agents performed the code review and the verification reported above. The human contributor takes responsibility for the change.