20-bo‘lim

Amaliy loyiha - xavfsizlik auditi

Darslikda o'rganilgan bilimlarni birlashtirib, veb ilovaning to'liq xavfsizlik auditini o'tkazamiz va hisobot yozamiz.

🕑 22 daqiqa o‘qish 📄 955 so‘z 👁 7 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Loyiha shartlari
  2. Audit rejasi
  3. 1-bosqich: Qamrov
  4. 2-bosqich: Infratuzilma
  5. 3-bosqich: Ilova
  6. Qo'lda tekshirish: autentifikatsiya
  7. Qo'lda tekshirish: avtorizatsiya
  8. Qo'lda tekshirish: biznes mantiq
  9. 4-bosqich: Kod tahlili
  10. 5-bosqich: Jarayonlar
  11. 6-bosqich: Hisobot
  12. 7-bosqich: Qayta tekshirish
  13. Doimiy audit
  14. Darslik yakuni
  15. Xulosa

Endi hamma bilimni birlashtiramiz. Biz o'zimizning dokon.uz onlayn do'konini to'liq audit qilamiz - infratuzilmadan kodgacha.

Loyiha shartlari #

Faqat o'z tizimingizda

Bu loyihani faqat o'zingizga tegishli yoki yozma ruxsat berilgan tizimda bajaring.

Amaliyot uchun xavfsiz muhitlar:

  • Mahalliy virtual mashina (VirtualBox + Ubuntu)
  • Docker konteynerlari
  • OWASP Juice Shop, DVWA (ataylab zaif ilovalar)
  • TryHackMe, HackTheBox, PortSwigger Web Security Academy

Boshqaning tizimini ruxsatsiz tekshirish - jinoyat.

Terminal
# Sinov muhitini tayyorlash
mkdir -p ~/audit-laboratoriya && cd ~/audit-laboratoriya

# Zaif ilova - o'rganish uchun
docker run -d --name juice-shop -p 3000:3000 bkimminich/juice-shop

# O'z ilovangiz nusxasi
git clone https://github.com/foydalanuvchi/dokon.git
cd dokon
docker compose up -d

Audit rejasi #

Audit bosqichlari 1. Qamrov Ruxsat, chegara Aktivlar ro'yxati 2. Infratuzilma Portlar, TLS Sarlavhalar 3. Ilova OWASP Top 10 Mantiq xatolari 4. Kod SAST, sirlar Bog'liqliklar 5. Jarayon Zaxira, jurnal Siyosatlar 6. Hisobot va ustuvorlik Topilmalar, jiddiylik, tavsiya, muddat 7. Tuzatish va qayta tekshirish Har bir tuzatish uchun test yoziladi
Audit - bir martalik voqea emas, muntazam jarayon

1-bosqich: Qamrov #

MARKDOWN
# Audit qamrovi

**Tashkilot:** Dokon MChJ
**Sana:** 2026-09-15 dan 2026-09-25 gacha
**Auditor:** Ichki xavfsizlik jamoasi

## Qamrovda
| Aktiv | Manzil | Turi |
|-------|--------|------|
| Asosiy sayt | dokon.uz | Veb ilova |
| API | api.dokon.uz | REST API |
| Admin panel | admin.dokon.uz | Veb ilova |
| Statik fayllar | static.dokon.uz | CDN |
| Ma'lumotlar bazasi | 10.0.2.10 | MariaDB |
| Ilova serveri | 10.0.2.20 | Ubuntu 22.04 |
| Kod ombori | github.com/dokon/dokon | Git |

## Qamrovdan tashqarida
- To'lov provayderi tizimi (uchinchi tomon)
- Ofis tarmog'i
- Xodimlar noutbuklari

## Cheklovlar
- DoS testlari o'tkazilmaydi
- Ijtimoiy muhandislik o'tkazilmaydi
- Ishlab chiqarish bazasiga yozish operatsiyalari yo'q
- Test soatlari: 22:00 - 06:00

## Aloqa
- Auditor: @husanboy, +998 90 xxx
- Favqulodda to'xtatish: @aziz, +998 91 xxx
Qamrovni yozma tasdiqlang

Og'zaki "ha, tekshirib ko'r" yetarli emas.

Yozma hujjatda bo'lishi kerak: nima, qachon, kim, qaysi usullar va kim ruxsat berdi.

Bu sizni ham, tashkilotni ham himoya qiladi.

2-bosqich: Infratuzilma #

Terminal
#!/bin/bash
# infratuzilma-audit.sh
set -uo pipefail

MAQSAD="dokon.uz"
NATIJA="natijalar/infratuzilma"
mkdir -p "$NATIJA"

echo "===> 1. DNS yozuvlari"
{
    dig +short "$MAQSAD" A
    dig +short "$MAQSAD" AAAA
    dig +short "$MAQSAD" MX
    dig +short "$MAQSAD" TXT
    dig +short "$MAQSAD" CAA
    dig +short "_dmarc.$MAQSAD" TXT
} > "$NATIJA/dns.txt"

echo "===> 2. Ochiq portlar"
nmap -Pn -sV --top-ports 1000 "$MAQSAD" -oN "$NATIJA/portlar.txt"

echo "===> 3. TLS sozlamalari"
testssl.sh --quiet --color 0 "$MAQSAD" > "$NATIJA/tls.txt" 2>&1

echo "===> 4. Xavfsizlik sarlavhalari"
curl -sSI "https://$MAQSAD" > "$NATIJA/sarlavhalar.txt"

echo "===> 5. Subdomenlar"
curl -s "https://crt.sh/?q=%25.$MAQSAD&output=json" \
    | python3 -c "import sys,json;[print(x['name_value']) for x in json.load(sys.stdin)]" \
    | tr '\n' '\n' | sort -u > "$NATIJA/subdomenlar.txt"

echo "===> 6. Ochiq bo'lmasligi kerak bo'lgan yo'llar"
for yol in .git/config .env composer.json .DS_Store backup.sql \
           phpinfo.php server-status .svn/entries web.config; do
    KOD=$(curl -s -o /dev/null -w "%{http_code}" "https://$MAQSAD/$yol")
    printf "%-24s %s\n" "$yol" "$KOD"
done | tee "$NATIJA/ochiq-yollar.txt"

echo "===> Tayyor. Natijalar: $NATIJA"
Natija
===> 6. Ochiq bo'lmasligi kerak bo'lgan yo'llar
.git/config              404
.env                     404
composer.json            200      <-- MUAMMO
.DS_Store                404
backup.sql               404
phpinfo.php              404
server-status            403
.svn/entries             404
web.config               404
Terminal
# Sarlavhalarni tekshirish
curl -sSI https://dokon.uz | grep -iE \
    'strict-transport|content-security|x-frame|x-content-type|referrer-policy|permissions-policy|server|x-powered'
Natija
server: nginx/1.18.0                          <-- versiya oshkor
x-powered-by: PHP/8.2.4                       <-- versiya oshkor
strict-transport-security: max-age=31536000
x-content-type-options: nosniff
                                              <-- CSP yo'q
                                              <-- X-Frame-Options yo'q
NGINX
# Tuzatish
server_tokens off;

add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'self'" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

# Yashirin fayllarni to'sish
location ~ /\.(?!well-known) {
    deny all;
    return 404;
}

location ~ ^/(composer\.(json|lock)|package\.json|\.env) {
    deny all;
    return 404;
}
PHP
// PHP versiyasini yashirish - php.ini
// expose_php = Off

3-bosqich: Ilova #

Terminal
# Yo'llarni aniqlash
gobuster dir \
    -u https://dokon.uz \
    -w /usr/share/wordlists/dirb/common.txt \
    -x php,html,json,bak,old \
    -t 20 \
    --exclude-length 0 \
    -o natijalar/yollar.txt
Terminal
# ZAP avtomatik skan (o'z tizimingizda!)
docker run --rm -v "$(pwd)/natijalar:/zap/wrk" \
    -t ghcr.io/zaproxy/zaproxy:stable \
    zap-baseline.py \
    -t https://sinov.dokon.uz \
    -r zap-hisobot.html \
    -w zap-ogohlantirish.md
Avtomatik skaner yetarli emas

Skanerlar quyidagilarni topa oladi:

  • Ma'lum zaifliklar (CVE)
  • Yo'q sarlavhalar
  • Oddiy inyeksiya nuqtalari

Ular quyidagilarni topa olmaydi:

  • Biznes mantiq xatolari
  • IDOR (kontekstni bilmaydi)
  • Huquqlarni oshirish yo'llari
  • Narx manipulyatsiyasi

Shuning uchun qo'lda tekshirish majburiy.

Qo'lda tekshirish: autentifikatsiya #

Terminal
# 1. Foydalanuvchi sanash - javob bir xilmi?
for pochta in [email protected] [email protected]; do
    echo "--- $pochta"
    curl -s -w "\nvaqt: %{time_total}s\n" \
        -X POST https://dokon.uz/parolni-tiklash \
        -d "pochta=$pochta"
done
Natija
--- [email protected]
{"xabar":"Havola yuborildi"}
vaqt: 0.412s

--- [email protected]
{"xabar":"Bunday foydalanuvchi topilmadi"}      <-- MUAMMO
vaqt: 0.089s                                     <-- vaqt farqi ham
PHP
// Tuzatish: bir xil javob va bir xil vaqt
public function parolniTiklang(string $pochta): Javob
{
    $foydalanuvchi = $this->foydalanuvchilar->pochtaBoyicha($pochta);

    if ($foydalanuvchi !== null) {
        $this->tiklashXatiniYuboring($foydalanuvchi);
    } else {
        // Vaqt farqini yo'q qilamiz
        $this->soxtaIshBajaring();
    }

    // Har doim bir xil javob
    return $this->javob->ok([
        'xabar' => 'Agar bunday hisob mavjud bo\'lsa, havola yuborildi',
    ]);
}
Terminal
# 2. Tezlik cheklovi bormi?
for i in $(seq 1 15); do
    KOD=$(curl -s -o /dev/null -w "%{http_code}" \
        -X POST https://dokon.uz/kirish \
        -d "[email protected]&parol=notogri$i")
    echo "$i: $KOD"
done
Natija
1: 401
2: 401
...
14: 401
15: 401                                          <-- MUAMMO: cheklov yo'q
PHP
// Tuzatish: ikki qatlamli cheklov
final class KirishCheklovi
{
    public function tekshiring(string $pochta, string $ip): void
    {
        // Hisob bo'yicha - hisobni himoya qiladi
        $hisobKaliti = 'kirish:hisob:' . hash('sha256', strtolower($pochta));

        if ($this->kesh->soni($hisobKaliti) >= 5) {
            $this->jurnal->ogohlantirish('kirish.hisob_bloklandi', [
                'pochta' => $pochta, 'ip' => $ip,
            ]);

            throw new JudaKopUrinish(900);
        }

        // IP bo'yicha - parol purkashdan himoya qiladi
        $ipKaliti = 'kirish:ip:' . $ip;

        if ($this->kesh->soni($ipKaliti) >= 30) {
            throw new JudaKopUrinish(3600);
        }
    }

    public function muvaffaqiyatsizlikniYozing(string $pochta, string $ip): void
    {
        $this->kesh->oshiring('kirish:hisob:' . hash('sha256', strtolower($pochta)), 900);
        $this->kesh->oshiring('kirish:ip:' . $ip, 3600);
    }
}
Ikki qatlam nima uchun?

Faqat hisob bo'yicha cheklov: hujumchi 10 000 hisobga bittadan mashhur parolni sinaydi (parol purkash) - hech qaysi hisob bloklanmaydi.

Faqat IP bo'yicha cheklov: botnet 10 000 IP dan hujum qiladi - har bir IP chegaradan past qoladi.

Ikkalasi birga kerak.

Qo'lda tekshirish: avtorizatsiya #

Terminal
# IDOR sinovi - matritsa usuli
# Ikki hisob yaratamiz va bir-birining resurslariga kirishga urinamiz

TOKEN_A="..."   # birinchi mijoz
TOKEN_B="..."   # ikkinchi mijoz

# B ning buyurtmasi
BUYURTMA_B=1042

for endpoint in \
    "GET /api/buyurtma/$BUYURTMA_B" \
    "PUT /api/buyurtma/$BUYURTMA_B" \
    "DELETE /api/buyurtma/$BUYURTMA_B" \
    "GET /api/buyurtma/$BUYURTMA_B/hujjat"
do
    USUL=$(echo "$endpoint" | cut -d' ' -f1)
    YOL=$(echo "$endpoint" | cut -d' ' -f2)

    KOD=$(curl -s -o /dev/null -w "%{http_code}" \
        -X "$USUL" \
        -H "Authorization: Bearer $TOKEN_A" \
        "https://api.dokon.uz$YOL")

    printf "%-6s %-36s %s\n" "$USUL" "$YOL" "$KOD"
done
Natija
GET    /api/buyurtma/1042                   403
PUT    /api/buyurtma/1042                   403
DELETE /api/buyurtma/1042                   403
GET    /api/buyurtma/1042/hujjat            200      <-- MUAMMO
Unutilgan yo'l

Bu juda tipik holat: asosiy endpointlar himoyalangan, lekin qo'shimcha yo'l (hujjat yuklab olish, eksport, chop etish) tekshiruvsiz qolgan.

Shuning uchun matritsa usuli kerak: har bir resurs uchun barcha yo'llarni sinang.

PHP
// Tuzatish: markazlashgan huquq tekshiruvi
abstract class BuyurtmaNazorat extends Nazorat
{
    /**
     * Har bir amal shu metod orqali buyurtmani oladi.
     * Huquqni chetlab o'tishning iloji yo'q.
     */
    protected function buyurtmaniOling(int $id): Buyurtma
    {
        $buyurtma = $this->buyurtmalar->id($id);

        if ($buyurtma === null) {
            throw new TopilmadiXatosi();
        }

        if (!$this->ruxsat->koraOladi($this->joriyFoydalanuvchi(), $buyurtma)) {
            // 404 qaytaramiz - mavjudligini oshkor qilmaslik uchun
            throw new TopilmadiXatosi();
        }

        return $buyurtma;
    }
}
PHP
// Test - har bir yo'l uchun
public function test_barcha_buyurtma_yollari_himoyalangan(): void
{
    $birinchi = $this->mijozYarating();
    $ikkinchi = $this->mijozYarating();
    $buyurtma = $this->buyurtmaYarating($ikkinchi->id);

    $this->kiring($birinchi->pochta);

    $yollar = [
        ['GET',    "/api/buyurtma/{$buyurtma->id}"],
        ['PUT',    "/api/buyurtma/{$buyurtma->id}"],
        ['DELETE', "/api/buyurtma/{$buyurtma->id}"],
        ['GET',    "/api/buyurtma/{$buyurtma->id}/hujjat"],
        ['GET',    "/api/buyurtma/{$buyurtma->id}/tolovlar"],
        ['POST',   "/api/buyurtma/{$buyurtma->id}/bekor"],
    ];

    foreach ($yollar as [$usul, $yol]) {
        $javob = $this->soragan($usul, $yol);

        $this->assertSame(404, $javob->kodi(), "$usul $yol himoyalanmagan");
    }
}

Qo'lda tekshirish: biznes mantiq #

Terminal
# 1. Manfiy miqdor
curl -X POST https://api.dokon.uz/savat \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"mahsulot_id": 10, "miqdor": -5}'
Natija
{"jami": -450000, "holat": "qoshildi"}          <-- MUAMMO
Terminal
# 2. Narxni mijoz yuboradi
curl -X POST https://api.dokon.uz/buyurtma \
    -H "Authorization: Bearer $TOKEN" \
    -d '{"mahsulot_id": 10, "miqdor": 1, "narx": 1}'
Natija
{"buyurtma_id": 1099, "jami": 1}                <-- MUAMMO
Terminal
# 3. Chegirma kodini takroran ishlatish (poyga holati)
for i in $(seq 1 10); do
    curl -s -X POST https://api.dokon.uz/savat/chegirma \
        -H "Authorization: Bearer $TOKEN" \
        -d '{"kod": "YANGI50"}' &
done
wait
Natija
{"chegirma": 50, "jami": 225000}
{"chegirma": 50, "jami": 112500}
{"chegirma": 50, "jami": 56250}                 <-- MUAMMO: takror qo'llandi
PHP
// Tuzatish
final class SavatXizmati
{
    public function qoshing(int $mahsulotId, int $miqdor): void
    {
        // 1. Miqdor chegarasi
        if ($miqdor < 1 || $miqdor > 100) {
            throw new NotogriMiqdor('Miqdor 1 va 100 orasida bo\'lsin');
        }

        // 2. Narx faqat serverdan olinadi
        $mahsulot = $this->mahsulotlar->id($mahsulotId);

        if ($mahsulot === null || !$mahsulot->faol) {
            throw new TopilmadiXatosi();
        }

        // 3. Ombordagi qoldiq tekshiriladi
        if ($mahsulot->qoldiq < $miqdor) {
            throw new YetarliEmas("Omborda faqat {$mahsulot->qoldiq} dona");
        }

        $this->savat->qoshing($mahsulotId, $miqdor, $mahsulot->narx);
    }

    public function chegirmaQollang(string $kod): void
    {
        // Poyga holatidan himoya - bazada blok
        $this->baza->tranzaksiya(function () use ($kod) {
            $chegirma = $this->baza->qator(
                'SELECT * FROM chegirmalar WHERE kod = :kod FOR UPDATE',
                ['kod' => $kod]
            );

            if ($chegirma === null || $chegirma['ishlatilgan'] >= $chegirma['limit']) {
                throw new NotogriChegirma('Kod yaroqsiz');
            }

            // Bitta savatga faqat bitta chegirma
            if ($this->savat->chegirmaBormi()) {
                throw new NotogriChegirma('Chegirma allaqachon qo\'llangan');
            }

            $this->baza->bajaring(
                'UPDATE chegirmalar SET ishlatilgan = ishlatilgan + 1 WHERE id = :id',
                ['id' => $chegirma['id']]
            );

            $this->savat->chegirmaOrnating($chegirma);
        });
    }
}
Narxni hech qachon mijozdan olmang

Mijoz yuboradigan yagona narsa - mahsulot identifikatori va miqdor.

Narx, chegirma, soliq, yetkazib berish narxi - hammasi serverda hisoblanadi.

Bu qoida buzilgan holat - onlayn do'konlardagi eng ko'p uchraydigan va eng qimmat zaiflik.

4-bosqich: Kod tahlili #

Terminal
#!/bin/bash
# kod-audit.sh
set -uo pipefail

mkdir -p natijalar/kod

echo "===> 1. Sirlarni qidirish (butun tarix)"
gitleaks detect --source . --report-path natijalar/kod/sirlar.json --verbose

echo "===> 2. Bog'liqliklar"
composer audit --format=json > natijalar/kod/bogliqliklar.json || true
npm audit --json > natijalar/kod/npm.json 2>/dev/null || true

echo "===> 3. Statik tahlil"
semgrep --config=p/php --config=p/security-audit --config=p/owasp-top-ten \
    --json --output=natijalar/kod/semgrep.json .

echo "===> 4. Xavfli naqshlar"
{
    echo "--- SQL birlashtirish"
    grep -rnE '(query|exec)\s*\(\s*["'"'"'].*\$' --include='*.php' . || echo "yo'q"

    echo "--- Kod bajarish"
    grep -rnE '\b(eval|assert|create_function|preg_replace\s*\(.*/e)' --include='*.php' . || echo "yo'q"

    echo "--- Tashqi buyruq"
    grep -rnE '\b(shell_exec|system|passthru|proc_open|popen)\s*\(' --include='*.php' . || echo "yo'q"

    echo "--- Deserializatsiya"
    grep -rn 'unserialize(' --include='*.php' . || echo "yo'q"

    echo "--- Zaif tasodifiylik"
    grep -rnE '\b(mt_rand|rand|uniqid)\s*\(' --include='*.php' . || echo "yo'q"

    echo "--- Ekranlanmagan chiqish"
    grep -rnE '<\?=\s*\$(_GET|_POST|_REQUEST)' --include='*.php' . || echo "yo'q"

    echo "--- Kodda sir"
    grep -rniE '(parol|password|api_key|secret|token)\s*=\s*["'"'"'][^"'"'"']{8,}' \
        --include='*.php' --exclude-dir=vendor . || echo "yo'q"
} > natijalar/kod/naqshlar.txt

echo "===> 5. Fayl huquqlari"
find . -type f -perm -o+w -not -path './.git/*' > natijalar/kod/yozilishi-mumkin.txt

echo "===> Tayyor"
Natija
===> 4. Xavfli naqshlar
--- SQL birlashtirish
./app/Hisobot/EksportXizmati.php:88:  $qatorlar = $pdo->query("SELECT * FROM buyurtmalar WHERE sana >= '$boshlanish'");

--- Zaif tasodifiylik
./app/Auth/TiklashToken.php:24:  return md5(uniqid(mt_rand(), true));

--- Kodda sir
./config/tolov.php:12:  'kalit' => 'sk_live_4f8a2b9c1d3e5f7a',
PHP
// TiklashToken.php - oldingi (zaif)
public function yarating(): string
{
    return md5(uniqid(mt_rand(), true));
}
Nima uchun bu xavfli?

uniqid() - joriy vaqtga asoslangan, tasodifiy emas. mt_rand() - Mersenne Twister, kriptografik emas; bir necha natijadan keyingi qiymatlarni hisoblash mumkin. md5() - buzilgan xesh funksiyasi.

Natijada tiklash tokenini taxmin qilish mumkin: hujumchi istalgan foydalanuvchi parolini tiklaydi.

PHP
// Tuzatilgan
final class TiklashToken
{
    private const UZUNLIK = 32;
    private const MUDDAT = 1800;   // 30 daqiqa

    public function yarating(int $foydalanuvchiId): string
    {
        // Eski tokenlarni bekor qilamiz
        $this->baza->bajaring(
            'DELETE FROM tiklash_tokenlari WHERE foydalanuvchi_id = :fid',
            ['fid' => $foydalanuvchiId]
        );

        $ochiq = bin2hex(random_bytes(self::UZUNLIK));

        // Bazada faqat xesh saqlanadi
        $this->baza->bajaring(
            'INSERT INTO tiklash_tokenlari (foydalanuvchi_id, token_xesh, eskiradi)
             VALUES (:fid, :xesh, :eskiradi)',
            [
                'fid' => $foydalanuvchiId,
                'xesh' => hash('sha256', $ochiq),
                'eskiradi' => date('Y-m-d H:i:s', time() + self::MUDDAT),
            ]
        );

        return $ochiq;
    }

    public function tekshiring(string $token): ?int
    {
        $qator = $this->baza->qator(
            'SELECT foydalanuvchi_id FROM tiklash_tokenlari
             WHERE token_xesh = :xesh AND eskiradi > NOW()',
            ['xesh' => hash('sha256', $token)]
        );

        return $qator === null ? null : (int) $qator['foydalanuvchi_id'];
    }
}
Terminal
# Kodda topilgan sir - darhol bekor qiling
# 1. To'lov provayderi panelida kalitni bekor qilish
# 2. Yangi kalit yaratish
# 3. Muhit o'zgaruvchisiga ko'chirish
# 4. Git tarixidan tozalash

git filter-repo --path config/tolov.php --invert-paths
# yoki
bfg --replace-text sirlar.txt
Git tarixidan tozalash yetarli emas

Kalit git tarixida bo'lgan bo'lsa, u:

  • Klonlarda qolgan
  • Fork larda qolgan
  • CI keshida qolgan
  • Ehtimol allaqachon skanerlangan

Birinchi qadam har doim: kalitni bekor qilish. Tarixni tozalash - ikkinchi qadam.

5-bosqich: Jarayonlar #

Jarayon auditi
SavolTekshirish usuli
Zaxira ishlaydimi?Tiklash sinovini o'tkazing
Jurnal yig'iladimi?Sinov hodisasini yarating va qidiring
Ogohlantirish keladimi?10 marta noto'g'ri kirish qiling
Ketgan xodim kirishi o'chirilganmi?Hisoblarni HR ro'yxati bilan solishtiring
Yamoqlar o'rnatilganmi?apt list --upgradable
Kim admin?Huquqlar ro'yxatini chiqaring
Terminal
# Faol hisoblar va HR ro'yxatini solishtirish
mysql -N -e "
SELECT pochta FROM dokon.foydalanuvchilar
WHERE rol IN ('admin', 'moderator') AND holat = 'faol'
ORDER BY pochta;" | sort > /tmp/tizim.txt

sort /tmp/hr-xodimlar.txt > /tmp/hr.txt

echo "=== Tizimda bor, HR da yo'q (TEKSHIRING!) ==="
comm -23 /tmp/tizim.txt /tmp/hr.txt

echo "=== HR da bor, tizimda yo'q (normal) ==="
comm -13 /tmp/tizim.txt /tmp/hr.txt
Natija
=== Tizimda bor, HR da yo'q (TEKSHIRING!) ===
[email protected]          <-- 4 oy oldin ketgan
[email protected]                   <-- sinov hisobi, o'chirilmagan
[email protected]                  <-- xizmat hisobi (normal, hujjatlansin)
Terminal
# Oxirgi 90 kun ichida kirmagan hisoblar
mysql -e "
SELECT pochta, rol, oxirgi_kirish,
       DATEDIFF(NOW(), oxirgi_kirish) AS kun
FROM dokon.foydalanuvchilar
WHERE holat = 'faol'
  AND (oxirgi_kirish < DATE_SUB(NOW(), INTERVAL 90 DAY) OR oxirgi_kirish IS NULL)
ORDER BY oxirgi_kirish;"

6-bosqich: Hisobot #

MARKDOWN
# Xavfsizlik auditi hisoboti - dokon.uz

**Sana:** 2026-09-25
**Auditor:** Ichki xavfsizlik jamoasi
**Qamrov:** Veb ilova, API, infratuzilma, kod, jarayonlar

---

## Rahbariyat uchun xulosa

Auditda **14 ta** topilma aniqlandi: 2 ta kritik, 4 ta yuqori,
5 ta o'rta, 3 ta past.

**Eng jiddiy xatar:** parolni tiklash tokeni taxmin qilinadigan
algoritm bilan yaratiladi. Bu hujumchiga istalgan hisobni, shu
jumladan administrator hisobini egallash imkonini beradi.

**Ikkinchi kritik topilma:** to'lov provayderi kaliti kod omborida
ochiq saqlanadi. Kalit bekor qilindi va almashtirildi (24-sentabr).

Kritik topilmalar **7 kun** ichida, yuqori darajadagilar **30 kun**
ichida tuzatilishi tavsiya etiladi.

---

## Topilmalar

| ID | Topilma | Jiddiylik | Holat |
|----|---------|:---------:|-------|
| T-01 | Taxmin qilinadigan parol tiklash tokeni | Kritik | Ochiq |
| T-02 | To'lov kaliti kod omborida | Kritik | Tuzatildi |
| T-03 | Buyurtma hujjatida IDOR | Yuqori | Ochiq |
| T-04 | Narx mijoz so'rovidan olinadi | Yuqori | Ochiq |
| T-05 | Kirishda tezlik cheklovi yo'q | Yuqori | Ochiq |
| T-06 | Chegirma kodida poyga holati | Yuqori | Ochiq |
| T-07 | SQL birlashtirish (eksport moduli) | O'rta | Ochiq |
| T-08 | CSP sarlavhasi yo'q | O'rta | Ochiq |
| T-09 | Foydalanuvchi sanash mumkin | O'rta | Ochiq |
| T-10 | Ketgan xodim hisobi faol | O'rta | Ochiq |
| T-11 | composer.json ochiq | O'rta | Ochiq |
| T-12 | Server versiyasi oshkor | Past | Ochiq |
| T-13 | Manfiy miqdor qabul qilinadi | Past | Ochiq |
| T-14 | Zaxira tiklash sinovi o'tkazilmagan | Past | Ochiq |

---

## T-01: Taxmin qilinadigan parol tiklash tokeni

**Jiddiylik:** Kritik (CVSS 9.1)
**Joy:** `app/Auth/TiklashToken.php:24`
**Turi:** CWE-338, Kriptografik jihatdan zaif generator

### Tavsif
Tiklash tokeni `md5(uniqid(mt_rand(), true))` orqali yaratiladi.
Bu uch komponentning hech biri kriptografik xavfsiz emas:
`uniqid()` joriy vaqtga asoslangan, `mt_rand()` oldindan aytish
mumkin bo'lgan generator, `md5()` buzilgan xesh.

### Ta'siri
Hujumchi bir nechta tokenni kuzatib, generator holatini tiklaydi
va istalgan foydalanuvchi uchun amal qiladigan token yaratadi.
Bu to'liq hisob egallashga olib keladi - shu jumladan
administrator hisobiga.

### Takrorlash
1. Ikkita hisob yarating
2. Ikkalasi uchun ham tiklashni so'rang
3. Tokenlarni solishtiring - vaqtga bog'liq naqsh ko'rinadi

### Tavsiya
Tokenni kriptografik generator bilan yarating:

    $token = bin2hex(random_bytes(32));

Qo'shimcha: tokenni bazada **xeshlab** saqlang, 30 daqiqada
eskirtiring, bir marta ishlating.

### Muddat
7 kun (2026-10-02)

### Mas'ul
@aziz

---

## Ustuvorlik rejasi

### Hafta 1 (kritik)
- [ ] T-01: Token generatorini almashtirish
- [x] T-02: Kalitni bekor qilish va ko'chirish

### Hafta 2-4 (yuqori)
- [ ] T-03: Barcha buyurtma yo'llariga huquq tekshiruvi
- [ ] T-04: Narxni serverda hisoblash
- [ ] T-05: Ikki qatlamli tezlik cheklovi
- [ ] T-06: Chegirmani tranzaksiya ichida qo'llash

### Oy 2-3 (o'rta va past)
- [ ] T-07 dan T-14 gacha

### Har bir tuzatish uchun
- [ ] Zaiflikni ko'rsatuvchi test yozilgan
- [ ] Tuzatish amalga oshirilgan
- [ ] Test CI da o'tadi
- [ ] Qayta tekshirish o'tkazilgan

7-bosqich: Qayta tekshirish #

PHP
// Har bir topilma uchun regressiya testi
final class AuditRegressiyaTesti extends TestCase
{
    /** T-01: Token kriptografik xavfsiz bo'lsin */
    public function test_t01_tiklash_tokeni_tasodifiy(): void
    {
        $tokenlar = [];

        for ($i = 0; $i < 100; $i++) {
            $tokenlar[] = (new TiklashToken($this->baza))->yarating($i + 1);
        }

        // Barchasi noyob
        $this->assertCount(100, array_unique($tokenlar));

        // Uzunlik yetarli
        foreach ($tokenlar as $token) {
            $this->assertSame(64, strlen($token));
            $this->assertMatchesRegularExpression('/^[0-9a-f]{64}$/', $token);
        }

        // Ochiq token bazada saqlanmaydi
        $bazadagi = $this->baza->qiymat('SELECT token_xesh FROM tiklash_tokenlari LIMIT 1');
        $this->assertNotContains($bazadagi, $tokenlar);
    }

    /** T-04: Narx mijozdan olinmaydi */
    public function test_t04_narx_serverda_hisoblanadi(): void
    {
        $mahsulot = $this->mahsulotYarating(narx: 450000);

        $this->kiring('[email protected]');

        $javob = $this->soragan('POST', '/api/savat', [
            'mahsulot_id' => $mahsulot->id,
            'miqdor' => 2,
            'narx' => 1,              // Hujumchi urinishi
        ]);

        $this->assertSame(900000, $javob->json('jami'));
    }

    /** T-05: Tezlik cheklovi ishlaydi */
    public function test_t05_kirishda_cheklov(): void
    {
        for ($i = 1; $i <= 6; $i++) {
            $javob = $this->soragan('POST', '/kirish', [
                'pochta' => '[email protected]',
                'parol' => "notogri$i",
            ]);
        }

        $this->assertSame(429, $javob->kodi());
        $this->assertNotEmpty($javob->sarlavha('Retry-After'));
    }

    /** T-06: Chegirma bir marta qo'llanadi */
    public function test_t06_chegirma_takrorlanmaydi(): void
    {
        $this->chegirmaYarating('YANGI50', foiz: 50, limit: 1);

        $this->kiring('[email protected]');
        $this->savatgaQoshing(mahsulotId: 1, miqdor: 1);

        $birinchi = $this->soragan('POST', '/api/savat/chegirma', ['kod' => 'YANGI50']);
        $ikkinchi = $this->soragan('POST', '/api/savat/chegirma', ['kod' => 'YANGI50']);

        $this->assertSame(200, $birinchi->kodi());
        $this->assertSame(422, $ikkinchi->kodi());
    }

    /** T-13: Manfiy miqdor rad etiladi */
    public function test_t13_manfiy_miqdor(): void
    {
        $this->kiring('[email protected]');

        foreach ([-5, 0, 101, 999999] as $miqdor) {
            $javob = $this->soragan('POST', '/api/savat', [
                'mahsulot_id' => 1,
                'miqdor' => $miqdor,
            ]);

            $this->assertSame(422, $javob->kodi(), "Miqdor: $miqdor");
        }
    }
}
Terminal
# Qayta tekshirish
composer test -- --testsuite=audit-regressiya

# Infratuzilmani qayta skanerlash
./infratuzilma-audit.sh

# Sarlavhalarni tekshirish
curl -sSI https://dokon.uz | grep -i content-security-policy
Natija
PHPUnit 10.5.0

.........                                               9 / 9 (100%)

OK (9 tests, 34 assertions)

content-security-policy: default-src 'self'; script-src 'self'; ...

Doimiy audit #

YAML
# .github/workflows/haftalik-audit.yml
name: Haftalik xavfsizlik auditi

on:
  schedule:
    - cron: '0 4 * * 1'
  workflow_dispatch:

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Sirlar
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Bog'liqliklar
        run: composer audit

      - name: Statik tahlil
        uses: returntocorp/semgrep-action@v1
        with:
          config: p/security-audit

      - name: Sarlavhalar
        run: |
          SARLAVHALAR=$(curl -sSI https://dokon.uz)
          for s in content-security-policy strict-transport-security \
                   x-content-type-options x-frame-options; do
            if ! echo "$SARLAVHALAR" | grep -qi "^$s"; then
              echo "::error::Sarlavha yo'q: $s"
              exit 1
            fi
          done

      - name: Regressiya testlari
        run: composer test -- --testsuite=audit-regressiya

      - name: Natijani xabar qilish
        if: failure()
        run: |
          curl -X POST "$SLACK_URL" \
            -d '{"text":"Haftalik audit muvaffaqiyatsiz tugadi"}'
        env:
          SLACK_URL: ${{ secrets.SLACK_XAVFSIZLIK }}
Audit - bir martalik voqea emas

Bir marta o'tkazilgan audit bir kunlik suratni beradi.

Ertaga:

  • Yangi kod yoziladi
  • Yangi CVE e'lon qilinadi
  • Yangi xodim qo'shiladi
  • Yangi bog'liqlik o'rnatiladi

Shuning uchun auditning katta qismini avtomatlashtiring va har hafta ishga tushiring. Qo'lda audit yiliga 1-2 marta, avtomatik audit - har hafta.

Darslik yakuni #

20 bo'limda o'rganilganlar Asoslar 1. Kiberxavfsizlik nima 2. Tahdidlar 3. Kriptografiya 4-5. Kirish nazorati Infratuzilma 6. Tarmoq xavfsizligi 7. Tizim himoyasi 14. Zararli dasturlar 17. Zaxira va tiklanish Ilova 8-9. Veb zaifliklari 10. Ma'lumot himoyasi 12. Xavfsizlik testi 18. Xavfsiz dasturlash Boshqaruv 11. Zaifliklar boshqaruvi 13. Ijtimoiy muhandislik 15-16. Monitoring, javob 19. Siyosat va boshqaruv 20. Amaliy loyiha - to'liq audit Barcha bilimni bitta ishda birlashtirish Keyingi qadam: amaliyot O'z loyihangizni himoyalang, CTF da qatnashing, o'qishni davom eting
Kiberxavfsizlik - tugamaydigan o'rganish jarayoni
Keyin nima?

Amaliyot:

  • PortSwigger Web Security Academy (bepul, juda sifatli)
  • TryHackMe - boshlang'ich uchun qulay yo'llar
  • HackTheBox - qiyinroq mashqlar
  • OverTheWire - Linux va tarmoq asoslari
  • CTF musobaqalari

O'qish:

  • OWASP Cheat Sheet Series
  • NIST maxsus nashrlari (SP 800 seriyasi)
  • CIS Benchmarks
  • Zaiflik hisobotlari (HackerOne Hacktivity)

Sertifikatlar:

  • CompTIA Security+ - asos
  • eJPT, PNPT - amaliy pentest
  • OSCP - jiddiy amaliy sertifikat
  • CISSP - boshqaruv yo'nalishi

Eng muhimi: o'z loyihangizni himoyalang. Nazariya amaliyotsiz tez unutiladi.

Yakuniy topshiriq
  1. Sinov muhitini tayyorlang (Docker yoki VM).
  2. Audit qamrovi hujjatini yozing.
  3. Infratuzilma audit skriptini ishga tushiring.
  4. Xavfsizlik sarlavhalarini tekshiring va tuzating.
  5. Autentifikatsiyani qo'lda sinang (sanash, cheklov).
  6. IDOR matritsasini tuzing va barcha yo'llarni sinang.
  7. Biznes mantiqni sinang (narx, miqdor, chegirma).
  8. Kod tahlilini o'tkazing (sirlar, SAST, naqshlar).
  9. Jarayonlarni tekshiring (hisoblar, zaxira, jurnal).
  10. To'liq hisobot yozing: topilma, jiddiylik, tavsiya, muddat.
  11. Har bir topilma uchun regressiya testi yozing.
  12. Haftalik avtomatik auditni CI ga qo'shing.

Xulosa #

  • Audit qamrovni yozma tasdiqlashdan boshlanadi.
  • Bosqichlar: infratuzilma → ilova → kod → jarayon → hisobot.
  • Avtomatik skaner yetarli emas - biznes mantiq faqat qo'lda topiladi.
  • IDOR ni matritsa usuli bilan qidiring: har resurs, har yo'l.
  • Eng ko'p uchraydigan xato: narxni mijozdan olish.
  • Poyga holatini FOR UPDATE va tranzaksiya bilan yoping.
  • Kodda topilgan sir - avval bekor qiling, keyin tarixni tozalang.
  • Jarayon auditi: hisoblar, zaxira, jurnal, yamoqlar.
  • Hisobot rahbariyat uchun xulosa bilan boshlansin.
  • Har bir topilma uchun regressiya testi yozing.
  • Auditning katta qismini avtomatlashtiring va haftalik ishga tushiring.
  • Kiberxavfsizlik - bir marta bajariladigan ish emas, doimiy jarayon.

Darslik tugadi. Endi bilimni amalda qo'llang - va har doim faqat o'z tizimingizda yoki yozma ruxsat bilan ishlang.

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.