mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 19:01:47 +00:00
fix(segurança): corrigir 10 vulnerabilidades do relatório de segurança
- tokens: remover aceite de expiresAt NULL e forçar TTL de 1 ano - tokens: corrigir refresh que invalidava access token anterior - xlsx: desabilitar parsing de fórmulas (CVE-2024-44294) - csp: expandir Content-Security-Policy com origens explícitas - headers: adicionar Referrer-Policy e X-Permitted-Cross-Domain-Policies - api: retornar 401 JSON em vez de redirect 302 em rotas autenticadas - health: remover version disclosure do /api/health - robots.txt: simplificar para não expor rotas internas - sitemap: corrigir URL com protocolo duplicado - criar security.txt (RFC 9116) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,6 @@ import { NextResponse } from "next/server";
|
||||
import { apiTokens } from "@/db/schema";
|
||||
import {
|
||||
extractBearerToken,
|
||||
hashToken,
|
||||
refreshAccessToken,
|
||||
verifyJwt,
|
||||
} from "@/shared/lib/auth/api-token";
|
||||
@@ -59,11 +58,11 @@ export async function POST(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
// Atualizar hash do token e último uso
|
||||
// Atualizar último uso e expiração (sem sobrescrever tokenHash,
|
||||
// pois o JWT é auto-verificável por assinatura)
|
||||
await db
|
||||
.update(apiTokens)
|
||||
.set({
|
||||
tokenHash: hashToken(result.accessToken),
|
||||
lastUsedAt: new Date(),
|
||||
lastUsedIp:
|
||||
request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { and, eq, gt, isNull } from "drizzle-orm";
|
||||
import { NextResponse } from "next/server";
|
||||
import { apiTokens } from "@/db/schema";
|
||||
import { extractBearerToken, hashToken } from "@/shared/lib/auth/api-token";
|
||||
import { extractBearerToken, verifyJwt } from "@/shared/lib/auth/api-token";
|
||||
import { db } from "@/shared/lib/db";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
@@ -17,21 +17,21 @@ export async function POST(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
// Validar token os_xxx via hash lookup
|
||||
if (!token.startsWith("os_")) {
|
||||
// Verificar JWT (assinatura + expiração)
|
||||
const payload = verifyJwt(token);
|
||||
|
||||
if (!payload || payload.type !== "api_access") {
|
||||
return NextResponse.json(
|
||||
{ valid: false, error: "Formato de token inválido" },
|
||||
{ valid: false, error: "Token inválido ou expirado" },
|
||||
{ status: 401 },
|
||||
);
|
||||
}
|
||||
|
||||
// Hash do token para buscar no DB
|
||||
const tokenHash = hashToken(token);
|
||||
|
||||
// Buscar token no banco
|
||||
// Buscar token no banco por tokenId para checar revogação
|
||||
const tokenRecord = await db.query.apiTokens.findFirst({
|
||||
where: and(
|
||||
eq(apiTokens.tokenHash, tokenHash),
|
||||
eq(apiTokens.id, payload.tokenId),
|
||||
eq(apiTokens.userId, payload.sub),
|
||||
isNull(apiTokens.revokedAt),
|
||||
gt(apiTokens.expiresAt, new Date()),
|
||||
),
|
||||
@@ -39,7 +39,7 @@ export async function POST(request: Request) {
|
||||
|
||||
if (!tokenRecord) {
|
||||
return NextResponse.json(
|
||||
{ valid: false, error: "Token inválido ou revogado" },
|
||||
{ valid: false, error: "Token revogado ou não encontrado" },
|
||||
{ status: 401 },
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user