fix: review fixes for WsReadInfo and WsUpgrade
- WsReadInfo: validate 64-bit frame payload length against maxPayload before casting to int (prevents overflow/memory exhaustion) - WsReadInfo: always send close response per RFC 6455 Section 5.5.1, including for empty close frames - WsUpgrade: restrict no-masking to leaf node connections only (browser clients must always mask frames)
This commit is contained in:
@@ -176,7 +176,10 @@ public struct WsReadInfo
|
||||
{
|
||||
var (lenBuf, p2) = WsGet(stream, buf, pos, max, 8);
|
||||
pos = p2;
|
||||
r.Remaining = (int)BinaryPrimitives.ReadUInt64BigEndian(lenBuf);
|
||||
var len64 = BinaryPrimitives.ReadUInt64BigEndian(lenBuf);
|
||||
if (len64 > (ulong)maxPayload)
|
||||
throw new InvalidOperationException($"frame payload length {len64} exceeds max payload {maxPayload}");
|
||||
r.Remaining = (int)len64;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -264,11 +267,17 @@ public struct WsReadInfo
|
||||
if (payload.Length > WsConstants.CloseStatusSize)
|
||||
r.CloseBody = Encoding.UTF8.GetString(payload.AsSpan(WsConstants.CloseStatusSize));
|
||||
}
|
||||
// Per RFC 6455 Section 5.5.1, always send a close response
|
||||
if (r.CloseStatus != WsConstants.CloseStatusNoStatusReceived)
|
||||
{
|
||||
var closeMsg = WsFrameWriter.CreateCloseMessage(r.CloseStatus, r.CloseBody ?? "");
|
||||
r.PendingControlFrames.Add(new ControlFrameAction(WsConstants.CloseMessage, closeMsg));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Empty close frame — respond with empty close
|
||||
r.PendingControlFrames.Add(new ControlFrameAction(WsConstants.CloseMessage, []));
|
||||
}
|
||||
break;
|
||||
|
||||
case WsConstants.PingMessage:
|
||||
|
||||
@@ -62,8 +62,9 @@ public static class WsUpgrade
|
||||
ext.Contains(WsConstants.PmcExtension, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
// No-masking support
|
||||
bool noMasking = headers.TryGetValue(WsConstants.NoMaskingHeader, out var nmVal) &&
|
||||
// No-masking support (leaf nodes only — browser clients must always mask)
|
||||
bool noMasking = kind == WsClientKind.Leaf &&
|
||||
headers.TryGetValue(WsConstants.NoMaskingHeader, out var nmVal) &&
|
||||
string.Equals(nmVal.Trim(), WsConstants.NoMaskingValue, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// Browser detection
|
||||
|
||||
Reference in New Issue
Block a user