Русский

Инструменты разработчика · Кодер и декодер URL

Двойное кодирование URL: как происходит %2520, как его обнаружить и отменить

· Как это работает

URL-кодировка javascript рабочий процесс разработчика отладка

Параметр URL, показывающий, что %2520 последовательно декодируется до %20, а затем до пробела.
Оригинальная векторная иллюстрация ToolAcre

%2520 в URL означает, что пробел был закодирован дважды. В этом посте объясняются ошибки конвейера, которые вызывают это, как распознать подпись и сколько проходов декодирования безопасно.

Двойное кодирование URL: когда %2520 означает, что пространство прошло через два кодировщика.

Имя файла, поступающее как «my%20file.pdf» вместо «my file.pdf», сигнализирует о двойном кодировании: пробел был закодирован в %20, затем сам знак процента был закодирован в %25, что привело к получению %2520 в конечном URL. Каждый уровень системы, такой как клиентский код, веб-платформа или обратный прокси-сервер, может кодироваться один раз. Когда кодируются два отдельных слоя, один символ становится искаженным.

Двойное кодирование чаще всего встречается в сложных цепочках перенаправления и системах шаблонов. Разработчик может создать закодированный URL внутри платформы, которая сама по умолчанию кодирует весь вывод. Обратный прокси-сервер или сеть доставки контента могут перекодировать URL-адреса, которые уже поступили в закодированном виде из внутренней системы. Параметр, содержащий уже закодированное значение, кодируется еще раз, прежде чем быть вложенным в другую структуру URL.

Почему %25 является подсказкой — сам знак процента кодируется, поэтому %20 становится %2520, а %C3%A9 становится %25C3%25A9

Характерным признаком двойного кодирования является появление %25 там, где вы обычно ожидаете увидеть один знак процента в URL или данных. В обычно закодированном URL вы никогда не увидите %25, если не отправите литерал «%25». Если пробел, закодированный как %20, кодируется снова, он становится %2520.

Символ с акцентом, например é, который обычно кодируется как %C3%A9, становится %25C3%25A9 при двукратном последовательном кодировании двумя разными системами. Научившись обнаруживать шаблон %25 в полосах URL, журналах и сообщениях об ошибках, вы экономите бесчисленные часы утомительной работы по отладке в производственных средах, где данные проходят через несколько служб.

Где введено двойное кодирование — клиентский код плюс фреймворк, редиректы, прокси и помощники шаблонов.

Двойное кодирование ухудшает как читаемость, так и возможность серверных систем правильно анализировать URL. Файл с именем «my file.pdf» при правильном кодировании становится «my%20file.pdf». Если закодированная строка перекодируется — возможно, с помощью формы — она становится «my%2520file.pdf».

Когда сервер получает это сообщение и декодирует его один раз, он видит «my%20file.pdf» как буквальное имя файла, а не распознает его как «мой file.pdf». Любые приложения, ожидающие получить только один проход декодирования, получат искаженный результат. Хуже того, разработчик, который дважды декодирует, чтобы исправить проблемы со значениями, которые были закодированы только один раз, фактически повредит законные данные с помощью дополнительного прохода декодирования.

Рабочий пример: декодирование дважды закодированного URL по одному проходу — что показывает каждый проход и когда остановиться

Код JavaScript на стороне клиента и настройки платформы на стороне сервера являются наиболее распространенными источниками случайного двойного кодирования в производственных системах. Приложение JavaScript может использовать encodeURIComponent для значения, а затем передать его непосредственно в платформу, которая по умолчанию кодирует весь вывод строк, тем самым кодируя знак процента во второй раз. Уровень обратного прокси, предназначенный для очистки URL-адресов, может перекодировать параметры, которые уже были предварительно закодированы из серверного приложения.

Перенаправление URL, созданное путем объединения введенных пользователем данных со вспомогательной функцией платформы, может кодироваться на обоих этапах одновременно. Рабочий пример: пользователь отправляет «test&value» через форму HTML, браузер кодирует его как «test%26value». Платформа видит буквальный процентный текст и кодирует его, создавая «test%2526value». Одно декодирование дает «test%26value», но все равно неверно.

Если намеренно двойное кодирование — URL переносится внутри другого параметра запроса URL.

Намеренное двойное кодирование допустимо в одном конкретном случае: когда URL должен перемещаться внутри другого параметра запроса URL. Потоки OAuth и ссылки возврата для входа в систему иногда требуют вложения одного полного URL в другой. Внутренний URL сначала должен быть полностью закодирован в процентах, затем вся закодированная строка должна быть снова закодирована как значение параметра для внешнего URL.

Такое двойное кодирование является преднамеренным и абсолютно необходимым в этих случаях. Анализатор внешнего параметра декодирует один раз, получая все еще закодированный внутренний URL. Затем внутренняя система снова декодирует, восстанавливая исходный URL. Важнейшим ключом является понимание цели и ее четкое документирование в комментариях к коду для будущих сопровождающих.

Распространенные ошибки — декодирование до тех пор, пока ничего не изменится, что повреждает значения, которые на законных основаниях содержат %25.

Классическая и опасная ошибка — многократное декодирование до тех пор, пока ничего не изменится, что приведет к повреждению значений, которые на законных основаниях содержат знаки процента в фактических данных. Такой параметр, как «discount%2525» (представляющий литерал «%25», закодированный как значение параметра, а затем снова закодированный для транспортировки), полностью корректен по своей конструкции. Расшифровав его один раз, вы получите «скидку%25», что по-прежнему верно. Декодирование во второй раз дает «скидку%», что неверно и приводит к потере информации.

Разработчик может предположить, что «%25» является ошибкой, и выполнить декодирование повторно, потеряв знак процента. Вместо этого декодируйте ровно столько раз, сколько требует ваша архитектура: один раз для параметра, два раза вложенных. Подсчитайте слои, чтобы знать правильные операции декодирования.

Что здесь не распространяется — кодировка объекта HTML, наложенная поверх URL-адресов, которую обрабатывает escaper объект HTML.

Распространенные ошибки включают в себя кодирование всего URL с помощью encodeURIComponent, а затем ожидание, что косые черты и двоеточия будут работать как структурные разделители, чего они не могут сделать после кодирования. Другая частая ошибка — смешивание разных стандартов кодирования: в одном коде используется процентное кодирование для RFC 3986, а в другом коде используется кодирование формы со знаками плюса, обозначающими пробелы. Такое значение, как «мой+файл», становится по-настоящему двусмысленным — оно может означать «мой файл» или буквальный текст «мой+файл» с плюсом.

Если процентное кодирование сначала касается «my+file», оно становится «my%2Bfile». Если последует декодирование формы с ожиданием плюса как пробела, оно останется неверным. Согласованность слоев имеет важное значение. Каждая система должна использовать один и тот же стандарт кодирования, или каждый уровень должен быть явно задокументирован.

Вывод: кодируйте ровно один раз для каждого слоя — как кодировщик и декодер URL позволяет декодировать один проход за раз и видеть каждый промежуточный результат

После того как вы успешно определили двойное кодирование, возникающее в производственных системах, исправление полностью зависит от того, где в конвейере происходит дублирование. Если кодируются и клиентский код, и платформа, полностью удалите кодировку из одного из них. Если параметр проходит через несколько серверных служб, проследите полный путь через каждую службу и определите, какая служба кодирует, хотя это не следует делать.

Тщательно протестируйте исправление, пропустив образцы данных через полный сквозной конвейер и убедитесь, что данные доставляются в пункт назначения в неизмененном виде. Четко задокументируйте предположение о кодировании на каждой границе: «эта конечная точка возвращает параметры в процентном кодировании» или «это промежуточное программное обеспечение ожидает необработанный UTF-8 и применяет к нему кодировку». Включите ожидаемое количество проходов декодирования в эту документацию для будущих разработчиков.