Hiz siniri: giris, kayit ve arama uclari

Uygulamada hicbir hiz siniri yoktu. /api/auth/login sinirsiz sifre denemesine,
/api/auth/register sinirsiz sahte hesap acmaya aciкti (her hesap FREE plan
kotasi alir = dogrudan maliyet).

- src/lib/rate-limit.ts: IP basina sabit pencere sayaci, surec belleginde
  (ek altyapi yok). Cok instance'a cikilirsa Redis/Postgres'e tasinmali.
- giris 10/15dk — sayac IP+eposta bazli: tek IP'den farkli hesaplara
  saldiri da yavaslar
- kayit 5/saat
- ads/search 60/dk — kota kontrolu zaten var, bu limit agir sorgu seliyle
  veritabanini bogmayi engeller
- 429 + Retry-After + Turkce mesaj
- IP: x-forwarded-for'un SON elemani (ilk eleman istemci tarafindan
  uydurulabilir; son elemani bizim proxy ekler)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-02 13:50:10 +03:00
co-authored by Claude Opus 5
parent 4e8dcf207d
commit 2441519ab6
4 changed files with 113 additions and 0 deletions
+6
View File
@@ -5,8 +5,14 @@ import { currentUser } from "@/lib/auth/current-user";
import { checkAndConsumeQuota } from "@/lib/quota";
import { maskAdForPlan } from "@/lib/locked-response";
import { planFromUser } from "@/lib/plans";
import { hizSiniriAsimi } from "@/lib/rate-limit";
export async function GET(req: Request) {
// Kota kontrolü zaten var; bu limit kota tüketmeyen planlarda da
// veritabanını ağır sorgu seliyle boğmayı engeller.
const sinir = hizSiniriAsimi(req, "arama");
if (sinir) return sinir;
const user = await currentUser();
if (!user) return NextResponse.json({ error: "UNAUTHORIZED" }, { status: 401 });
+5
View File
@@ -3,11 +3,16 @@ import { NextResponse } from "next/server";
import { z } from "zod";
import { prisma } from "@/lib/db";
import { createSession } from "@/lib/auth/session";
import { hizSiniriAsimi } from "@/lib/rate-limit";
const schema = z.object({ email: z.string().email(), password: z.string().min(1) });
export async function POST(req: Request) {
const body = schema.parse(await req.json());
// Sayaç e-posta bazlı da tutulur: tek IP'den farklı hesaplara saldırı da yavaşlar.
const sinir = hizSiniriAsimi(req, "giris", body.email.trim().toLowerCase());
if (sinir) return sinir;
const user = await prisma.user.findUnique({ where: { email: body.email } });
if (!user?.passwordHash) return NextResponse.json({ error: "INVALID_CREDENTIALS" }, { status: 401 });
const ok = await bcrypt.compare(body.password, user.passwordHash);
+5
View File
@@ -5,6 +5,7 @@ import { z } from "zod";
import { prisma } from "@/lib/db";
import { createSession } from "@/lib/auth/session";
import { isConfiguredAdminEmail } from "@/lib/admin-emails";
import { hizSiniriAsimi } from "@/lib/rate-limit";
const schema = z.object({
email: z.string().email(),
@@ -13,6 +14,10 @@ const schema = z.object({
});
export async function POST(req: Request) {
// Sahte hesap seli = ücretsiz plan kotası tüketimi (doğrudan maliyet).
const sinir = hizSiniriAsimi(req, "kayit");
if (sinir) return sinir;
const body = schema.parse(await req.json());
const email = body.email.trim().toLowerCase();
const isAdmin = isConfiguredAdminEmail(email);