Skip to content

[P3][security][hardening] api/rbac.py: hmac.compare_digest com API key não-ASCII → TypeError (500) #1150

Description

@FabioLeitao

Contexto

Follow-up do #1143 (fix constant-time do #1134). Ao trocar provided == expected por hmac.compare_digest(provided, expected) em api/rbac.py (~linha 176, resolve_effective_roles_for_request), abriu-se uma aresta de robustez.

Problema

hmac.compare_digest(a, b) exige que os dois args sejam str ASCII-only (ou bytes). Se o atacante mandar uma API key não-ASCII no header (X-API-Key ou Authorization: Bearer … com acento/emoji/byte alto), o compare_digest levanta TypeError → não tratado → HTTP 500.

  • NÃO é bypass de auth — não retorna roles, o request não passa. É robustez: 500 em vez de 401.
  • Severidade LOW/P3: input malformado do atacante causa erro-de-servidor (não vaza nada sensível; no máximo sinaliza que o path de compare foi alcançado).
  • O == antigo não tinha isso (comparava qualquer str) — é regressão de robustez introduzida pelo hardening.

Fix (preserva constant-time)

Comparar em bytes (sem a restrição ASCII do str):

if provided and hmac.compare_digest(provided.encode("utf-8"), expected.encode("utf-8")):
    ...

Non-ASCII vira bytes distintos de expectedcompare_digest retorna False (não-match), sem crash e ainda constant-time. Alternativa: try/except TypeError tratando como não-match (menos limpo).

AC

  • api/rbac.py: comparar em bytes (.encode()) no path da API key.
  • Teste: request com X-API-Key não-ASCII (ex: "café-🔑") → 401 (não-match), não 500.
  • Confirmar que o teste de constant-time existente (test_rbac_api_key_compare_uses_hmac_compare_digest) segue verde.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions