Что такое URL-кодирование на самом деле
URL-кодирование, или процентное кодирование, — это способ передать в URL символы, которые в нём недопустимы. В URL можно использовать лишь небольшой набор латинских букв, цифр и знаков. Всё остальное — пробел, кириллица, эмодзи, арабские слова — записывается как % и две шестнадцатеричные цифры на каждый байт.
Тот же приём применяют к символам, которые разрешены, но что-то означают. ? начинает строку запроса, а & разделяет параметры, поэтому при поиске хлеб & сыр амперсанд нужно отправить как %26, иначе сервер увидит два параметра вместо одного.
В этом вся задача: безопасно поместить значение в URL, не изменив смысла адреса. Это не сжатие, не шифрование и не фильтр безопасности.
Как символ превращается в %XX
Кодируются байты, а не символы. Сначала текст переводится в байты UTF-8, затем каждый байт, который нужно закодировать, записывается как % и его значение в hex.
Символ ASCII занимает один байт, поэтому пробел (байт 32, hex 20) становится %20. Символы за пределами ASCII занимают в UTF-8 от двух до четырёх байт, и у каждого байта свой код:
я→ байты D1 8F →%D1%8F€→ байты E2 82 AC →%E2%82%AC😀→ байты F0 9F 98 80 →%F0%9F%98%80
Декодирование идёт в обратном порядке: собрать байты и прочитать их как UTF-8. Если байты получены в другой кодировке, например Windows-1251, выйдут «кракозябры» — привет вместо привет. Все современные браузеры и фреймворки используют UTF-8 — и вам стоит.
Зарезервированные и незарезервированные символы: важен контекст
RFC 3986 делит символы URL на две группы.
Незарезервированные — A–Z a–z 0–9 - . _ ~ — никогда не требуют кодирования. Кодировать их можно, но бессмысленно, и хороший кодировщик их не трогает.
Зарезервированные — : / ? # [ ] @ ! $ & ' ( ) * + , ; = — задают структуру URL. Кодировать ли символ, зависит от того, где он стоит. / между сегментами пути должен остаться косой чертой, а / в имени файла, переданном параметром, должен стать %2F. Поэтому нет единого правильного способа «закодировать URL»: каждую часть кодируют для того места, куда она попадёт.
encodeURIComponent или encodeURI
В JavaScript есть две встроенные функции, и выбор не той — самая частая ошибка с URL.
| Функция | Для чего | Не трогает |
|---|---|---|
encodeURIComponent | Одно значение: параметр, сегмент пути | Только незарезервированные |
encodeURI | Целый адрес, который должен работать | Также зарезервированные |
Примените encodeURI к значению a&b=c — & и = уцелеют, и один параметр превратится в два. Примените encodeURIComponent к целому URL — все / и : экранируются, и ссылка перестанет быть ссылкой. Правило: собирайте URL из частей и кодируйте каждое значение через encodeURIComponent, а лучше доверьте это URLSearchParams.
В других языках то же разделение: quote и quote_plus в Python, rawurlencode и urlencode в PHP. Наш URL-кодировщик и декодировщик поддерживает оба режима, чтобы вы увидели разницу на своих данных.
+ или %20: исключение для форм
В пути пробел — это %20, а + — просто плюс. Но HTML-формы, отправленные со стандартным типом application/x-www-form-urlencoded, кодируют пробел в строке запроса как +, а сервер декодирует его обратно.
Проблемы начинаются на стыке двух соглашений. Номер вроде +7 495 123-45-67, вставленный в запрос без кодирования, придёт как 7 495 123-45-67: сервер прочитал + как пробел. Решение — кодировать плюс как %2B, что делает любой кодировщик по правилам форм. Если не знаете, какое соглашение ждёт другая сторона, %20 для пробела и %2B для плюса безопасны всегда.
Двойное кодирование и ошибка %2520
%25 — это закодированный знак процента. Поэтому %2520 в URL — это %20, закодированный повторно: значение прошло через кодировщик, будучи уже закодированным.
Обычно это происходит на границе: фреймворк кодирует параметр, который вызывающий код уже закодировал, или URL перенаправления кодируют один раз, чтобы вставить в другой URL, а затем ещё раз — библиотека. Видимые симптомы: ошибка 404, поиск по буквальному тексту %20 или имя файла, полное знаков процента.
Двойное декодирование вернёт оригинал, но настоящее исправление — найти второй кодировщик и убрать его. Кодируйте ровно один раз — в момент, когда значение попадает в URL.
Кодирование — не экранирование и не шифрование
Процентное кодирование делает значение безопасным внутри URL. Для HTML, JavaScript или SQL оно ничего не делает. Как только сервер декодирует %3Cscript%3E, у него снова обычный <script>, поэтому вывод всё равно нужно экранировать под место назначения, а запросы к базе — параметризовать.
Это и не секретность. Любой может декодировать URL, а адреса попадают в журналы сервера, историю браузера, системы аналитики и заголовок Referer следующей страницы. Никогда не кладите пароль, токен или персональные данные в строку запроса только потому, что это «выглядит зашифрованным». То же относится к Base64, как объясняет наше руководство по Base64.
Когда декодирование не удаётся
Большинство проблем с URL — это одно из следующего:
- «URIError: malformed URI sequence». После
%нет двух шестнадцатеричных цифр или байты не являются корректным UTF-8. Буквальный знак процента сам должен передаваться как%25. - Кириллица превращается в п или �. Байты записаны в одной кодировке, а прочитаны в другой. Убедитесь, что обе стороны используют UTF-8.
- Параметр обрывается на &. Значение не закодировали или закодировали через
encodeURIвместоencodeURIComponent. - Плюсы становятся пробелами. Декодирование форм прочитало
+как пробел. Кодируйте настоящий плюс как%2B. - %2520, %253D и подобные. Двойное кодирование: ищите второй кодировщик.
Вставьте URL в декодер и посмотрите каждый параметр отдельно — разбор обычно показывает проблему за секунды.
Связанные инструменты и руководства:
- URL-кодировщик и декодировщик - Кодируйте текст или целый URL, превращайте %XX обратно в текст и смотрите каждый параметр.
- Кодировщик и декодер Base64 - Кодируйте текст в Base64 или обратно — с URL-safe выводом и корректным UTF-8.
- Base64 простыми словами: как работают кодирование и декодирование
Частые вопросы
Что такое URL-кодирование?⌄
URL-кодирование, или процентное кодирование, записывает недопустимые в URL символы как % и две шестнадцатеричные цифры на каждый байт UTF-8. Пробел становится %20, а «я» — %D1%8F. Так любой текст можно передать в URL, не меняя его смысла.
Почему пробел иногда +, а иногда %20?⌄
HTML-формы, отправленные как application/x-www-form-urlencoded, кодируют пробел в строке запроса как +. Во всех остальных местах, включая пути и большинство API, пробел — это %20, а + означает обычный плюс. %20 безопасен всегда.
Что использовать: encodeURI или encodeURIComponent?⌄
Используйте encodeURIComponent для одного значения — параметра запроса или сегмента пути, — потому что он кодирует &, =, / и ?. encodeURI подходит только для целого URL, который должен сохранить структуру.
Что означает %2520?⌄
Это дважды закодированный пробел: %25 — знак процента, значит %2520 — это %20, закодированный повторно. Декодируйте дважды, чтобы прочитать, и исправьте код, который кодирует значение два раза.
Безопасно ли URL-кодирование?⌄
Нет. Его может обратить кто угодно, секретности оно не даёт, а декодированный ввод всё ещё может нести инъекцию. Экранируйте вывод для HTML, используйте параметризованные запросы к базе и никогда не кладите секреты в URL.
Более 15 лет практического опыта в веб-разработке и безопасности. Специализация — практическая веб-безопасность: чтобы сайты были защищёнными, надёжными и легко диагностировались. BuildToolForge создан, чтобы такие проверки были бесплатными, приватными и понятными. Инструменты по возможности работают прямо в браузере, а всё, что вы вводите в инструмент, не сохраняется.
Как мы пишем руководства: Каждое руководство основано на практическом опыте, сверено с официальными стандартами и проверено нашими инструментами на реальных доменах. Мы обновляем руководства, когда меняются стандарты или инструменты. Нашли ошибку? Напишите нам: contact@buildtoolforge.com.