fix(webui): require proxy-generated auth assertions
This commit is contained in:
@@ -93,6 +93,24 @@ from nanobot.webui.websocket_logging import websockets_server_logger
|
||||
_WEBUI_HTTP_OPEN_TIMEOUT_S = 360.0
|
||||
|
||||
|
||||
_ROUTING_ASSERTION_HEADERS = frozenset(
|
||||
{
|
||||
"host",
|
||||
"forwarded",
|
||||
"x-forwarded-for",
|
||||
"x-forwarded-host",
|
||||
"x-forwarded-proto",
|
||||
"x-real-ip",
|
||||
"cf-connecting-ip",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _is_routing_assertion_header(value: str) -> bool:
|
||||
normalized = value.casefold()
|
||||
return normalized in _ROUTING_ASSERTION_HEADERS or normalized.startswith("x-forwarded-")
|
||||
|
||||
|
||||
class TrustedProxyAuthConfig(Base):
|
||||
"""Authentication assertions accepted from explicitly trusted proxy peers."""
|
||||
|
||||
@@ -128,6 +146,11 @@ class TrustedProxyAuthConfig(Base):
|
||||
value = value.strip()
|
||||
if not value or any(char.isspace() or ord(char) < 0x21 for char in value):
|
||||
raise ValueError("assertion_header must be a valid HTTP header name")
|
||||
if _is_routing_assertion_header(value):
|
||||
raise ValueError(
|
||||
"assertion_header must identify a proxy-generated authentication assertion, "
|
||||
"not a routing or client metadata header"
|
||||
)
|
||||
return value
|
||||
|
||||
@model_validator(mode="after")
|
||||
|
||||
@@ -3473,6 +3473,16 @@ def test_trusted_proxy_rejects_invalid_or_universal_cidrs(
|
||||
with pytest.raises(ValidationError):
|
||||
WebSocketConfig.model_validate(_trusted_proxy_config([cidr]))
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"assertion_header",
|
||||
["Host", "Forwarded", "X-Forwarded-For", "X-Real-IP", "CF-Connecting-IP"],
|
||||
)
|
||||
def test_trusted_proxy_rejects_routing_headers(assertion_header: str) -> None:
|
||||
from pydantic_core import ValidationError
|
||||
|
||||
with pytest.raises(ValidationError, match="proxy-generated"):
|
||||
WebSocketConfig.model_validate(_trusted_proxy_config(assertion_header=assertion_header))
|
||||
|
||||
def test_wildcard_host_without_auth_raises_on_startup(bus: MagicMock) -> None:
|
||||
import pytest
|
||||
from pydantic_core import ValidationError
|
||||
|
||||
Reference in New Issue
Block a user