fix: address spec compliance gaps - tenant check, XFF fallback, rate limiting
- Gap 1: Add tenant ID verification after device lookup in SSH relay handleSSH,
closing cross-tenant token reuse vulnerability
- Gap 2: Add X-Forwarded-For fallback (last entry) when X-Real-IP is absent in
SSH relay source IP extraction; import strings package
- Gap 3: Add @limiter.limit("10/minute") to POST /winbox-session and POST
/ssh-session using existing slowapi pattern from app.middleware.rate_limit
- Gap 4: Add TODO comment in open_ssh_session explaining that SSH session count
enforcement is at the poller level; no NATS subject exists yet for API-side
pre-check
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,7 @@ from app.schemas.remote_access import (
|
||||
TunnelStatusItem,
|
||||
WinboxSessionResponse,
|
||||
)
|
||||
from app.middleware.rate_limit import limiter
|
||||
from app.services.audit_service import log_action
|
||||
from sqlalchemy import select
|
||||
|
||||
@@ -102,6 +103,7 @@ async def _check_tenant_access(current_user: CurrentUser, tenant_id: uuid.UUID,
|
||||
summary="Open a WinBox tunnel to the device",
|
||||
dependencies=[Depends(require_operator_or_above)],
|
||||
)
|
||||
@limiter.limit("10/minute")
|
||||
async def open_winbox_session(
|
||||
tenant_id: uuid.UUID,
|
||||
device_id: uuid.UUID,
|
||||
@@ -176,6 +178,7 @@ async def open_winbox_session(
|
||||
summary="Create a single-use SSH WebSocket session token",
|
||||
dependencies=[Depends(require_operator_or_above)],
|
||||
)
|
||||
@limiter.limit("10/minute")
|
||||
async def open_ssh_session(
|
||||
tenant_id: uuid.UUID,
|
||||
device_id: uuid.UUID,
|
||||
@@ -194,6 +197,13 @@ async def open_ssh_session(
|
||||
await _get_device(db, tenant_id, device_id)
|
||||
source_ip = _source_ip(request)
|
||||
|
||||
# TODO(defense-in-depth): No API-side SSH session count check is performed here.
|
||||
# SSH session limits (per-user, per-device, global) are enforced at the poller/SSH
|
||||
# relay level on WebSocket connect. There is currently no NATS subject that exposes
|
||||
# SSH session counts to the API (tunnel.status.list only covers WinBox tunnels).
|
||||
# When such a subject is added, query it here before issuing the token and raise
|
||||
# HTTPException(429) if limits are exceeded, providing earlier feedback to the client.
|
||||
|
||||
try:
|
||||
await log_action(
|
||||
db, tenant_id, current_user.user_id, "ssh_session_open",
|
||||
|
||||
Reference in New Issue
Block a user