· kaynak Hacker News – Front Page (native)
CPython, str.lower()'ın yanlış Unicode sürümünü kullandığı bir IDNA hatasını düzeltti
Seth Larson, CPython'ın IDNA codec'inin, standardın gerektirdiği Unicode 3.2 kuralları yerine yorumlayıcının modern Unicode verilerini izleyen str.lower()'ı çağırarak spesifikasyona uymayan alan adı kodlamaları ürettiğini anlatıyor.

Gözler önünde saklanan bir standartlar hatası
Python Software Foundation'da Security Developer-in-Residence olarak çalışan CPython geliştiricisi Seth Larson, Python'ın en sıradan dizge işlemlerinden birinin nasıl bir güvenlik açığına dönüştüğünü anlatan bir yazı kaleme aldı. Yazısı Hacker News'in ana sayfasına ulaşan Larson'a göre sorun, standart kütüphanenin uluslararasılaşmış alan adlarını (IDNA) ele alma biçiminde yatıyor ve özünde, str.lower()'ın bir karakteri küçük harfe çevirirken hangi Unicode sürümüne danıştığına kadar indirgeniyor.
Arka plan: Unicode'un ASCII alan adlarına eşlenmesi
Çekirdek internet standartlarının birçoğu yalnızca ASCII kabul eder, oysa alan adları Latin alfabesinin çok ötesindeki yazı sistemleriyle yazılır. Bu boşluğu IDNA, yani Internationalizing Domain Names in Applications köprüler. Larson, eski biçimi olan IDNA 2003'ün, metni ASCII uyumlu bir forma dönüştürmeden önce normalize edip harf durumunu katlamak için NamePrep'e dayandığını — RFC 3491'de RFC 3454'teki StringPrep algoritmasının bir profili olarak tanımlanmış — açıklıyor. IDNA 2003'ün yerini daha sonra RFC 5890'dan 5893'e kadar uzanan RFC'lerle tanımlanan IDNA 2008 almıştır.
Python iki dünyayı da sunar. str.encode('idna') ile kullanılan yerleşik idna codec'i IDNA 2003'ü uygularken, Python Package Index'teki üçüncü taraf idna paketi IDNA 2008'i uygular. Larson'ın genel tavsiyesi, bir uygulama bilinçli olarak eski davranışa ihtiyaç duymadıkça codec yerine paketi tercih etmek yönünde.
Uyuşmazlık nereden sızıyor
RFC 3454'ün 3.2. bölümünde tanımlanan StringPrep'in harf katlama adımı, karakterleri B.2 ve B.3 tabloları üzerinden eşler. B.2 tablosu esasen her karakteri Unicode kurallarına göre küçük harfe çevirmektir, B.3 ise istisnaları içerir. Standart kütüphanedeki stringprep modülü B.3 istisnalarını uygular, ardından kalan her şeye str.lower() çağırır.
İşte bu geri dönüş hatanın kendisidir. str.lower(), çalışan yorumlayıcıyla birlikte gelen Unicode veritabanını kullanır — Larson'ın raporunda unicodedata.unidata_version 17.0.0'dır — ancak RFC'nin tabloları fiilen yerine sabitlenmiş Unicode 3.2.0 harf katlama kurallarıdır. Spesifikasyon bir anlık görüntüye sabitlenmiştir, oysa uygulamanın bir adımı her Python sürümüyle birlikte ileriye kayar. Dikkat çekici bir şekilde, Python zaten sabitlenmiş bir Unicode 3.2.0 veritabanı olan unicodedata.ucd_3_2_0'ı da içerir; hem stringprep hem de idna codec'i aramaları için onu içe aktarır, sondaki .lower() çağrısı ise bu sabitlemeyi basitçe atlar.
Bu sapma gözlemlenebilir. Ꭰ (U+13A0) karakteri için Larson, RFC 3454 kuralları izlendiğinde "ᎠᎠ".encode("idna") ifadesinin xn--58da ürettiğini, Unicode 17.0.0 harf katlaması uygulandığında ise xn--kz9aa ürettiğini gösteriyor. Dolayısıyla aynı girdi dizgesi, yorumlayıcının Unicode verisine bağlı olarak farklı ASCII alan adlarına kodlanabiliyor — standardın talep ettiği ile kodun yaptığı arasındaki bu boşluğu Larson bir güvenlik açığı olarak sınıflandırıyor.
Çözüm
Larson'ın anlattığı düzeltme, StringPrep yolunun Unicode 3.2.0'a sabitlenmiş gibi davranmasını sağlıyor. Codepoint'ler üzerinde çalışarak, Stan Ulbrych ile birlikte yorumlayıcının modern str.lower()'ının 3.2.0 davranışından ayrıldığı her konumu kaydetti ve bu özel fonksiyonun eski sonuçları üretmesi için yeni istisnalar kodladılar. Sorunu Bitshift bildirdi, çözümü Marc-Andre Lemburg ve Petr Viktorin inceledi ve olay CVE-2026-17084 olarak takip ediliyor. Larson, Python Software Foundation'daki güvenlik çalışmasının Alpha-Omega tarafından sponsorlandığını da ekliyor.
Neden önemli
Bu olay, "just lowercase it" ifadesinin yani 'küçük harfe çeviriver' yaklaşımının nötr bir işlem olmadığının hatırlatıcısı. str.lower(), her yorumlayıcıyla birlikte gelen ve sürümler arasında değişen Unicode verisine bağlıdır; dolayısıyla sabitlenmiş bir Unicode anlık görüntüsü üzerine kurulu herhangi bir algoritma, yalnızca bazı adımlarda değil her adımda anlık görüntüye sabitlenmiş tablolar kullanmalıdır.
Geliştiriciler için pratik çıkarımlar açık. Yeni kod, .encode("idna") yerine güncel IDNA 2008 kurallarını uygulayan üçüncü taraf idna paketini tercih etmeli. Ayrıca eski codec'e bel bağlamış herhangi bir sistem, belirli adların kodlamasının Python derlemeleri arasında farklılık gösterebileceğinin farkında olmalı; yani iki uygulama, aynı alan adı dizgesinin eşleşip eşleşmediği konusunda sessizce ayrışabilir — ad doğrulama ve karşılaştırma kodunda tam da önem taşıyan türden bir tutarsızlık bu.
- #python
- #security
- #unicode
- #idna
- #cve