İçeriğe geç

Giriş denemelerini sınırlama

Güvenlik · Zorluk 5/5 · JavaScript · 42 satırKöken: Kurgu

Görev

Yapay zekâdan istenen

POST /login için hesap başına deneme sınırı yaz. Bir hesapta 15 dakika içinde 5 başarısız denemeden sonra, ilk başarısız denemenin üzerinden 15 dakika geçene kadar o hesaba gelen her deneme, şifre doğru olsa bile 429 almalı. Başarılı giriş sayacı sıfırlar; yanlış şifre 401 alır. E-postada büyük-küçük harf önemsizdir; users.findUser da harfe bakmadan arar. Servis tek bir Node.js sürecinde çalışır; eski kayıtları başka bir iş temizler. Hangi e-postanın kayıtlı olduğunu gizlemek bu görevin kapsamında değil.

Teslim notu

Yapay zekâ kodu teslim ederken şunu yazdı:

“Kaba kuvvet denemelerine karşı hesap başına sınır eklendi: 15 dakikada 5 başarısız denemeden sonra 429 dönüyor. Deneme ilk await'ten önce sayıldığı için aynı anda gelen istekler de sınırı aşamıyor.”

Yapay zekânın yazdığı kod

JavaScript42 satır

Hatalı bulduğun satırları işaretle; her işarete önem seç ve nedenini bir cümleyle yaz.

Satıra tıkla ya da dokun. Klavyede satıra gidip Enter'a bas.

0/5 işaret
Önem nasıl seçilir
  • KritikVeri kaybı, güvenlik açığı ya da para kaybı
  • ÖnemliGörevin istediği bir durumda kullanıcı yanlış sonuç alır
  • KüçükGörevin dışında kalan nadir bir uç durum ya da okunurluk

Test konusunda önem, testin yakalamadığı hatalı uygulamanın etkisine göre belirlenir.

Gerekçe puanlanmaz; sonuçta örnek cevapla karşılaştırırsın.

const MAX_FAILED_ATTEMPTS = 5;
const WINDOW_MS = 15 * 60 * 1000;
3
/**
 * @typedef {{ id: string, passwordHash: string }} User
 * @typedef {{ count: number, since: number }} Attempts
 */
8
/**
 * POST /login with a limit on failed attempts per account.
 *
 * @param {{ findUser(email: string): Promise<User | null> }} users
 *   Finds a user by email, ignoring letter case.
 * @param {(password: string, hash: string) => Promise<boolean>} verify
 * @param {Map<string, Attempts>} attempts Shared by all requests.
 */
export function createLogin(users, verify, attempts) {
  /**
   * @param {string} email
   * @param {string} password
   * @param {number} now Milliseconds since the epoch.
   */
  return async function login(email, password, now) {
    const key = email.trim();
    let entry = attempts.get(key);
    if (entry === undefined || now - entry.since >= WINDOW_MS) {
      entry = { count: 0, since: now };
      attempts.set(key, entry);
    }
    entry.count += 1;
31
    const user = await users.findUser(key);
    if (user !== null && (await verify(password, user.passwordHash))) {
      attempts.delete(key);
      return { status: 200, userId: user.id };
    }
    if (entry.count > MAX_FAILED_ATTEMPTS) {
      return { status: 429 };
    }
    return { status: 401 };
  };
}

Kanıtlayan test

Doğru seçenek, bu kodda başarısız olan, yani hatayı ortaya çıkaran testtir.

Test seçenekleri
Göndermek için en az bir satır işaretle.

Gönderince sayaca yedi bilgi gider; gerekçe metnin cihazında kalır. Veriler