Помилки кодування URL-адреси, які розробники все ще допускають (і виправляють)

Помилки кодування URL-адреси незначні, постійні та часто виявляються під час виробництва. Неправильне %20, амперсанд із подвійним кодуванням або переплутане + проти пробілу може порушувати виклики API, пошкоджувати дані відстеження та створювати вразливі місця в безпеці. Давайте виправимо найпоширеніші.
Перевірте своє кодування за допомогою нашого інструменту URL Encoder/Decoder — вставте будь-який рядок і миттєво перегляньте закодований результат.
encodeURI проти encodeURIComponent
JavaScript має дві вбудовані функції кодування, і використання неправильної є джерелом помилок №1:
| Функція | Кодує | Зберігає | Використовувати для |
|---|---|---|---|
encodeURI | Пробіли, не ASCII | : / ? # [ ] @ ! $ & ' ( ) * + , ; = | Кодування повної URL |
encodeURIComponent | Усе вище + : / ? # @ ! $ & ' ( ) * + , ; = | Тільки - _ . ~ та буквено-цифрові | Кодування значення параметра запиту |
// НЕПРАВИЛЬНО — encodeURI зберігає & у значеннях запиту
const url = 'https://api.example.com/search?q=' + encodeURI('том і джеррі');
// Результат: https://api.example.com/search?q=tom%20&%20jerry
// & зберігається — тепер він виглядає як окремий параметр! // ПРАВИЛЬНО
const url = 'https://api.example.com/search?q=' + encodeURIComponent('том і джеррі');
// Результат: https://api.example.com/search?q=tom%20%26%20jerry
Емпіричне правило: Використовуйте encodeURIComponent для окремих значень. Використовуйте encodeURI, лише якщо у вас є повна URL-адреса, для якої потрібні лише символи, відмінні від ASCII.
Помилки подвійного кодування
Подвійне кодування відбувається, коли вже закодований рядок кодується знову:
const name = 'привіт, світ';
const encoded = encodeURIComponent(name); // привіт%20світе
const подвоєний = encodeURIComponent(закодований); // привіт%2520світе
// %25 - це кодування самого %!
Це зазвичай відбувається, коли:
- Фреймворк автоматично кодує параметри запиту, і ви також їх попередньо кодуєте
- URL-адреса кодується перед збереженням, а потім знову кодується під час отримання
- Проміжне програмне забезпечення обробляє URL-адресу на кількох рівнях, до кожного з яких додається кодування
Виявлення
Шукайте %25 в URL-адресах — це майже завжди ознака подвійного кодування. Послідовність %2520 (пробіл із подвійним кодуванням) є класичним сигналом.
+ проти %20 Confusion
У надсиланні форм HTML (application/x-www-form-urlencoded) пробіли стають +. У стандартному процентному кодуванні (RFC 3986) пробіли стають %20.
Це важливо, оскільки:
decodeURIComponentnot декодує + назад у космос — залишає його як літерал +- Бекенд-фреймворки можуть або не можуть автоматично декодувати
+ залежно від аналізатора - Якщо ваш API очікує
%20, але отримує +, пошук за запитом "red+car" повертає результати для "red+car" (з літеральним плюсом) замість "red car"
// Безпечне декодування, яке обробляє як +, так і %20
функція safeDecodeParam(значення) { return decodeURIComponent(value.replace(/\+/g, '%20'));
}
UTF-8 Edge Cases
Не-ASCII-символи, як-от é, ü, 日本語, і смайли мають бути у відсотковому кодуванні як їхній байт UTF-8 послідовності:
encodeURIComponent('café') // кафе%C3%A9
encodeURIComponent('日本語') // %E6%97%A5%E6%9C%AC%E8%AA%9E
encodeURIComponent('🔒') // %F0%9F%94%92
Проблеми виникають, коли:
- Сервер очікує Latin-1, але отримує UTF-8 (mojibake — спотворені символи)
- Стовпці бази даних не налаштовані на UTF-8, багатобайтові символи мовчки скорочуються
- Файли журналу інтерпретують закодовані рядки з неправильним набором символів
Пасткові камені URL-адреси перенаправлення та зворотного виклику
Зворотні виклики OAuth і URL-адреси перенаправлення особливо схильні до помилок кодування:
// Створення перенаправлення OAuth
const redirectUri = 'https://myapp.com/callback?source=oauth';
const authUrl = `https://provider.com/auth?redirect_uri=${encodeURIComponent(redirectUri)}`;
// Правильно: вся URL-адреса зворотного виклику (включно з власною?) кодується як одне значення параметра
Поширені помилки:
- Зовсім не кодується
redirect_uri — ? у зворотному виклику розділяє батьківську URL-адресу - Часткове кодування
redirect_uri — кодування шляху, але не запиту - Кодування повної URL-адреси авторизації замість лише значення параметра
Ці помилки часто створюють уразливості відкритого перенаправлення, які зловмисники використовують для фішингу.
Контрольний список налагодження
Якщо URL-адреса не працює належним чином, перевірте це в такому порядку:
- Шукайте %25 — вказує на подвійне кодування
- Перевірка + проти %20 — чи послідовно обробляються пробіли?
- Перегляньте необроблений запит — скористайтеся вкладкою DevTools у веб-переглядачі «Мережа», щоб побачити фактичну надіслану закодовану URL-адресу
- Тестуйте зі спеціальними символами — спробуйте
& = ? # / у значеннях, щоб перевірити, чи вони порушують структуру URL - Check Content-Type — сервер аналізує як
application/x-www-form-urlencoded або application/json? - Перевірте декодування на сервері — реєструйте необроблені та розкодовані значення на стороні сервера
Безпечні допоміжні функції
// Безпечне створення рядка запиту
функція buildQueryString(params) { повернути Object.entries(params) .map(([ключ, значення]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}` ) .join('&');
} // Використовуйте URLSearchParams (сучасні браузери + Node.js)
const params = new URLSearchParams({ q: 'tom & jerry', page: '1' });
const url = `https://api.example.com/search?${params}`;
// Правильно: автоматично обробляє кодування
Найкраща практика: Використовуйте конструктор URLSearchParams або URL замість об’єднання рядків вручну. Вони правильно обробляють кодування за замовчуванням.
FAQ
Чому + стає пробілом?
Це успадковане кодування форми HTML (application/x-www-form-urlencoded), де пробіли кодуються як +. У стандартному процентному кодуванні (RFC 3986) пробілами є %20. Конвенція + застосовується лише до рядків запиту в надсиланні форми, а не до сегментів шляху чи інших частин URL.
Як правильно закодувати вкладені URL-адреси?
Використовуйте encodeURIComponent для внутрішньої URL-адреси, перш ніж розмістити його в параметрі запиту зовнішньої URL-адреси. Це кодує символи на зразок :/?, які інакше сприймалися б як частина зовнішньої структури URL-адреси.
Чому підписи порушуються після кодування URL-адреси?
Підписи обчислюються за точними послідовностями байтів. Якщо ви підписуєте рядок перед кодуванням (або після декодування), але перевіряєте його в закодованій формі (або навпаки), байти відрізняються, і підпис не вдається. Завжди нормалізуйте кодування перед підписанням.
Пов’язані інструменти та статті
- URL Encoder/Decoder — тестування кодування в реальному часі
- Помилки безпеки JWT — кодування також має значення для обробки токенів
- Виправлення невідповідності контрольної суми — при зміні кодування пошкоджені хеші файлів