Dasturlash tilida oddiy va xavfsiz deb tushuniladigan funksiya qanday qilib xavfsizlik zaifligiga aylanishi mumkin? Python dasturchisi Set Laron o'z blogida str.lower() metodining IDNA 2003 standartidagi implementatsiyada qanday qilib CVE-2026-17084 xavfsizlik ochig'ini keltirib chiqqanligini batafsil tahlil qildi. Bu voqea Unicode standartlari, internet standartlari va dasturiy ta'minot yangilanishlari o'rtasidagi murakkab aloqani yana bir bor ko'rsatdi.
IDNA va StringPrep: domen nomlari uchun Unicode muammosi
Internetning dastlabki standartlari faqat ASCII belgilarini qo'llab-quvvatlagan. Ammo dunyo lotin alifbosidan kengroq belgilardan foydalanganligi uchun, Unicode belgilarini ASCII ga aylantiruvchi mexanizm kerak bo'ldi. Bu masalani hal qilish uchun StringPrep (RFC 3454) va IDNA 2003 (RFC 3491) standartlari qabul qilindi. Ularning yadrok tarkibi — harf kattaligi/kichikligi farqsiz solishtirish (case folding) uchun maxsus B.2 va B.3 jadvallari edi.
def map_table_b3(code):
r = b3_exceptions.get(ord(code))
if r is not None: return r
return code.lower()
Muhim nuqta: StringPrep algoritmi Unicode 3.2.0 versiyasining case-folding qoidalariga bog'liq. Bu standart 2003 yilda qabul qilingan, shuning uchun undagi jadvallar ham o'sha paytdagi Unicode versiyasiga moslashtirilgan. Keyinroq IDNA 2008 (RFC 5890-5893) chiqib, eski standartni eskirtirdi, lekin Python hali ham `idna` kodeki orqali IDNA 2003 ni qo'llab-quvvatlaydi.
Python qanday Unicode versiyalarini boshqaradi
Python har bir yangi versiyada yangilangan Unicode ma'lumotlar bazasini (masalan, Unicode 17.0.0) hamdaht qiladi. Amma StringPrep va IDNA 2003 uchun kerak bo'lgan Unicode 3.2.0 ma'lumotlari ham alohida unicodedata.ucd_3_2_0 moduli sifatida saqlanib qoladi. Standart kutubxonadagi stringprep va encodings.idna modullari aynan shu eski ma'lumotlar bazasidan foydalangan holda import qilinadi:
from unicodedata import ucd_3_2_0 as unicodedata
Bu yerda muammo yuzaga keladi. StringPrep algoritmining B.3 jadvalidagi istisnolarni qayta ishlovchi funksiya ichida quyidagi kod ishlatilgan:
>>> import unicodedata
>>> unicodedata.unidata_version
'17.0.0'
def map_table_b3(code):
r = b3_exceptions.get(ord(code))
if r is not None: return r
return code.lower()
Oxirgi qatordagi code.lower() chaqiruvi joriy Python interpretery Unicode versiyasini (masalan, 17.0.0) chaqiradi, o'sha paytda esa kerak Unicode 3.2.0 qoidalariga mos natija. Agar Unicode yangilanishida biror belgining kichik harfga aylantirish qoidasini o'zgartirgan bo'lsa, natija StringPrep specifikatsiyasidan farq qiladi.
Amalda qanday xato yuzaga keladi
Laron Cherokee alifbosidagi U+13A0 (Ꭰ) belgisini misol keltiradi. Unicode 3.2.0 da bu belgi o'ziga teng (o'zgaruvsiz) edi, lekin yangilik versiyalarda uning kichik harf varianti qo'shilgan. Natijada:
- Specifikatsiyaga mos (Unicode 3.2.0):
"ᎠᎠ".encode("idna") → 'xn--58da'
- Joriy Python Unicode bilan:
"ᎠᎠ".encode("idna") → 'xn--kz9aa'
Bu farq domen nomi kodlashida xavfsizlik zaifligi yaratadi: bir xil Unicode satri turli Unicode versiyasidagi Python interpretatorlarida farqli ASCII natijalarga aylanishi mumkin. Bu homografik hujumlar yoki domen nomi tekshiruvlarini o'tkazib yuborish uchun istifodan qilinishi mumkin.
$ grep -I "ucd_3_2_0" -R Lib/
Lib/stringprep.py:from unicodedata import ucd_3_2_0 as unicodedata
Lib/encodings/idna.py:from unicodedata import ucd_3_2_0 as unicodedata
Yechim: Unicode 3.2.0 ga moslashtirish
Python xavfsizlik jamoasi (Bitshift tomonidan xabar berilgan, Ston Ulbrix va boshqalar ishtirok etgan) yechim sifatida b3_exceptions jadvalini kengaytirdi. Har bir Unicode kod nuqtasi tekshirilib, str.lower() natijasi Unicode 3.2.0 dan farq qiladigan barcha belgilar alohida istisno sifatida qo'shildi. Shunday qilib, funksiya joriy Unicode versiyasi ishlatilsa ham, StringPrep uchun kerakli natijani berishi ta'minlandi.
Bu yondashuv — "shim" (yumshoq o'zgartirish) usuli — standart kutubxoda majburiy qoldirilgan eski standart (IDNA 2003) ni buzmasdan, yangilangan Unicode ma'lumotlari bilan ishlash imkonini berdi.
IDNA 2003 vs IDNA 2008: qaysi koderni ishlatish kerak?
Maqola muhim amaliy maslahatni ham eslatib o'tadi: Python-da ikkita IDNA implementatsiyasi mavjud:
# RFC 3454 compliant value ('Ꭰ' is U+13A0)
>>> "ᎠᎠ".encode("idna")
'xn--58da'
# Value if using Unicode 17.0.0 case-folding
>>> "ᎠᎠ".encode("idna")
'xn--kz9aa'
str.encode('idna') — standart kutubxona, IDNA 2003 (eskirgan, lekin hali ham ishlatiladi).
idna paketi (PyPI dan o'rnatiladi) — IDNA 2008 (zamonaviy standart).
Umumiy qoida: yangi loyihalarda doim `idna` paketidan foydalaning. Eski standart kerak bo'lgan maxsus hollarda (masalan, eski tizimlar bilan integratsiya) va shu paytda xavfsizlik yamalanishi (CVE-2026-17084) o'rnatilgan Python versiyasidan foydalaning.
Bu xavfsizlik kimni ta'sirlantiradi?
Ta'sir doirasi cheklangan: faqat IDNA 2003 (`idna` kodeki) dan foydalangan va Unicode 3.2.0 dan keyin Unicode konsorsiumi kichik harfga aylantirish qoidalarini o'zgartirgan belgilarni qayta ishlaydigan dasturlar. Ko'pgina zamonaviy ilovalar allaqachon IDNA 2008 ga o'tgan. Ammo eski tizimlarni qo'llab-quvvatlaydigan kutubxonalar va freymvorklar (masalan, ba'zi email validatsiya modullari) hali ham xavf ostida bo'lishi mumkin.
Dasturchilar uchun asosiy urinish: idna kodeki ishlatilayotgan joylarni aniqlash va Python ni xavfsizlik yamasi bilan yangilangan versiyaga ko'tarish. Python Software Foundation (PSF) xavfsizlik mutaxassisi sifatida Laronning ishi Alpha-Omega hamdosti bilan amalga oshirilgan.
Xulosa: oddiy funksiya, murakkab natija
Bu hodisa ko'rgazmasi: hatto str.lower() kabi oddiy, har kuni ishlatiladigan metod ham, agar u standartlashgan algoritmning (StringPrep) qat'iy talablariga (Unicode versiyasi) to'g'ri kelmasa, xavfsizlik ochig'iga aylanishi mumkin. Dasturchilar uchun dars: standart kutubxona funksiyalarining xotira ichidagi Unicode versiyasiga bog'liqligini unutmang, ayniqsa eski internet standartlari bilan ishlash paytida. Python jamoasining tezkor yamasi (CVE-2026-17084) bu muammoni hal qildi, lekin u kod tahlili va standartlarga rioya qilishning ahamiyatini yana bir bor ta'kidladi.
Asl manba: sethmlarson.dev