Close captcha-bypass and email-abuse vectors

- Block direct /api/auth/sign-up at the middleware (404): it bypassed
  the Turnstile/honeypot wrapper. /api/register is unaffected — it
  invokes auth.handler programmatically, not through HTTP.
- Tighten rate limits on send-verification-email and forget-password
  (3/min/IP): both send emails to arbitrary addresses and shared the
  loose global 100/min limit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 14:18:30 +05:00
parent 85cf8be705
commit 5a67ac8086
2 changed files with 11 additions and 0 deletions
+4
View File
@@ -54,6 +54,10 @@ export const auth = betterAuth({
// массовый сброс паролей + общие IP (офис/NAT). 10/мин/IP — защита
// от брутфорса сохраняется, но терпимо к повторам и опечаткам.
"/sign-in/email": { window: 60, max: 10 },
// Эндпоинты, отправляющие письма на произвольный адрес: глобальный
// лимит 100/мин позволял абузить почтовую репутацию домена.
"/send-verification-email": { window: 60, max: 3 },
"/forget-password": { window: 60, max: 3 },
},
},
trustedOrigins: [
+7
View File
@@ -6,6 +6,13 @@ const PUBLIC_ROUTES = ["/login", "/register", "/verify-email", "/forgot-password
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Прямой Better Auth sign-up обходит Turnstile/honeypot-обёртку
// (/api/register) — наружу закрыт. Сама регистрация не страдает:
// /api/register вызывает auth.handler программно, минуя middleware.
if (pathname.startsWith("/api/auth/sign-up")) {
return new NextResponse(null, { status: 404 });
}
if (
PUBLIC_ROUTES.some((route) => pathname.startsWith(route)) ||
pathname.startsWith("/_next") ||