Add 'gerenciador/' from commit '34cc9c75a57dedbf61a6e6a1ba1f35f76e72434b'
git-subtree-dir: gerenciador git-subtree-mainline:f4f546c928git-subtree-split:34cc9c75a5
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
"""
|
||||
Proteção CSRF via "double-submit cookie": o middleware registrado em
|
||||
app/main.py garante que todo navegador que acessa o painel tenha um cookie
|
||||
"csrf_token" (gerado uma vez, aleatório, HttpOnly). Todo formulário que
|
||||
muda estado (POST) embute esse mesmo valor como campo oculto — os
|
||||
templates leem de request.state.csrf_token, que o middleware preenche a
|
||||
cada requisição. Toda rota POST que muda estado usa Depends(exigir_csrf),
|
||||
que confere se o valor enviado no formulário bate com o valor do cookie.
|
||||
|
||||
Por quê isso barra CSRF: um site hostil consegue forçar o navegador da
|
||||
vítima a mandar um POST para o painel (o cookie vai junto automaticamente),
|
||||
mas não consegue LER o valor do cookie para replicá-lo como campo oculto do
|
||||
formulário forjado — só JavaScript rodando na própria origem do painel
|
||||
consegue (e não roda em outra origem, por causa do same-origin policy).
|
||||
"""
|
||||
import secrets
|
||||
|
||||
from fastapi import HTTPException, Request, status
|
||||
|
||||
CSRF_COOKIE_NAME = "csrf_token"
|
||||
|
||||
|
||||
def gerar_token() -> str:
|
||||
return secrets.token_urlsafe(32)
|
||||
|
||||
|
||||
def token_do_contexto(request: Request) -> str:
|
||||
"""
|
||||
Lê o token que o middleware colocou em request.state.csrf_token.
|
||||
Retorna "" se o middleware não estiver montado (por exemplo, testes que
|
||||
sobem só um router isolado, sem app/main.py) — nesse caso o formulário
|
||||
simplesmente não terá csrf_token preenchido, e exigir_csrf abaixo vai
|
||||
rejeitar o POST a menos que o teste monte o cookie/campo manualmente.
|
||||
"""
|
||||
return getattr(request.state, "csrf_token", "")
|
||||
|
||||
|
||||
async def exigir_csrf(request: Request) -> None:
|
||||
"""Dependency para toda rota POST que muda estado."""
|
||||
form = await request.form()
|
||||
token_formulario = str(form.get(CSRF_COOKIE_NAME, ""))
|
||||
token_cookie = request.cookies.get(CSRF_COOKIE_NAME, "")
|
||||
if not token_cookie or not token_formulario or not secrets.compare_digest(token_formulario, token_cookie):
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Token CSRF ausente ou inválido.")
|
||||
Reference in New Issue
Block a user