Нормализация символов Unicode и доменные имена
IDN – это “многоязычные доменные имена” (Internationalized Domain Names), подразумевающие преобразование кодировок на стороне клиента: Unicode кодируется при помощи Punycode, поскольку в DNS, пока что, Unicode не используется (полезная технология, вообще говоря, полезна лишь там, где действительно нужна и может быть внедрена, но это история для другой записки). Весьма неудобный дополнительный слой, который образуется из-за обработки IDN, постоянно приводит к проблемам. Самая “заковыристая”, а поэтому постоянно вылезающая тут и там, проблема – нормализация unicode-записи. Собственно, не так давно мне пришлось исправлять эту проблему в одном из сервисов, работающих с доменными именами. Но если сейчас посмотреть и потестировать те или иные профильные веб-интерфейсы, преобразующие IDN, то, думаю, данная экзотическая проблема проявится у многих (это особенно близко регистраторам доменных имён). Кстати, если этот текст читают разработчики подобных инструментов, то потестируйте имеющиеся реализации. Строки для тестирования я привожу ниже, вместе с описанием логики проблемы (впрочем, она уже упоминалась в прошлогодней записке про шумерские цифры, которую вряд ли много кто прочитал).
Итак, Unicode устроен весьма продвинутым способом. Настолько продвинутым, что там есть поддержка дорисовывания различных дополнительных значков (диакритических, например) к символам. То есть, имеются “закорючки” со “знакоместом”, на которое знакоместо ставится связанный символ. Это весьма полезно во многих системах письма. Однако некоторые буквы некоторых алфавитов имеют и “основное” представление в качестве отдельного кода, уже включающее в себя “закорючку”. Пример – русская буква “й”. Графически, это буква “и”, но с “чёрточкой” (называется “бреве” или “кратка”). Unicode позволяет закодировать “чёрточку” разными способами, как минимум, двумя – вместе с буквой и отдельно.
Посмотрите на две строки: “биткойн.рф” (1) и “биткойн.рф” (2) – они должны выглядеть одинаково. Эта одинаковость обманчива, потому что в первом случае “й” записано как U+0438 + U+0306 – буква “и” + “знак бреве”, два значения; а во втором случае – это просто буква “й” (U+0439, одно значение), где, так сказать, всё включено.
Графически, строки эквивалентны, что производит неизгладимое впечатление на разработчиков, столкнувшихся с этим явлением впервые (ну и на тех, кто столкнулся в третий или в пятый раз – тоже впечатление производит). Расщепление сущностей тут случается на два уровня выше, чем графическая отрисовка. Промежуточный итог: две разных строки кодов выглядят абсолютно одинаково, чтобы протестировать различие – строки нужно скопировать через совместимый буфер обмена, так как при помощи привычной раскладки кириллической клавиатуры набрать их не получится (в некоторых других раскладках разная “диакритика” и прочие “дополнения” доступны отдельно, но далеко не факт, что результат сохранится именно как пара кодов).
Возвращаемся к IDN. Эта технология требует преобразования кодов Unicode к DNS-записи, алфавит которой допускает (без учёта регистра) для подстрок имён хостов символы [a-z] (от “a” до “z”), [0-9] и “минус” “-” (точки тут не считаем). Для кодирования этими ASCII-символами байтовых значений Unicode используется алгоритм, называемый Punycode. Принцип тут аналогичен тому, как работает, например, Base32 (или “кодирование в рунах”), детали отличаются, но нам это здесь не так важно. Важно, что Punycode ничего не знает про особенности Unicode и просто отображает в подмножество ASCII значения unicode-байтов (и обратно), то есть, разные кодовые записи одной буквы отобразятся в разные punycode-последовательности. Что не так трудно продемонстрировать на нашем примере: “биткойн” == “qsa11dvaajue4a”, а “биткойн” == “90aoddqe0a” (выглядит занятно, да).
Однако с точки зрения DNS “qsa11dvaajue4a” и “90aoddqe0a” – разные значения, поэтому имена, их содержащие, тоже будут разными. Разный способ записи одного и того же графического представления для целей DNS не подходит – в реестрах имён, на серверах имён, первоочередное значение имеет ASCII-представление. Поэтому и используется процесс, называемый нормализацией, который описывает соглашение о том, как разные “чёрточки” так приклеить к буквам, чтобы привести всё к одной последовательности кодов, а уже её использовать, например, в DNS. Естественно, unicode-нормализация важна не только в DNS, но подробное описание принципов остаётся за рамками этой записки – его можно найти в соответствующем документе. Отмечу, что современные библиотеки для работы с IDN, обычно, позволяют прозрачно использовать нормализацию, нужно только не забыть её правильно включить при вызове функций преобразования. И, вообще говоря, алгоритмов нормализации – несколько, что делает ситуацию интереснее. А полагать, что столкнуться с подобным на практике невозможно, будет ошибкой – копирование символов иностранных письменностей в составе имён, которые не удалось ввести с клавиатуры, вполне себе встречается.
Адрес записки: https://dxdt.ru/2023/08/08/10715/
Похожие записки:
- Сбой DNSSEC в .RU
- Rowhammer-атака и код сравнения с нулём
- Палеография и падение тел
- Версия "огненной машины" из манускрипта
- Постквантовые криптосистемы и квантовые компьютеры
- Геоаналитика через "Яндекс"
- Наложенные сети Google и браузеры в будущем
- Офтопик: miaow, mew и moo в английском
- Другой Евклид в старом переводе "Элементов"
- Подпись и использование ключей из TLS-сертификатов для веба
- Длина "постквантовых ключей" и немного про будущее DNS
Написать комментарий