19-bo‘lim
Eng ko'p uchraydigan xatolar
Kriptografiya kodidagi xatolar katalogi - ularning aksariyati algoritmda emas, birlashtirishda.
Ushbu bo‘lim mundarijasi
Bu bo'lim - butun darslikning tekshiruv ro'yxati.
Uning asosiy fikri 1-bo'limda aytilgan edi: zaifliklarning katta qismi algoritmda emas, uni noto'g'ri birlashtirishda.
Xatolar katalogi #
function korsat(string $nom, string $qiymat): void
{
printf("%-26s %s%s", $nom . ':', $qiymat, PHP_EOL);
}
$xatolar = [
[1, 'base64 ni shifrlash deb bilish', 'malumot ochiq'],
[2, '== yoki === bilan MAC solishtirish', 'vaqt boyicha sizish'],
[3, 'md5/sha1 ishlatish', 'toqnashuv topiladi'],
[4, 'parolni sha256 bilan saqlash', 'lugat hujumi tez'],
[5, 'hash($sir . $matn) bilan imzolash', 'uzunlikni kengaytirish'],
[6, 'paroldan HKDF bilan kalit olish', 'juda tez - himoya yoq'],
[7, 'ECB rejimi', 'naqsh korinadi'],
[8, 'AEAD siz shifrlash', 'ozgartirish sezilmaydi'],
[9, 'nonce ni takrorlash', 'shifr butunlay ochiladi'],
[10, 'PKCS#1 v1.5 bilan shifrlash', 'Bleichenbacher hujumi'],
[11, 'openssl_verify natijasini === 1 siz', '-1 rost hisoblanadi'],
[12, 'DH natijasini togridan-togri kalit qilish', 'bir tekis emas'],
[13, 'sertifikat tekshiruvini ochirish', 'MITM ga toliq ochiq'],
[14, 'TLS 1.0/1.1 ni yoqib qoldirish', 'eskirgan shifrlar'],
[15, 'token uchun mt_rand/uniqid', 'taxmin qilinadi'],
[16, 'hamma narsani deterministik shifrlash', 'chastota tahlili'],
[17, 'JWT alg ni tokendan olish', 'alg=none, chalkashlik'],
[18, 'kalitni kodda saqlash', 'git tarixida qoladi'],
];
printf("%-4s %-42s %s%s", "BO'LIM", 'XATO', 'OQIBATI', PHP_EOL);
echo str_repeat('-', 82), PHP_EOL;
foreach ($xatolar as $x) {
printf("%-6d %-42s %s%s", ...[...$x, PHP_EOL]);
}
BO'LIM XATO OQIBATI
----------------------------------------------------------------------------------
1 base64 ni shifrlash deb bilish malumot ochiq
2 == yoki === bilan MAC solishtirish vaqt boyicha sizish
3 md5/sha1 ishlatish toqnashuv topiladi
4 parolni sha256 bilan saqlash lugat hujumi tez
5 hash($sir . $matn) bilan imzolash uzunlikni kengaytirish
6 paroldan HKDF bilan kalit olish juda tez - himoya yoq
7 ECB rejimi naqsh korinadi
8 AEAD siz shifrlash ozgartirish sezilmaydi
9 nonce ni takrorlash shifr butunlay ochiladi
10 PKCS#1 v1.5 bilan shifrlash Bleichenbacher hujumi
11 openssl_verify natijasini === 1 siz -1 rost hisoblanadi
12 DH natijasini togridan-togri kalit qilish bir tekis emas
13 sertifikat tekshiruvini ochirish MITM ga toliq ochiq
14 TLS 1.0/1.1 ni yoqib qoldirish eskirgan shifrlar
15 token uchun mt_rand/uniqid taxmin qilinadi
16 hamma narsani deterministik shifrlash chastota tahlili
17 JWT alg ni tokendan olish alg=none, chalkashlik
18 kalitni kodda saqlash git tarixida qoladi
Endi hali ko'rmagan bir nechta xatoni ko'ramiz.
1. Qaytish qiymatini tekshirmaslik #
$kalit = hex2bin(str_repeat('aa', 32));
$nonce = hex2bin(str_repeat('bb', 12));
$teg = '';
$shifr = openssl_encrypt('Maxfiy', 'aes-256-gcm', $kalit,
OPENSSL_RAW_DATA, $nonce, $teg);
// Buzilgan ma'lumot keldi
$buzuq = $shifr;
$buzuq[0] = chr(ord($buzuq[0]) ^ 0xff);
// XATO: natijani tekshirmasdan ishlatish
$natija = openssl_decrypt($buzuq, 'aes-256-gcm', $kalit,
OPENSSL_RAW_DATA, $nonce, $teg);
korsat('qaytgan qiymat', var_export($natija, true));
korsat('turi', gettype($natija));
// Endi u satr sifatida ishlatiladi
$foydalanuvchi = (string) $natija;
korsat('satrga aylantirilgan', "'" . $foydalanuvchi . "'");
korsat('bosh satr bilan solishtirish',
$foydalanuvchi === '' ? 'TENG - xavfli' : 'teng emas');
qaytgan qiymat: false
turi: boolean
satrga aylantirilgan: ''
bosh satr bilan solishtirish: TENG - xavfli
false jimgina bo'sh satrga aylanadiopenssl_decrypt xatoda false qaytaradi. Agar uni
tekshirmasangiz va satr sifatida ishlatsangiz - u bo'sh
satrga aylanadi.
Amaliy oqibati:
$rol = openssl_decrypt($kuki, ...); // false
if ($rol === $kutilgan_rol) { ... } // '' bilan solishtirish
Yoki yanada yomoni:
$ruxsatlar = explode(',', openssl_decrypt(...)); // ['']
To'g'ri yozilishi har doim:
$matn = openssl_decrypt(...);
if ($matn === false) {
throw new RuntimeException('ochib bolmadi');
}
Xuddi shu qoida openssl_encrypt, openssl_sign,
hex2bin, base64_decode($x, true) uchun ham amal
qiladi.
2. Bitta kalitni ikki maqsadda ishlatish #
$kalit = hex2bin(str_repeat('cc', 32));
// XATO: shifrlash uchun ham, imzolash uchun ham bir xil kalit
$nonce = hex2bin(str_repeat('01', 12));
$teg = '';
$shifr = openssl_encrypt('malumot', 'aes-256-gcm', $kalit,
OPENSSL_RAW_DATA, $nonce, $teg);
$mac = hash_hmac('sha256', $shifr, $kalit);
korsat('xato usul', 'bitta kalit - ikki maqsad');
// TO'G'RI: bitta asosiy kalitdan ikkita ajratilgan kalit
$shifrKaliti = hash_hkdf('sha256', $kalit, 32, 'shifrlash');
$macKaliti = hash_hkdf('sha256', $kalit, 32, 'imzolash');
korsat('shifr kaliti', substr(bin2hex($shifrKaliti), 0, 24) . '...');
korsat('mac kaliti', substr(bin2hex($macKaliti), 0, 24) . '...');
korsat('bir xilmi', hash_equals($shifrKaliti, $macKaliti) ? 'HA' : 'yoq');
xato usul: bitta kalit - ikki maqsad
shifr kaliti: b4f63dbaec7d76c3ff015caf...
mac kaliti: 4ba954a8271eb88681601704...
bir xilmi: yoq
Bitta kalitni ikki xil algoritmda ishlatish kalitlararo hujumlarga yo'l ochadi.
Har algoritm o'z xavfsizlik faraziga asoslangan va ular birga ishlaganda kutilmagan o'zaro ta'sir paydo bo'lishi mumkin.
Amaliy qoida oddiy: har maqsadga alohida kalit. Buni
qilish arzon - hash_hkdf bir qator (6-bo'lim).
Bu shunga o'xshash holatlarga ham tegishli:
| Bir xil kalit ishlatilgan joy | To'g'risi |
|---|---|
| Shifrlash va HMAC | Ikki ajratilgan kalit |
| Ikki xil ma'lumot turi | Har turga alohida |
| Ikki muhit (test va prod) | Butunlay boshqa kalitlar |
| Ikki mijoz | Har mijozga alohida |
3. MAC ni noto'g'ri joyga qo'yish #
$shifrKaliti = hex2bin(str_repeat('11', 32));
$macKaliti = hex2bin(str_repeat('22', 32));
$iv = hex2bin(str_repeat('33', 16));
$matn = 'rol=user';
// XATO 1: MAC ochiq matn ustidan (MAC-then-encrypt)
$mac1 = hash_hmac('sha256', $matn, $macKaliti, true);
$shifr1 = openssl_encrypt($matn . $mac1, 'aes-256-cbc', $shifrKaliti,
OPENSSL_RAW_DATA, $iv);
// TO'G'RI: MAC shifrmatn ustidan (encrypt-then-MAC)
$shifr2 = openssl_encrypt($matn, 'aes-256-cbc', $shifrKaliti,
OPENSSL_RAW_DATA, $iv);
$mac2 = hash_hmac('sha256', $iv . $shifr2, $macKaliti, true);
korsat('xato tartib', 'MAC(ochiq matn), keyin shifrlash');
korsat('togri tartib', 'shifrlash, keyin MAC(IV + shifrmatn)');
// To'g'ri usulda buzilgan ma'lumot OCHILMASDAN rad etiladi
$buzuq = $shifr2;
$buzuq[0] = chr(ord($buzuq[0]) ^ 0xff);
$kutilgan = hash_hmac('sha256', $iv . $buzuq, $macKaliti, true);
korsat('buzilgan malumot',
hash_equals($mac2, $kutilgan) ? 'QABUL' : 'RAD - ochilmasdan');
xato tartib: MAC(ochiq matn), keyin shifrlash
togri tartib: shifrlash, keyin MAC(IV + shifrmatn)
buzilgan malumot: RAD - ochilmasdan
Uchta variant bor va faqat bittasi xavfsiz:
| Tartib | Kim ishlatgan | Baho |
|---|---|---|
| Encrypt-then-MAC | IPsec | To'g'ri |
| MAC-then-Encrypt | Eski TLS | Zaif (padding oracle) |
| Encrypt-and-MAC | SSH | Zaif (MAC ochiq matnni sizdiradi) |
Asosiy sabab: encrypt-then-MAC da buzilgan ma'lumot ochilmasdan turib rad etiladi. Shifrlash kodi ishonchsiz ma'lumotga umuman tegmaydi.
Qolgan ikkitasida esa avval ochish kerak - va ochish jarayonidagi xatolar (to'ldirish, format) hujumchiga ma'lumot beradi.
Amaliy tavsiya: bu tartibni o'zingiz qurmang. AES-GCM yoki ChaCha20-Poly1305 ishlating - ular buni ichida to'g'ri qiladi (8-bo'lim).
4. Xato xabarlari orqali sizish #
// XAVFLI: har xato uchun alohida xabar
function xavfliOch(string $paket, string $kalit): string
{
if (strlen($paket) < 28) {
return 'XATO: paket juda qisqa';
}
$nonce = substr($paket, 0, 12);
$teg = substr($paket, 12, 16);
$shifr = substr($paket, 28);
$matn = openssl_decrypt($shifr, 'aes-256-gcm', $kalit,
OPENSSL_RAW_DATA, $nonce, $teg);
if ($matn === false) {
return 'XATO: teg mos kelmadi';
}
if (!str_starts_with($matn, 'v1:')) {
return 'XATO: versiya notogri';
}
if (json_decode(substr($matn, 3), true) === null) {
return 'XATO: JSON buzuq';
}
return 'OK';
}
// XAVFSIZ: hamma xato uchun bitta xabar
function xavfsizOch(string $paket, string $kalit): string
{
$umumiyXato = 'XATO: paket yaroqsiz';
if (strlen($paket) < 28) {
return $umumiyXato;
}
$matn = openssl_decrypt(substr($paket, 28), 'aes-256-gcm', $kalit,
OPENSSL_RAW_DATA, substr($paket, 0, 12), substr($paket, 12, 16));
if ($matn === false
|| !str_starts_with($matn, 'v1:')
|| json_decode(substr($matn, 3), true) === null) {
return $umumiyXato;
}
return 'OK';
}
$kalit = hex2bin(str_repeat('dd', 32));
$nonce = hex2bin(str_repeat('01', 12));
$teg = '';
$shifr = openssl_encrypt('v1:{"a":1}', 'aes-256-gcm', $kalit,
OPENSSL_RAW_DATA, $nonce, $teg);
$yaxshi = $nonce . $teg . $shifr;
$sinovlar = [
'togri paket' => $yaxshi,
'qisqa paket' => 'abc',
'buzilgan teg' => $nonce . str_repeat("\x00", 16) . $shifr,
];
printf("%-16s %-28s %s%s", 'PAKET', 'XAVFLI USUL', 'XAVFSIZ USUL', PHP_EOL);
echo str_repeat('-', 74), PHP_EOL;
foreach ($sinovlar as $nom => $paket) {
printf("%-16s %-28s %s%s", $nom,
xavfliOch($paket, $kalit), xavfsizOch($paket, $kalit), PHP_EOL);
}
PAKET XAVFLI USUL XAVFSIZ USUL
--------------------------------------------------------------------------
togri paket OK OK
qisqa paket XATO: paket juda qisqa XATO: paket yaroqsiz
buzilgan teg XATO: teg mos kelmadi XATO: paket yaroqsiz
Chap ustunga qarang: har xato boshqacha xabar beradi. Hujumchi shu farqqa qarab paketni bosqichma-bosqich "tuzatib" boradi.
Bu orakul (oracle) hujumi. Uning eng mashhur shakli - padding oracle: server "to'ldirish noto'g'ri" va "MAC noto'g'ri" ni ajratib ko'rsatsa, shifr bayt-bayt ochiladi.
To'g'ri yondashuv:
| Kim uchun | Nima ko'radi |
|---|---|
| Foydalanuvchi | Bitta umumiy xabar |
| Jurnal (ichki) | To'liq tafsilot |
Ya'ni tafsilot yo'qolmaydi - u faqat tashqariga chiqmaydi:
$this->jurnal->xato('teg mos kelmadi', ['id' => $id]);
return 'Paket yaroqsiz';
Javob vaqti ham bir xil bo'lishi kerak - aks holda xabar bir xil bo'lsa ham, kechikish farqi ma'lumot beradi (2-bo'lim).
5. Siqish va shifrlash tartibi #
$maxfiy = 'MAXFIY-TOKEN-12345';
// Foydalanuvchi kiritmasi bilan birga siqib shifrlaymiz
function olcham(string $foydalanuvchiMatni, string $maxfiy): int
{
// XATO: avval siqish, keyin shifrlash
return strlen(gzcompress($foydalanuvchiMatni . $maxfiy, 9));
}
// Hujumchi turli taxminlar bilan uzunlikni o'lchaydi
$taxminlar = [
'AAAAAAAAAAAAAAAAAA' => 'butunlay notogri',
'MAXFIY-XXXXXXXXXXX' => 'boshi togri',
'MAXFIY-TOKEN-XXXXX' => 'kopi togri',
'MAXFIY-TOKEN-12345' => 'TOLIQ TOGRI',
];
printf("%-22s %-18s %s%s", 'TAXMIN', 'IZOH', 'SIQILGAN OLCHAM', PHP_EOL);
echo str_repeat('-', 62), PHP_EOL;
foreach ($taxminlar as $taxmin => $izoh) {
printf("%-22s %-18s %d bayt%s", $taxmin, $izoh,
olcham($taxmin, $maxfiy), PHP_EOL);
}
TAXMIN IZOH SIQILGAN OLCHAM
--------------------------------------------------------------
AAAAAAAAAAAAAAAAAA butunlay notogri 29 bayt
MAXFIY-XXXXXXXXXXX boshi togri 31 bayt
MAXFIY-TOKEN-XXXXX kopi togri 31 bayt
MAXFIY-TOKEN-12345 TOLIQ TOGRI 29 bayt
Jadvalga qarang: taxmin qanchalik to'g'ri bo'lsa, siqilgan hajm shuncha kichik.
Sabab: siqish algoritmi takrorlanuvchi qismlarni topadi. Foydalanuvchi kiritmasi maxfiy qiymatga o'xshasa, takrorlanish ko'payadi va hajm kamayadi.
Shifrlash bu sizishni to'xtatmaydi, chunki shifrmatn uzunligi siqilgan hajmga teng.
Bu CRIME va BREACH hujumlarining asosi. Ular HTTPS trafikda sessiya kukilarini o'g'irlash uchun ishlatilgan.
Qoida:
| Vaziyat | Nima qilish |
|---|---|
| Maxfiy va foydalanuvchi ma'lumoti bir buferda | Siqmang |
| Faqat foydalanuvchi ma'lumoti | Siqish mumkin |
| Faqat maxfiy ma'lumot | Siqish mumkin |
| Shubha bo'lsa | Siqmang |
HTTP javoblarida bu Content-Encoding: gzip ni maxfiy
ma'lumot bo'lgan javoblarda o'chirish yoki CSRF tokenini
har javobda niqoblash bilan hal qilinadi.
Oddiy audit vositasi #
function auditQil(string $kod): array
{
$qoidalar = [
'md5/sha1 ishlatilgan' => '/\b(md5|sha1)\s*\(/i',
'ECB rejimi' => '/[\'"]\w+-ecb[\'"]/i',
'MAC uchun == yoki ===' => '/hash_hmac\([^)]*\)\s*[=!]==?/',
'mt_rand/rand token uchun' => '/\b(mt_rand|rand|uniqid)\s*\(/',
'qattiq yozilgan kalit' => '/[\'"][0-9a-f]{32,}[\'"]/i',
'tekshiruv ochirilgan' => '/verify_peer\s*=>\s*false/i',
'PKCS1 v1.5 shifrlash' => '/OPENSSL_PKCS1_PADDING/',
'toldirishsiz RSA' => '/OPENSSL_NO_PADDING/',
];
$topilgan = [];
foreach ($qoidalar as $nom => $naqsh) {
if (preg_match($naqsh, $kod)) {
$topilgan[] = $nom;
}
}
return $topilgan;
}
$namunalar = [
'toza kod' => '$x = openssl_encrypt($m, "aes-256-gcm", $k, 0, $n, $t);',
'md5 parol' => '$xesh = md5($parol);',
'ecb rejimi' => 'openssl_encrypt($m, "aes-256-ecb", $k);',
'zaif token' => '$token = uniqid();',
'tekshiruvsiz' => '["ssl" => ["verify_peer" => false]]',
'qattiq kalit' => '$k = "' . str_repeat('ab', 16) . '";',
];
foreach ($namunalar as $nom => $kod) {
$t = auditQil($kod);
printf('%-14s %s%s', $nom,
$t === [] ? 'toza' : 'OGOHLANTIRISH: ' . implode('; ', $t), PHP_EOL);
}
toza kod toza
md5 parol OGOHLANTIRISH: md5/sha1 ishlatilgan
ecb rejimi toza
zaif token OGOHLANTIRISH: mt_rand/rand token uchun
tekshiruvsiz toza
qattiq kalit OGOHLANTIRISH: qattiq yozilgan kalit
Naqsh qidiruvi matn ko'radi, mantiqni emas.
| Topa oladi | Topa olmaydi |
|---|---|
| Eskirgan funksiya nomi | Nonce takrorlanishi |
| O'chirilgan tekshiruv | Kalitning qayerdan kelishi |
| Qattiq yozilgan qiymat | Encrypt-then-MAC tartibi |
| Xavfli konstanta | Xato xabarlari orqali sizish |
Ya'ni bunday skaner birinchi filtr, audit emas.
Haqiqiy tekshiruv uchun:
| Usul | Nima beradi |
|---|---|
| Kodni ko'rib chiqish | Mantiqiy xatolar |
| Tahdid modellashtirish | Yetishmayotgan himoya |
| Mustaqil audit | Yangi ko'z |
| Testlar | Buzilgan ma'lumot rad etiladimi |
Oxirgisi eng arzon va eng kam qilinadigan ish: buzilgan ma'lumot bilan test yozing. Har shifrlash kodida "o'zgartirilgan shifrmatn rad etiladi" degan test bo'lishi kerak.
Yakuniy tekshiruv ro'yxati #
| Savol | Bo'lim |
|---|---|
Parol password_hash bilan saqlanadimi | 4 |
Maxfiy qiymatlar hash_equals bilan solishtiriladimi | 2 |
| Shifrlash AEAD (GCM/ChaCha20) bilanmi | 8 |
| Nonce har xabarda yangimi | 9 |
openssl_decrypt natijasi false ga tekshiriladimi | 19 |
| Har maqsadga alohida kalit ajratilganmi | 6 |
Tokenlar random_bytes dan kelib chiqadimi | 15 |
| JWT algoritmi kodda qat'iymi | 17 |
| Sertifikat tekshiruvi yoqilganmi | 13, 14 |
| Kalitlar muhit o'zgaruvchisi yoki KMS damimi | 18 |
| Kalit almashtirish sinab ko'rilganmi | 18 |
| Xato xabarlari umumiymi | 19 |
| Buzilgan ma'lumot uchun testlar bormi | 19 |
- Katalogdagi o'n sakkiz xatoni o'z kodingizga qo'llab tekshiring.
openssl_decryptnatijasini tekshirmaslik oqibatini ko'rsating.- Bitta kalitni ikki maqsadda ishlatuvchi kodni HKDF ga o'tkazing.
- MAC-then-encrypt va encrypt-then-MAC farqini yozing.
- Buzilgan ma'lumot ochilmasdan rad etilishini ko'rsating.
- Batafsil va umumiy xato xabarlarini solishtiring.
- Siqish orqali sirning uzunligi sizishini takrorlang.
- Nima uchun shifrlash bu sizishni to'xtatmasligini tushuntiring.
- Oddiy audit vositasini yozing va o'z kodingizda ishga tushiring.
- "Buzilgan shifrmatn rad etiladi" testini yozing.
Xulosa #
- Zaifliklarning katta qismi algoritmda emas, uni birlashtirishda.
openssl_decryptxatodafalseqaytaradi va u satrga aylanganda bo'sh satr bo'ladi.- Qaytish qiymatini har doim tekshiring.
- Bitta kalitni ikki maqsadda ishlatmang -
hash_hkdfbilan ajrating. - Encrypt-then-MAC yagona xavfsiz tartib; AEAD buni o'zi qiladi.
- Buzilgan ma'lumot ochilmasdan turib rad etilishi kerak.
- Batafsil xato xabarlari orakul hujumiga yo'l ochadi - tashqariga bitta umumiy javob.
- Tafsilot jurnalga yoziladi, foydalanuvchiga emas.
- Maxfiy ma'lumot bilan foydalanuvchi kiritmasini birga siqmang (CRIME/BREACH).
- Naqsh qidiruvchi skanerlar birinchi filtr; mantiqiy xatolarni testlar topadi.
Keyingi, yakuniy bo'limda o'rganganlarimizni bitta ishlaydigan tizimda birlashtiramiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
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.