diff --git a/Dockerfile b/Dockerfile index df5efa5..d3d1c4f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,5 +3,12 @@ WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY app ./app +# Não roda como root dentro do container — reduz o estrago de uma +# eventual RCE (mesmo sem vulnerabilidade conhecida hoje, é uma +# mitigação de baixo custo e sem efeito colateral aqui, já que a app não +# precisa gravar nada no filesystem além de escutar a porta 8000, que não +# é privilegiada). +RUN useradd --no-create-home --shell /usr/sbin/nologin painel +USER painel EXPOSE 8000 CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/app/main.py b/app/main.py index 81dce00..67c397e 100644 --- a/app/main.py +++ b/app/main.py @@ -45,11 +45,50 @@ async def csrf_cookie_middleware(request: Request, call_next): if precisa_definir_cookie: response.set_cookie( - CSRF_COOKIE_NAME, request.state.csrf_token, httponly=True, samesite="strict" + CSRF_COOKIE_NAME, request.state.csrf_token, httponly=True, samesite="strict", + # Secure só quando a requisição já chegou em HTTPS — ver o + # comentário equivalente em app/routers/auth.py sobre o + # cookie de sessão (mesma razão, mesmo cuidado com proxy). + secure=request.url.scheme == "https", ) return response +@app.middleware("http") +async def security_headers_middleware(request: Request, call_next): + """ + Cabeçalhos de resposta que não dependem de nenhuma lógica de negócio, + só reduzem a superfície de ataque do navegador: impedem o painel de + ser carregado dentro de um