Инструменты разработчика · Кодер и декодер URL
Punycode против процентного кодирования: как обрабатываются домены и пути, не относящиеся к ASCII
· Фон
интернационализация Punycode URL-кодировка
URL с именем хоста, отличным от ASCII, и путем, отличным от ASCII, использует две совершенно разные кодировки. В этом посте объясняется IDNA и punycode для хоста, процентное кодирование для всего остального, а также почему существует разделение.
Адрес, который показывает «münchen.example» в одном браузере и «xn--mnchen-3ya.example» в другом — один хост, два варианта написания.
Город Мюнхен фигурирует в немецком доменном имени. В адресной строке вашего браузера вы можете увидеть, что münchen.example отображается нормально. Скопируйте адрес из другого приложения, и он появится как xn--mnchen-3ya.example, строка, содержащая только ASCII, которая совсем не похожа на немецкий текст. Один URL, два варианта написания, оба абсолютно действительны. Ни то, ни другое не является неправильным; они представляют один и тот же домен, используя совершенно разные наборы символов. Разница отражает фундаментальное ограничение на то, как работает DNS и как инфраструктура Интернета ожидает передачи имен хостов.
Сегменты пути, такие как /café/, требуют кодирования, но используют другую систему. Не-ASCII é становится %C3%A9 в путях. Почему такая разница? Ограничения DNS требуют использования Punycode для имен хостов.
Почему имена хостов не могут использовать процентное кодирование — метки DNS, разрешенные символы и ограничения длины
Метки DNS, отдельные сегменты имени хоста, разделенные точками, имеют очень строгие правила. Они могут содержать только ASCII букв, цифр, дефисов и подчеркиваний. У них есть ограничения по длине: каждая метка может иметь не более 63 октетов, а полное имя хоста не может превышать 255 октетов. Это жесткие ограничения самого протокола DNS, определенные десятилетия назад, еще до того, как международные доменные имена стали даже концепцией. Процентное кодирование не может работать для имен хостов, поскольку результирующая строка, скорее всего, превысит ограничения меток для более длинных слов.
Что еще более важно, DNS — это глобальная система, управляемая маршрутизаторами и серверами по всему миру. Не все из них понимают UTF-8 или Unicode. Символ с процентной кодировкой, такой как %C3%A9, по-прежнему состоит из трех символов ASCII, поэтому он соответствует ограничениям DNS. Но такой подход означает, что каждый поиск должен выполнять процентное кодирование на входе и декодирование на выходе, что усложняет сам уровень протокола. Для имен хостов требовалось лучшее решение.
IDNA и punycode в общих чертах — префикс xn-- и алгоритм начальной загрузки, качественно описанные
IDNA, спецификация интернационализированных доменных имен в приложениях, решает проблему имени хоста путем кодирования доменных имен, отличных от ASCII, в ASCII, который может обрабатывать DNS. Используемая кодировка называется punycode, алгоритм сжатия, который преобразует текст Unicode в ASCII с использованием префикса xn, за которым следует представление, закодированное в загрузочной строке. Алгоритм детерминирован: münchen всегда превращается в xn--mnchen-3ya каждый раз. Любое имя хоста, отличное от ASCII, должно быть преобразовано таким образом, прежде чем произойдет разрешение DNS.
Префикс xn-- сигнализирует DNS и программному обеспечению, поддерживающему IDNA, что следующие символы представляют собой Punycode, а не буквальные буквы ASCII. Домен типа example.xn--mnchen-3ya.com понимается как example.münchen.com программным обеспечением, поддерживающим IDNA. Punycode использует только буквы ASCII, цифры и дефисы, поэтому он без проблем вписывается в метки DNS. Алгоритм сжимает информацию, отличную от ASCII, в это представление ASCII.
Пути, запросы и фрагменты остаются закодированными в процентах — от UTF-8 байт до %XX, как и везде.
Все остальное в URL — путь, строка запроса, фрагмент — вместо этого использует процентное кодирование. Символ, отличный от ASCII, сначала преобразуется в UTF-8 байт, затем каждый байт записывается как %HH, где HH — шестнадцатеричное число. Путь /café/ становится /caf%C3%A9/.. Строка запроса ?name=josé становится ?name=jos%C3%A9. Процентное кодирование является стандартным повсюду в сети: в URL-адресах запросов HTTP, в формах HTML, в API. Он не требует специальной обработки со стороны DNS или маршрутизаторов.
Процентное кодирование также позволяет безопасно представлять другие специальные символы. Пробел становится %20, косая черта (если она должна присутствовать внутри значения) становится %2F и так далее. Схема последовательная и универсальная. Он не используется для имен хостов, поскольку DNS не понимает URL-адреса или процентное кодирование; он понимает только метки ASCII.
Рабочий пример: один URL с обоими — хост преобразован в punycode, путь закодирован в процентах, рядом
Возьмите URL "https://münchen.example/café?city=münchen". Имя хоста münchen должно быть преобразовано в punycode перед поиском DNS: https://xn--mnchen-3ya.example/café?city=münchen. Но подождите — путь и запрос также имеют значение, отличное от ASCII. Преобразуйте их тоже: https://xn--mnchen-3ya.example/caf%C3%A9?city=m%C3%BCnchen. Теперь имя хоста — punycode, путь и запрос — в процентном кодировании. Браузер отображает исходную версию Unicode для удобства чтения. Запрос HTTP содержит закодированную версию.
В инструменте кодирования и декодера URL вставьте путь, содержащий текст, отличный от ASCII, и сравните режим одного значения (только путь) с режимом всего адреса (полный URL). Инструмент показывает результат пути в процентном кодировании. Однако имя хоста требует отдельного преобразования punycode; большинство инструментов кодирования не поддерживают эту встроенную функцию, поэтому прочтите ее в документации к инструменту.
Атаки омографов и почему браузеры иногда отображают punycode — соображения безопасности, лежащие в основе правил отображения
Злоумышленник может зарегистрировать домен, используя кириллические буквы, которые визуально идентичны латинским буквам, например «https://xn--80akhbyknj4f.example" (кириллическая версия «example.example» в punycode). Если браузер отображает его в декодированном виде как кириллический текст, пользователи могут не заметить разницы. Чтобы предотвратить гомографические атаки, браузеры иногда показывают версию punycode вместо ее декодирования. Появляется предупреждение: этот домен полностью или частично не ASCII, и вы можете не узнать символы.
Кодер и декодер URL — это инструмент для кодирования и декодирования, а не для оценки безопасности. Если вы работаете с международными доменными именами, имейте в виду, что сеть видит именно представление punycode.
Что здесь не распространяется — запуск алгоритма punycode вручную или различия IDNA 2003 и 2008.
IDNA со временем претерпел несколько версий: IDNA 2003 и IDNA 2008 по-разному обрабатывают определенные крайние случаи, особенно в отношении нормализации и того, какие символы Юникода разрешены спецификацией. Некоторые старые системы по-прежнему используют IDNA 2003, в то время как другие перешли на IDNA 2008 для лучшего соответствия. Различия имеют большое значение, если вы создаете системы, которые должны быть совместимы в нескольких версиях. Всегда внимательно проверяйте системные требования.
Punycode использует сжатие начальной строки. Реализации существуют на распространенных языках, но проверьте политику IDNA в вашей системе имен хостов. Тестируйте разрешение и поведение дисплея, а не предполагайте.
Вывод: две кодировки для двух задач — как кодировщик и декодер URL обрабатывают части, закодированные в процентах, и почему кодировщик процентов — неправильный инструмент для имени хоста.
Имена хостов нуждаются в Punycode, поскольку DNS — это старый протокол, который понимает только метки ASCII и имеет строгие ограничения по длине и количеству символов. Пути, запросы и фрагменты используют процентное кодирование, поскольку оно универсально в Интернете и не имеет таких ограничений. Это два отдельных решения для двух совершенно разных проблем. Когда вы сталкиваетесь с именем, отличным от ASCII URL, имя хоста сначала преобразуется в Punycode, а затем остальное использует процентное кодирование.
Для большинства работ по разработке ваша платформа или библиотека автоматически выполняет это преобразование за кулисами. Но понимание того, почему существуют две разные кодировки, предотвращает путаницу при отладке международных URL-адресов или успешной реализации собственного кода обработки URL.