4-bo‘lim

Autentifikatsiya va parollar

Parol siyosati, ikki bosqichli autentifikatsiya, sessiyalar, tokenlar va parolsiz kirish.

🕑 16 daqiqa o‘qish 📄 1 069 so‘z 👁 6 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Uch omil
  2. Parol siyosati
  3. Buzilgan parollarni tekshirish
  4. Parolni saqlash
  5. Kirish urinishlarini cheklash
  6. Ikki bosqichli autentifikatsiya
  7. Zaxira kodlar
  8. WebAuthn
  9. Sessiyalar
  10. JWT tokenlari
  11. Parolni tiklash
  12. Parolsiz kirish
  13. Ijtimoiy kirish (OAuth)
  14. Xavfsizlik hodisalarini kuzatish
  15. Xulosa

Autentifikatsiya - "siz kimsiz?" degan savolga javob. U buzilsa, qolgan barcha himoya ma'nosini yo'qotadi.

Uch omil #

Autentifikatsiyaning uch omili Bilgan narsangiz Something you know • Parol • PIN kod • Maxfiy savol Eng zaif omil Ega narsangiz Something you have • Telefon (TOTP) • Xavfsizlik kaliti • Smart karta Kuchli himoya O'zingiz Something you are • Barmoq izi • Yuz • Ovoz Almashtirib bo'lmaydi Ikki turli omil = ikki bosqichli autentifikatsiya (2FA)
Ikkita parol - bu 2FA emas, ikkalasi ham bir xil omil
Biometriya - parol emas

Barmoq izini almashtirib bo'lmaydi. Agar u oshkor bo'lsa, umrbod oshkor qolaveradi.

Shuning uchun biometriya:

  • Qurilmada lokal saqlanishi kerak (serverga yuborilmasin)
  • Yagona omil sifatida ishlatilmasin
  • Zaxira usuli bo'lsin (PIN kod)

Parol siyosati #

Zamonaviy tavsiyalar (NIST)
Eski tavsiyaYangi tavsiya
8 belgi, murakkab12+ belgi, uzunlik muhimroq
Har 90 kunda almashtirishFaqat buzilish shubhasida
Maxsus belgi majburiyMajburiy emas
Maxfiy savolIshlatmang
Parol maslahatiIshlatmang
Tarqalgan parollar ro'yxatini tekshiring
Nusxa-joylashtirishga ruxsat bering
Majburiy almashtirish - zararli

Har 90 kunda parol almashtirish talab qilinsa, foydalanuvchilar:

Natija
Parol2026!  →  Parol2026!!  →  Parol2026!!!
Yanvar2026  →  Fevral2026   →  Mart2026

Bu parollarni zaiflashtiradi, kuchaytirmaydi.

To'g'ri yondashuv: uzun parol + 2FA + buzilish monitoringi.

PHP
final class ParolTekshiruvchi
{
    private const MIN_UZUNLIK = 12;
    private const MAKS_UZUNLIK = 128;

    public function __construct(
        private TarqalganParollarRoyxati $tarqalganlar,
    ) {}

    /** @return string[] Xatolar ro'yxati */
    public function tekshiring(string $parol, Foydalanuvchi $foydalanuvchi): array
    {
        $xatolar = [];

        $uzunlik = mb_strlen($parol);

        if ($uzunlik < self::MIN_UZUNLIK) {
            $xatolar[] = sprintf('Parol kamida %d belgi bo\'lishi kerak', self::MIN_UZUNLIK);
        }

        if ($uzunlik > self::MAKS_UZUNLIK) {
            $xatolar[] = 'Parol juda uzun';
        }

        if ($this->tarqalganlar->bormi($parol)) {
            $xatolar[] = 'Bu parol juda keng tarqalgan, boshqasini tanlang';
        }

        if ($this->shaxsiyMalumotBormi($parol, $foydalanuvchi)) {
            $xatolar[] = 'Parolda ism yoki email bo\'lmasligi kerak';
        }

        if ($this->ketmaKetlikmi($parol)) {
            $xatolar[] = 'Ketma-ket belgilar ishlatmang (12345, qwerty)';
        }

        return $xatolar;
    }

    private function shaxsiyMalumotBormi(string $parol, Foydalanuvchi $f): bool
    {
        $past = mb_strtolower($parol);

        foreach ([$f->ism, $f->familiya, explode('@', $f->email)[0]] as $qism) {
            if (mb_strlen($qism) >= 3 && str_contains($past, mb_strtolower($qism))) {
                return true;
            }
        }

        return false;
    }

    private function ketmaKetlikmi(string $parol): bool
    {
        $naqshlar = ['12345', 'qwerty', 'abcdef', '11111'];

        foreach ($naqshlar as $naqsh) {
            if (str_contains(mb_strtolower($parol), $naqsh)) {
                return true;
            }
        }

        return false;
    }
}

Buzilgan parollarni tekshirish #

PHP
// Have I Been Pwned - k-anonimlik bilan
final class TarqalganParollarRoyxati
{
    public function bormi(string $parol): bool
    {
        $xesh = strtoupper(sha1($parol));
        $prefiks = substr($xesh, 0, 5);
        $qolgan = substr($xesh, 5);

        // Faqat 5 belgi yuboriladi - to'liq parol emas
        $javob = $this->http->get("https://api.pwnedpasswords.com/range/{$prefiks}");

        foreach (explode("\n", $javob) as $qator) {
            [$suffiks, $soni] = explode(':', trim($qator));

            if (hash_equals($qolgan, $suffiks)) {
                return true;
            }
        }

        return false;
    }
}
K-anonimlik

Xizmatga to'liq parol yuborilmaydi - faqat xeshning birinchi 5 belgisi.

Server shu prefiks bilan boshlanadigan barcha xeshlarni qaytaradi (taxminan 500 ta), tekshiruv esa mahalliy bajariladi.

Shunday qilib xizmat sizning parolingizni bilmaydi.

Parolni saqlash #

PHP
// Ro'yxatdan o'tish
$xesh = password_hash($parol, PASSWORD_ARGON2ID, [
    'memory_cost' => 65536,
    'time_cost'   => 4,
    'threads'     => 2,
]);

// Kirish
if (password_verify($parol, $xesh)) {
    if (password_needs_rehash($xesh, PASSWORD_ARGON2ID, $sozlamalar)) {
        $yangiXesh = password_hash($parol, PASSWORD_ARGON2ID, $sozlamalar);
        $this->repozitoriy->xeshYangilang($id, $yangiXesh);
    }
}
password_needs_rehash - avtomatik yangilash

Vaqt o'tishi bilan hisoblash quvvati oshadi va eski sozlamalar zaiflashadi.

Bu funksiya foydalanuvchi keyingi kirishida xeshni jimgina yangilaydi - hech kim parolini almashtirishi shart emas.

Kirish urinishlarini cheklash #

PHP
final class KirishNazorati
{
    private const IP_CHEGARA = 20;
    private const HISOB_CHEGARA = 5;
    private const OYNA = 900;   // 15 daqiqa

    public function __construct(private KeshInterfeysi $kesh) {}

    public function ruxsatBormi(string $ip, string $login): bool
    {
        $ipUrinish = (int) $this->kesh->oling("kirish:ip:{$ip}");
        $hisobUrinish = (int) $this->kesh->oling('kirish:hisob:' . sha1($login));

        return $ipUrinish < self::IP_CHEGARA
            && $hisobUrinish < self::HISOB_CHEGARA;
    }

    public function muvaffaqiyatsizYozing(string $ip, string $login): void
    {
        $this->kesh->oshiring("kirish:ip:{$ip}", self::OYNA);
        $this->kesh->oshiring('kirish:hisob:' . sha1($login), self::OYNA);
    }

    public function tozalang(string $ip, string $login): void
    {
        $this->kesh->ochiring("kirish:ip:{$ip}");
        $this->kesh->ochiring('kirish:hisob:' . sha1($login));
    }

    public function kutishVaqti(string $login): int
    {
        return $this->kesh->qolganVaqt('kirish:hisob:' . sha1($login)) ?? 0;
    }
}
Faqat IP bo'yicha cheklash yetarli emas
Faqat IPFaqat hisob
Bir ofisdan hamma bloklanadiHujumchi ko'p hisobni sinaydi
Botnet turli IP dan hujum qiladiBitta hisobga hujum to'sildi

Ikkalasini birga ishlating.

Shuningdek "parol purkash" hujumini hisobga oling: hujumchi bitta mashhur parolni minglab hisobga sinaydi. Bunda har bir hisobga faqat 1-2 urinish to'g'ri keladi va hisob chegarasi ishlamaydi.

Yechim: umumiy muvaffaqiyatsiz urinishlar sonini ham kuzating.

PHP
// Progressiv kechikish
$kechikish = min(2 ** $urinishlar, 300);   // 2, 4, 8, 16 ... 300 soniya

Ikki bosqichli autentifikatsiya #

2FA usullari - xavfsizlik darajasi bo'yicha 1. Xavfsizlik kaliti FIDO2, WebAuthn, YubiKey - fishingga chidamli Eng yaxshi 2. Autentifikator ilovasi TOTP (Google Authenticator, Authy) - internet kerak emas Yaxshi 3. Push xabarnoma Qulay, lekin "charchatish hujumi" xavfi bor O'rtacha 4. SMS kod SIM almashtirish hujumiga ochiq, lekin hech nimadan yaxshiroq Zaif
Har qanday 2FA - 2FA yo'qligidan ancha yaxshi
PHP
// TOTP - vaqtga asoslangan bir martalik parol
final class TotpXizmati
{
    private const OYNA = 1;   // oldingi va keyingi 30 soniya

    public function sirYarating(): string
    {
        return Base32::kodlang(random_bytes(20));
    }

    public function qrHavolasi(string $sir, string $email, string $ilova): string
    {
        return sprintf(
            'otpauth://totp/%s:%s?secret=%s&issuer=%s&algorithm=SHA1&digits=6&period=30',
            rawurlencode($ilova),
            rawurlencode($email),
            $sir,
            rawurlencode($ilova),
        );
    }

    public function tekshiring(string $sir, string $kod): bool
    {
        $joriyVaqt = (int) floor(time() / 30);

        for ($i = -self::OYNA; $i <= self::OYNA; $i++) {
            if (hash_equals($this->kodYarating($sir, $joriyVaqt + $i), $kod)) {
                return true;
            }
        }

        return false;
    }

    private function kodYarating(string $sir, int $vaqt): string
    {
        $kalit = Base32::ochiring($sir);
        $malumot = pack('N*', 0, $vaqt);

        $xesh = hash_hmac('sha1', $malumot, $kalit, true);
        $ofset = ord($xesh[19]) & 0xf;

        $son = (
            ((ord($xesh[$ofset]) & 0x7f) << 24) |
            ((ord($xesh[$ofset + 1]) & 0xff) << 16) |
            ((ord($xesh[$ofset + 2]) & 0xff) << 8) |
            (ord($xesh[$ofset + 3]) & 0xff)
        ) % 1000000;

        return str_pad((string) $son, 6, '0', STR_PAD_LEFT);
    }
}
Bir martalik kodni qayta ishlatishga yo'l qo'ymang
PHP
// Ishlatilgan kodni belgilang
$kalit = "totp:ishlatilgan:{$foydalanuvchiId}:{$kod}";

if ($this->kesh->bormi($kalit)) {
    throw new KodAllaqachonIshlatilgan();
}

$this->kesh->saqlang($kalit, true, 90);

Aks holda hujumchi kodni ushlab qolib, 30 soniya ichida qayta ishlatishi mumkin.

Zaxira kodlar #

PHP
final class ZaxiraKodlar
{
    private const SONI = 10;

    /** @return string[] */
    public function yarating(int $foydalanuvchiId): array
    {
        $kodlar = [];
        $xeshlar = [];

        for ($i = 0; $i < self::SONI; $i++) {
            $kod = sprintf(
                '%s-%s',
                bin2hex(random_bytes(3)),
                bin2hex(random_bytes(3)),
            );

            $kodlar[] = $kod;
            $xeshlar[] = password_hash($kod, PASSWORD_DEFAULT);
        }

        $this->repozitoriy->saqlang($foydalanuvchiId, $xeshlar);

        // Kodlar faqat bir marta ko'rsatiladi
        return $kodlar;
    }

    public function ishlating(int $foydalanuvchiId, string $kod): bool
    {
        foreach ($this->repozitoriy->oling($foydalanuvchiId) as $id => $xesh) {
            if (password_verify($kod, $xesh)) {
                $this->repozitoriy->ochiring($id);   // bir martalik
                return true;
            }
        }

        return false;
    }
}
Zaxira kodlarsiz 2FA - xavf

Foydalanuvchi telefonini yo'qotsa, hisobiga kira olmaydi.

Qo'llab-quvvatlash orqali tiklash esa ijtimoiy muhandislik uchun eshik ochadi.

Zaxira kodlar - eng xavfsiz yechim. Ular:

  • Faqat bir marta ko'rsatiladi
  • Xeshlangan holda saqlanadi
  • Har biri bir martalik
  • Tugab qolsa, yangisini yaratish mumkin

WebAuthn #

JavaScript
// Ro'yxatdan o'tkazish
const kalit = await navigator.credentials.create({
    publicKey: {
        challenge: yangiChaqiruv,
        rp: { name: "Dokon", id: "dokon.uz" },
        user: {
            id: foydalanuvchiId,
            name: "[email protected]",
            displayName: "Husanboy Qodirov",
        },
        pubKeyCredParams: [
            { alg: -7,   type: "public-key" },   // ES256
            { alg: -257, type: "public-key" },   // RS256
        ],
        authenticatorSelection: {
            userVerification: "required",
            residentKey: "preferred",
        },
        timeout: 60000,
        attestation: "none",
    },
});
WebAuthn nima uchun fishingga chidamli?

Kalit domenga bog'langan.

Foydalanuvchi dokon-uz.support soxta saytiga kirsa, kalit umuman ishlamaydi - u faqat dokon.uz uchun ishlaydi.

Bu TOTP dan katta afzallik: TOTP kodini foydalanuvchi soxta saytga kiritishi mumkin.

Sessiyalar #

PHP
// Xavfsiz sessiya sozlamalari
session_set_cookie_params([
    'lifetime' => 0,           // brauzer yopilganda tugaydi
    'path'     => '/',
    'domain'   => '',
    'secure'   => true,        // faqat HTTPS
    'httponly' => true,        // JavaScript o'qiy olmaydi
    'samesite' => 'Lax',       // CSRF himoyasi
]);

ini_set('session.use_strict_mode', '1');
ini_set('session.use_only_cookies', '1');
ini_set('session.cookie_httponly', '1');
ini_set('session.gc_maxlifetime', '1800');

session_start();
PHP
// Kirishdan keyin sessiya identifikatorini yangilash
session_regenerate_id(true);
Sessiya fiksatsiyasi

Hujumchi foydalanuvchiga ma'lum sessiya identifikatori bilan havola yuboradi. Foydalanuvchi kirgach, hujumchi shu identifikator bilan uning hisobiga kiradi.

Himoya: kirishdan keyin session_regenerate_id(true).

use_strict_mode = 1 esa serverga noma'lum identifikatorni qabul qilmaslikni buyuradi.

PHP
final class SessiyaBoshqaruvchi
{
    private const FAOLSIZLIK_MUDDATI = 1800;    // 30 daqiqa
    private const MUTLAQ_MUDDAT = 43200;        // 12 soat

    public function tekshiring(): void
    {
        if (!isset($_SESSION['foydalanuvchi_id'])) {
            throw new SessiyaYoq();
        }

        if (time() - $_SESSION['oxirgi_faollik'] > self::FAOLSIZLIK_MUDDATI) {
            $this->tugating();
            throw new SessiyaMuddatiTugadi();
        }

        if (time() - $_SESSION['boshlangan'] > self::MUTLAQ_MUDDAT) {
            $this->tugating();
            throw new SessiyaMuddatiTugadi();
        }

        // Sessiyani o'g'irlashni qiyinlashtirish
        if ($_SESSION['agent_xeshi'] !== $this->agentXeshi()) {
            $this->tugating();
            throw new ShubhaliSessiya();
        }

        $_SESSION['oxirgi_faollik'] = time();
    }

    private function agentXeshi(): string
    {
        return hash('sha256', ($_SERVER['HTTP_USER_AGENT'] ?? '') . $this->sir);
    }

    public function tugating(): void
    {
        $_SESSION = [];

        if (ini_get('session.use_cookies')) {
            $p = session_get_cookie_params();
            setcookie(session_name(), '', time() - 42000,
                $p['path'], $p['domain'], $p['secure'], $p['httponly']);
        }

        session_destroy();
    }
}
IP manzilni sessiyaga bog'lamang

Mobil foydalanuvchilarda IP tez-tez o'zgaradi (uyali tarmoq, Wi-Fi ga o'tish).

Natijada foydalanuvchi doimiy tizimdan chiqib ketadi.

User-Agent esa barqarorroq - lekin u ham 100% ishonchli emas.

JWT tokenlari #

PHP
// Kirish tokeni - qisqa muddatli
$kirishToken = JWT::yarating([
    'sub' => (string) $foydalanuvchi->id,
    'rol' => $foydalanuvchi->rol->value,
    'iat' => time(),
    'exp' => time() + 900,           // 15 daqiqa
    'jti' => bin2hex(random_bytes(16)),
], $sir);

// Yangilash tokeni - uzoq muddatli, bazada saqlanadi
$yangilashToken = bin2hex(random_bytes(32));
$this->repozitoriy->saqlang(
    $foydalanuvchi->id,
    hash('sha256', $yangilashToken),
    muddat: '+30 days',
);
Ikki tokenli strategiya Kirish tokeni (JWT) • Muddat: 15 daqiqa • Har so'rovda yuboriladi • Bazaga murojaat kerak emas • Bekor qilib bo'lmaydi Yangilash tokeni • Muddat: 30 kun • Faqat yangilashda ishlatiladi • Bazada xeshlangan holda • Bekor qilish mumkin Nima uchun ikkita? JWT ni bekor qilib bo'lmaydi - qisqa muddat zararni cheklaydi
Chiqishda yangilash tokeni bazadan o'chiriladi
JWT xatolari
PHP
// 1. Algoritmni tekshirmaslik
$malumot = JWT::decode($token, $sir);   // "alg": "none" hujumi

// TO'G'RI
$malumot = JWT::decode($token, $sir, ['HS256']);
PHP
// 2. Muddatni tekshirmaslik
if (!isset($malumot['exp']) || $malumot['exp'] < time()) {
    throw new TokenMuddatiTugadi();
}
PHP
// 3. Maxfiy ma'lumotni JWT ga qo'yish
// JWT SHIFRLANMAGAN - u faqat imzolangan!
// base64 dekodlash bilan hamma o'qiy oladi
$token = JWT::yarating(['parol' => $parol]);   // XATO

Parolni tiklash #

PHP
final class ParolTiklashXizmati
{
    private const MUDDAT = 3600;   // 1 soat

    public function soraing(string $email): void
    {
        $foydalanuvchi = $this->repozitoriy->emailBoyicha($email);

        // Foydalanuvchi topilmasa ham bir xil javob
        if ($foydalanuvchi !== null) {
            $token = bin2hex(random_bytes(32));

            $this->tokenlar->saqlang(
                $foydalanuvchi->id,
                hash('sha256', $token),
                time() + self::MUDDAT,
            );

            $this->pochta->yuboring($email, new ParolTiklashXati($token));
        }

        // Har doim bir xil xabar
        $this->javob = 'Agar bu email ro\'yxatdan o\'tgan bo\'lsa, xat yuborildi';
    }

    public function tiklang(string $token, string $yangiParol): void
    {
        $yozuv = $this->tokenlar->xeshBoyicha(hash('sha256', $token))
            ?? throw new NotogriToken();

        if ($yozuv->muddat < time()) {
            throw new TokenMuddatiTugadi();
        }

        $this->repozitoriy->parolYangilang(
            $yozuv->foydalanuvchiId,
            password_hash($yangiParol, PASSWORD_ARGON2ID),
        );

        $this->tokenlar->ochiring($yozuv->id);

        // Barcha sessiyalarni tugatish
        $this->sessiyalar->hammasiniTugating($yozuv->foydalanuvchiId);

        $this->pochta->yuboring(
            $yozuv->email,
            new ParolOzgartirildi($this->sorov->ip(), new DateTimeImmutable()),
        );
    }
}
Parol o'zgarganda xabar bering

Foydalanuvchi bu o'zgarishni qilmagan bo'lsa, u darhol bilishi kerak.

Xatda: qachon, qaysi IP dan, qaysi qurilmadan. Va "bu siz emasmisiz?" degan havola.

Barcha sessiyalarni tugating

Parol o'zgarganda mavjud sessiyalar bekor qilinishi shart.

Aks holda hisobni o'g'irlagan hujumchi parol almashtirilgandan keyin ham kirishda davom etadi.

Parolsiz kirish #

UsulQanday ishlaydi
Sehrli havolaEmailga bir martalik havola
WebAuthnQurilma kaliti bilan
OAuthGoogle, GitHub orqali
SMS kodTelefon raqami bilan
PHP
final class SehrliHavolaXizmati
{
    private const MUDDAT = 900;   // 15 daqiqa

    public function yuboring(string $email): void
    {
        $token = bin2hex(random_bytes(32));

        $this->tokenlar->saqlang(
            $email,
            hash('sha256', $token),
            time() + self::MUDDAT,
        );

        $havola = sprintf('%s/kirish/%s', $this->asosiyUrl, $token);
        $this->pochta->yuboring($email, new SehrliHavolaXati($havola));
    }
}
Sehrli havola - email xavfsizligiga bog'liq

Agar foydalanuvchining emaili buzilgan bo'lsa, hujumchi barcha sehrli havolalar orqali kira oladi.

Shuning uchun:

  • Havola qisqa muddatli bo'lsin (15 daqiqa)
  • Bir martalik bo'lsin
  • Muhim amallar uchun qo'shimcha tasdiq talab qilinsin

Ijtimoiy kirish (OAuth) #

PHP
// Google orqali kirish
$holat = bin2hex(random_bytes(16));
$_SESSION['oauth_holat'] = $holat;

$url = 'https://accounts.google.com/o/oauth2/v2/auth?' . http_build_query([
    'client_id'     => $this->mijozId,
    'redirect_uri'  => $this->qaytishUrl,
    'response_type' => 'code',
    'scope'         => 'openid email profile',
    'state'         => $holat,
    'nonce'         => bin2hex(random_bytes(16)),
]);
PHP
// Qaytish
public function qaytish(Sorov $sorov): Javob
{
    // CSRF himoyasi
    if (!hash_equals($_SESSION['oauth_holat'] ?? '', $sorov->get('state'))) {
        throw new NotogriHolat();
    }

    unset($_SESSION['oauth_holat']);

    $token = $this->kodniTokengaAlmashtiring($sorov->get('code'));
    $malumot = $this->foydalanuvchiMalumotiniOling($token);

    // Email tasdiqlanganini tekshirish
    if (!($malumot['email_verified'] ?? false)) {
        throw new EmailTasdiqlanmagan();
    }

    // ...
}
state parametri majburiy

Usiz hujumchi o'z hisobini qurbonning hisobiga bog'lashi mumkin (CSRF hujumi).

state - tasodifiy qiymat, sessiyada saqlanadi va qaytishda tekshiriladi.

Xavfsizlik hodisalarini kuzatish #

PHP
// Shubhali faollik belgilari
$this->xavfsizlik->tekshiring($foydalanuvchi, [
    'yangi_qurilma'      => !$this->qurilmalar->tanishmi($barmoqIzi),
    'yangi_joylashuv'    => $this->geoIp->yangiMamlakatmi($ip, $foydalanuvchi),
    'gayritabiiy_vaqt'   => $this->vaqtTahlili->gayritabiimi($foydalanuvchi),
    'tez_joylashuv_ozgarishi' => $this->geoIp->imkonsizSayohatmi($foydalanuvchi, $ip),
]);
"Imkonsiz sayohat"

Foydalanuvchi 10 daqiqa oldin Toshkentdan kirgan, hozir Berlindan kiryapti.

Jismonan imkonsiz - demak hisob buzilgan yoki VPN ishlatilyapti.

Bunday holatda qo'shimcha tasdiq so'ralishi kerak.

Amaliy topshiriq
  1. ParolTekshiruvchi klassini yozing va sinang.
  2. Have I Been Pwned API bilan tarqalgan parol tekshiruvini qo'shing.
  3. password_hash va password_verify bilan ro'yxat va kirish yozing.
  4. Kirish urinishlarini cheklovchi tizim yozing (IP + hisob).
  5. Progressiv kechikishni qo'shing.
  6. TOTP xizmatini amalga oshiring va telefon ilovasi bilan sinang.
  7. Zaxira kodlar tizimini yozing.
  8. Xavfsiz sessiya sozlamalarini qo'llang.
  9. Parolni tiklash oqimini yozing - barcha xavfsizlik talablarini hisobga oling.
  10. Sessiyani o'g'irlashga urinib ko'ring va himoya ishlashini tekshiring.

Xulosa #

  • Uch omil: bilgan, ega bo'lgan, o'zingiz bo'lgan narsa.
  • Ikkita parol - 2FA emas, ikkalasi ham bir xil omil.
  • Zamonaviy parol siyosati: uzunlik muhimroq, majburiy almashtirish zararli.
  • Tarqalgan parollar ro'yxatini tekshiring (k-anonimlik bilan).
  • Argon2 yoki bcrypt ishlating, password_needs_rehash bilan avtomatik yangilang.
  • Kirish cheklovi IP va hisob bo'yicha birga bo'lsin.
  • WebAuthn fishingga chidamli - kalit domenga bog'langan.
  • Zaxira kodlarsiz 2FA foydalanuvchini hisobidan ayirishi mumkin.
  • Kirishdan keyin session_regenerate_id(true).
  • JWT shifrlanmagan - maxfiy ma'lumot qo'ymang; algoritmni albatta tekshiring.
  • Parol o'zgarganda barcha sessiyalarni tugating va xabar bering.
  • OAuth da state parametri majburiy.

Keyingi bo'limda avtorizatsiya va kirish nazoratini ko'ramiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.