fix: resolve auth security issues - 2FA require TOTP on disable, rate limiting, timing-safe login, token expiry check

This commit is contained in:
remco committed 2026-07-02 14:54:25 +02:00
1 parent 4a06b30263
commit 64f50b2dde
6 files changed
+63 -9

No files matched your search

+4 -3
View File
@@ -6,8 +6,6 @@ import { prisma } from "@/lib/prisma";
* (the Laravel Sanctum table that already exists in the emulator DB). Tokens are
* stored as the sha256 of the plaintext; the client sends the plaintext (or the
* Sanctum "{id}|{plaintext}" form) as `Authorization: Bearer …`.
*
* NOTE: the live amx_test table has NO expires_at column — never read/write it.
*/
const TOKENABLE_TYPE = "App\\Models\\User";
@@ -27,7 +25,10 @@ export async function bearerUserId(req: Request): Promise<number | null> {
try {
const row = await prisma.personalAccessTokens.findFirst({
where: { token: hashToken(raw) },
where: {
token: hashToken(raw),
OR: [{ expiresAt: null }, { expiresAt: { gt: new Date() } }],
},
select: { id: true, tokenableId: true },
});
if (!row) return null;
+9 -1
View File
@@ -29,7 +29,15 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
if (!rateLimit(`login:${await clientIp()}`, 10, 5 * 60_000).ok) return null;
const user = await prisma.user.findUnique({ where: { username } });
if (!user) return null;
if (!user) {
// Prevent timing-based enumeration: always run a dummy hash check.
await checkLogin(
password,
"$2y$12$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcd",
{ convertPasswords: false },
);
return null;
}
// Byte-compatible AtomCMS check (argon2id/bcrypt + md5->argon2id upgrade).
const res = await checkLogin(password, user.password, {