Punycode
Punycode – sposób kodowania napisów Unicode za pomocą ograniczonego zestawu znaków ASCII, zdefiniowany w dokumencie RFC 3492 na potrzeby mechanizmu nazw domen ze znakami narodowymi (IDNA). Przekształcenie jest jednoznaczne i odwracalne: znaki ASCII z napisu wejściowego są przepisywane dosłownie, a pozostałe znaki są reprezentowane za pomocą liter, cyfr i łączników, czyli znaków dozwolonych w etykietach nazw hostów[1]. Punycode jest szczególnym przypadkiem ogólniejszego algorytmu Bootstring, opisanego w tym samym dokumencie, z wartościami parametrów dobranymi dla IDNA[1]. W nazwach domen etykietę zakodowaną w ten sposób poprzedza się prefiksem xn--[2], na przykład nazwa kraków.pl przyjmuje postać xn--krakw-3ta.pl.
Historia
[edytuj | edytuj kod]Dokument RFC 3492, którego autorem jest Adam Costello z Uniwersytetu Kalifornijskiego w Berkeley, powstał w grupie roboczej IDN organizacji IETF i został opublikowany w marcu 2003 roku ze statusem Proposed Standard[1][3]. W tym samym miesiącu ukazała się specyfikacja IDNA (RFC 3490), która w operacji ToASCII wskazała Punycode jako kodowanie etykiet zawierających znaki spoza ASCII[4]. W 2010 roku specyfikację IDNA zastąpiła nowa wersja, IDNA2008 (RFC 5890 i RFC 5891), która nie zmieniła algorytmu Punycode w żaden sposób, a jedynie formalnie zaktualizowała odwołania do niego[2][5].
Rejestr domeny .pl, prowadzony przez NASK, umożliwia rejestrację nazw ze znakami narodowymi od września 2003 roku i według NASK był pierwszym rejestrem w Europie, który to wprowadził. W 2024 roku NASK podawał, że znaków diakrytycznych użyto w ponad 25 tysiącach nazw w domenie .pl[6]. W domenie .pl dozwolone są między innymi polskie litery ą, ć, ę, ł, ń, ó, ś, ź i ż, a także znaki innych alfabetów, przy czym w jednej nazwie nie można mieszać znaków z różnych zestawów. Przedmiotem umowy z rejestrem jest nazwa w postaci ASCII z prefiksem xn-- i w takiej postaci jest ona przechowywana w DNS[7].
Punycode stosuje się także w nazwach domen najwyższego poziomu. Na przykład rosyjska domena .рф jest zarejestrowana w strefie głównej od 12 maja 2010 roku jako xn--p1ai[8].
Zasada działania
[edytuj | edytuj kod]Algorytm Bootstring
[edytuj | edytuj kod]Bootstring przedstawia dowolny ciąg kodów znaków (ang. extended string) jako ciąg podstawowych kodów znaków (ang. basic string). Specyfikacja wymienia jego cechy: zupełność (każdy ciąg rozszerzony ma reprezentację), jednoznaczność (istnieje co najwyżej jedna reprezentacja), odwracalność, wydajność (stosunek długości ciągu podstawowego do rozszerzonego jest niewielki), prostotę implementacji oraz czytelność (podstawowe kody znaków występują w wyniku jako one same)[1].
Kodowanie składa się z czterech elementów[1]:
- Wydzielenie podstawowych kodów znaków – wszystkie podstawowe kody znaków z ciągu rozszerzonego są przepisywane dosłownie na początek wyniku, w pierwotnej kolejności, a po nich następuje ogranicznik, o ile liczba takich znaków jest niezerowa.
- Kodowanie wstawień (ang. insertion unsort coding) – pozostała część wyniku opisuje kolejne wstawienia znaków spoza zbioru podstawowego. Dekoder zaczyna od części dosłownej i wstawia do niej brakujące znaki, przetwarzając je w kolejności rosnących wartości kodów, a nie w kolejności występowania. Jego stan opisują dwie zmienne: pozycja i w budowanym ciągu i licznik n, czyli bieżąca wartość kodu. Każda liczba delta jest długością serii stanów bez wstawienia, poprzedzających stan, w którym znak o kodzie n zostaje wstawiony na pozycji i.
- Uogólnione liczby całkowite o zmiennej długości – delty są zapisywane cyframi w ustalonej podstawie, a koniec liczby rozpoznaje się po tym, że cyfra jest mniejsza od progu t(j), zależnego od jej pozycji j i parametru bias: t(j) = base · (j + 1) - bias, z ograniczeniem do przedziału od tmin do tmax.
- Adaptacja parametru bias – po każdej delcie parametr bias jest dostosowywany, ponieważ bieżąca delta daje wskazówkę co do prawdopodobnej wielkości następnej, a pierwsza delta jest zwykle znacznie większa od drugiej.
Parametry Punycode
[edytuj | edytuj kod]Punycode używa podstawy 36 oraz parametrów tmin = 1, tmax = 26, skew = 38, damp = 700, początkowej wartości bias równej 72 i początkowej wartości n równej 128 (0x80). Podstawowymi kodami znaków są kody ASCII (0..7F), ogranicznikiem jest łącznik (U+002D), a wartości cyfr mają litery od a do z (0–25, niezależnie od wielkości liter) oraz cyfry od 0 do 9 (26–35)[1]. Dekoder musi rozpoznawać zarówno wielkie, jak i małe litery, a koder powinien używać wyłącznie jednej wielkości liter[1].
Zakodowany napis może kończyć się łącznikiem tylko wtedy, gdy wejście składało się wyłącznie ze znaków podstawowych, a takich napisów IDNA nie koduje. Może natomiast zaczynać się łącznikiem, ale IDNA dodaje przed nim prefiks, dzięki czemu etykiety spełniają regułę z RFC 952, zgodnie z którą nazwa hosta nie zaczyna się ani nie kończy łącznikiem[1]. Specyfikacja ostrzega też przed wizualną wieloznacznością par znaków, takich jak O i 0 albo I, l i 1, w napisach przepisywanych ręcznie[1].
Przykłady
[edytuj | edytuj kod]Dla nazwy kraków znaki podstawowe tworzą ciąg krakw, po nim następuje łącznik, a ciąg 3ta koduje wstawienie znaku ó (U+00F3) na pozycji 4, licząc od zera. Napis zawierający wyłącznie znaki ASCII otrzymuje jedynie końcowy łącznik: w przykładzie ze specyfikacji -> $1.00 <- daje -> $1.00 <--[1]. Czeskie zdanie Pročprostěnemluvíčesky koduje się jako Proprostnemluvesky-uyb24dma41a[1].
| Nazwa ze znakami narodowymi | Punycode | Etykieta w DNS (A-label) |
|---|---|---|
| kraków | krakw-3ta | xn--krakw-3ta |
| łódź | d-uga0v4h | xn--d-uga0v4h |
| żółw | w-uga1v8h | xn--w-uga1v8h |
| gdańsk | gdask-y7a | xn--gdask-y7a |
| zażółć | za-6ja4f8n1l | xn--za-6ja4f8n1l |
| münchen | mnchen-3ya | xn--mnchen-3ya |
| рф | p1ai | xn--p1ai |
Zastosowanie w nazwach domen
[edytuj | edytuj kod]W IDNA etykieta zapisana znakami Unicode w postaci znormalizowanej NFC nazywana jest U-label, a jej postać ASCII – A-label. Każdy A-label zaczyna się od prefiksu xn--, po którym następuje wynik algorytmu Punycode, a ponieważ etykieta DNS nie może przekraczać 63 oktetów, sam zakodowany ciąg ma najwyżej 59 znaków. Konwersja między obiema postaciami polega na zastosowaniu Punycode oraz dodaniu lub usunięciu prefiksu[2]. Prefiks może być zapisany dowolną wielkością liter[4]. Kodowaniu podlega każda etykieta nazwy osobno[4], a etykiet złożonych wyłącznie ze znaków ASCII IDNA nie koduje[1]. Punycode jest przeznaczony wyłącznie do konwersji etykiet nazw domen w IDNA, a specyfikacja wprost zastrzega, że nie służy do przetwarzania dowolnego tekstu[1].
Bezpieczeństwo
[edytuj | edytuj kod]W Unicode istnieją znaki wyglądające identycznie jak litery łacińskie, na przykład cyrylickie а, е, о czy р, dlatego nazwa domeny ze znakami narodowymi może do złudzenia przypominać nazwę znanej witryny i służyć do phishingu. Atak tego rodzaju, nazwany atakiem homograficznym (ang. homograph attack), opisali w 2002 roku Evgeniy Gabrilovich i Alex Gontmakher, którzy w celu sprawdzenia jego wykonalności zarejestrowali wariant nazwy microsoft.com zapisany z użyciem liter rosyjskich[9]. W 2017 roku Xudong Zheng pokazał, że domena xn--80ak6aa92e.com, złożona wyłącznie z liter cyrylicy, była wyświetlana w przeglądarkach Chrome, Firefox i Opera jako apple.com, co omijało stosowane w nich zabezpieczenia przed homografami. Google wprowadziło poprawkę w Chrome 58[10]. W tym samym roku kampania złośliwych reklam Seamless, rozprowadzająca zestaw exploitów RIG, używała nazwy domeny złożonej ze znaków cyrylicy, zapisanej w Punycode[11].
W ruchu DNS nazwy ze znakami narodowymi występują wyłącznie w postaci ASCII z prefiksem xn--, dlatego zapytania o takie nazwy można wyodrębnić po tym prefiksie i porównać z podobnymi, legalnymi nazwami bez Punycode, co pozwala wykrywać próby podszywania się pod znane domeny[12]. Na przykład nazwa аpple.com, w której pierwszą literę zastąpiono cyrylicką а (U+0430), wygląda na ekranie jak apple.com, ale w DNS ma postać xn--pple-43d.com[10].
Przeglądarki internetowe same decydują, czy pokazać użytkownikowi nazwę w postaci Unicode, czy w postaci Punycode. Google Chrome podejmuje tę decyzję osobno dla każdej etykiety nazwy hosta i wyświetla postać Punycode między innymi wtedy, gdy etykieta zawiera znaki niedozwolone, miesza pisma w niedopuszczalny sposób, miesza systemy liczbowe, zawiera znaki niewidoczne albo jest myląco podobna do innej nazwy według kryteriów Unicode Technical Standard #39[13]. Standard ten określa mechanizmy wykrywania napisów wizualnie mylących (ang. confusable)[14].
Implementacje
[edytuj | edytuj kod]Dokument RFC 3492 zawiera w załączniku przykładową implementację kodera i dekodera[1]. Biblioteka standardowa języka Python udostępnia kodek punycode, implementujący RFC 3492, oraz kodek idna, implementujący RFC 3490 i korzystający z poprzedniego, przy czym dokumentacja ostrzega, że algorytmy kodowania i dekodowania słabo się skalują, więc długość niezaufanych danych wejściowych należy ograniczać[15]. Rejestr NASK udostępnia na swojej stronie narzędzie do tłumaczenia nazw domen między postacią ze znakami narodowymi a postacią ASCII[7].
Zobacz też
[edytuj | edytuj kod]Przypisy
[edytuj | edytuj kod]- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 A. Costello, Punycode: A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA), RFC 3492, IETF, marzec 2003, DOI: 10.17487/RFC3492, ISSN 2070-1721, OCLC 943595667 (ang.).
- 1 2 3 Internationalized Domain Names for Applications (IDNA): Definitions and Document Framework, RFC 5890, IETF, sierpień 2010, DOI: 10.17487/RFC5890, ISSN 2070-1721, OCLC 943595667 (ang.).
- ↑ RFC 3492: Punycode: A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA). IETF Datatracker. [dostęp 2026-10-10]. (ang.).
- 1 2 3 P. Faltstrom, P. Hoffman, A. Costello, Internationalizing Domain Names in Applications (IDNA), RFC 3490, IETF, marzec 2003, DOI: 10.17487/RFC3490, ISSN 2070-1721, OCLC 943595667 (ang.).
- ↑ Internationalized Domain Names in Applications (IDNA): Protocol, RFC 5891, IETF, sierpień 2010, DOI: 10.17487/RFC5891, ISSN 2070-1721, OCLC 943595667 (ang.).
- ↑ Dzień Domeny Internetowej. NASK, 2024-03-15. [dostęp 2026-10-10].
- 1 2 IDN wprowadzenie. NASK. [dostęp 2026-10-10].
- ↑ Delegation Record for .РФ. IANA. [dostęp 2026-10-10]. (ang.).
- ↑ Evgeniy Gabrilovich, Alex Gontmakher, The Homograph Attack, „Communications of the ACM”, 45 (2), 2002, s. 128, DOI: 10.1145/503124.503156 (ang.).
- 1 2 Xudong Zheng: Phishing with Unicode Domains. 2017-04-14. [dostęp 2026-10-10]. (ang.).
- ↑ Jérôme Segura: Seamless campaign serves RIG EK via Punycode (updated). Malwarebytes Labs, 2017-12-04. [dostęp 2026-10-10]. (ang.).
- ↑ Adam Ziaja: Threat hunting using DNS firewalls and data enrichment. REDTEAM.PL, 2019-08. [dostęp 2026-10-10]. (ang.).
- ↑ Internationalized Domain Names (IDN) in Google Chrome. Chromium Docs. [dostęp 2026-10-10]. (ang.).
- ↑ Unicode Technical Standard #39: Unicode Security Mechanisms. Unicode Consortium, 2026-08-27. [dostęp 2026-10-10]. (ang.).
- ↑ codecs – Codec registry and base classes. Python 3 documentation. [dostęp 2026-10-10]. (ang.).
Linki zewnętrzne
[edytuj | edytuj kod]- RFC 3492: Punycode: A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA) (ang.)
- IDN wprowadzenie – informacje NASK o nazwach ze znakami narodowymi w domenie .pl wraz z narzędziem do konwersji