Инструменты разработчика · Кодер и декодер Base64
Base64 против base64url: почему стандартный декодер отклоняет — и _
· Как это работает
base64 кодирование рабочий процесс разработчика
base64url заменяет + и / на - и _, поэтому выходные данные могут передаваться по URL-адресам и именам файлов без экранирования. В этом посте объясняются два алфавита, как их конвертировать и почему отступы обычно тоже удаляются.
Токен, который декодируется везде, кроме вашего кода — ошибка недопустимого символа, вызванная одним - или _
Сегмент JWT не удается декодировать в стандартном декодере Base64 из-за недопустимой ошибки в названии символа. Но визуально никакой черточки не появляется. Посмотрите еще раз — так и есть. Версия base64url использует - где стандартный Base64 использует +, и _ где он использует /. Многие декодеры принимают только один алфавит, и токен, закодированный для безопасности URL, будет отклонен кодом, ожидающим RFC 4648 стандарта Base64.
Эти два алфавита эквивалентны; преобразование между ними представляет собой механическую замену символов. Проблема возникает из-за того, что + и / имеют значения в URL-адресах. Знак плюс обозначает пробел в данных формы application/x-www-form-urlencoded. Косая черта является разделителем путей в URL. Если вы встраиваете Base64 непосредственно в параметр запроса URL без процентного кодирования + и декодер /, может их неправильно интерпретировать.
Почему + и / являются проблемой в URL-адресах и именах файлов — зарезервированное значение / в путях и + как пробел в данных формы
+ может быть прочитан как пробел до достижения декодера. A / может разделить значение параметра не в том месте. RFC 4648 раздел 5 определяет алфавит base64url для устранения двусмысленности: используйте - вместо + и _ вместо /,, чтобы вывод был безопасным в URL-адресах и именах файлов. Оба алфавита идентичны, за исключением двух символов.
Стандартный Base64 использует символы в позициях 62 и 63: A–Z (0–25), a–z (26–51), 0–9 (52–61), + (62), / (63). base64url использует A–Z (0–25), a–z (26–51), 0–9 (52–61), - (62), _ (63). Все остальное — перегруппировка битов, правила заполнения, сопоставление битов с индексами — то же самое. Строка индексов для стандартного Base64 создаст строку индексов для base64url; отличаться будут только символы в позициях 62 и 63.
Алфавит base64url из раздела RFC 4648 5 — два замененных символа и почему больше ничего не меняется
Если входные данные не содержат индексов 62 или 63 (нет + или / в стандарте, нет - или _ в base64url), оба алфавита выдают идентичный вывод. Преобразование стандартного Base64 в base64url осуществляется простым поиском и заменой: поменяйте местами + на - и / на _. Декодирование строки base64url в стандарте Base64 требует обратного: поменять местами - на + и _ на /.
Преобразование симметрично и всегда допустимо. Если вы столкнулись с токеном, который не декодируется с ошибкой в имени недопустимого символа — или _, проверьте, принимает ли декодер base64url. Если нет, примените замену символов, и если входные данные в остальном сформированы правильно, декодирование должно пройти успешно. Рассмотрим заголовок JWT {"alg":"HS256","typ":"JWT"}, закодированный как base64url. Стандартные байты UTF-8 проходят перегруппировку: три байта становятся четырьмя индексами, которые ищутся в алфавите base64url. ToolAcre предоставляет дополнение как выбор кодировщика, а не привязывает его к переключению алфавита. Такое разделение является полезным доказательством: URL-безопасный вывод может быть дополнен или не дополнен, в то время как декодер нормализует любую форму перед вызовом примитива браузера. Алфавит и дополнение — это связанные соглашения, а не один переключатель.
Заполнение в base64url по соглашению не является обязательным — почему JWT опускает = и как декодер может восстановить его по длине
Если индекс равен 62, выходной символ равен -; когда 63, вывод равен _. Идентичные байты в стандартном алфавите будут давать + в индексе 62 и / в индексе 63. Преобразование результата base64url в стандартный представляет собой посимвольную операцию: отсканируйте - и замените на +, отсканируйте _ и замените на /,, затем декодируйте как обычно.
Байты, которые вы восстанавливаете, идентичны, поскольку индексы были идентичны; различаются только символы. Заполнение в base64url по соглашению не является обязательным, хотя стандарт разрешает это. JWT структурированы как три сегмента base64url, соединенные точками; каждый сегмент использует заполнение, если это необходимо, но многие реализации опускают его и полагаются на тот факт, что потребляющее приложение знает ожидаемую длину в байтах.
Проработанный пример: преобразование сегмента заголовка JWT в стандартный Base64 — замена символов, добавление отступов, декодирование в JSON.
Декодер может восстановить недостающее дополнение, разделив длину строки на четыре, вычислив остаток и добавив 0, 1 или 2 знаки равенства. Если длина строки не кратна четырем, отсутствие заполнения очевидно. Если длина кратна четырем, строка была либо дополнена, а затем удалена, либо уже введена кратная четырем байтам (заканчивающаяся тремя байтами в последнем блоке, не требующая заполнения).
Объединение сегментов base64url требует внимания к заполнению. Если каждый из трех сегментов заканчивается знаком =, при непосредственном объединении создаются строки типа AAAA=BBBB=CCCC=, где дополнение в середине теперь представляет собой случайные символы, а не завершающие маркеры. Вот почему JWT пропускает заполнение в каждом сегменте: трехсегментная структура является явной, поэтому декодирование происходит независимо для каждой части, а заполнение в середине объединенной строки не требуется и может нарушить синтаксический анализ.
Распространенные ошибки — смешивание алфавитов в одной строке или процентное кодирование по стандарту Base64 вместо использования base64url.
При создании многосегментной полезной нагрузки определитесь с соглашением о дополнении в начале: либо включать в каждый сегмент и никогда не объединять напрямую, либо опускать и восстанавливать длину только при декодировании. Стандарт RFC 4648 является авторитетным для обоих алфавитов. Раздел 4 определяет стандарт Base64; раздел 5 указывает base64url. Каждый соответствующий декодер должен четко указывать, какой алфавит он принимает.
Код, принимающий base64url, но не стандартный Base64 (или наоборот), реализует только подмножество. Алфавит base64url существует для совместимости с URL и ограничениями имени файла; это не улучшение или замена, а просто вариант для конкретного контекста. Когда вы создаете API или формат токена, выберите один алфавит и задокументируйте его. Распространенной ошибкой является стандартное процентное кодирование Base64 вместо использования base64url. Реализация также объясняет границу статьи. Он нормализует дефис и подчеркивание перед декодированием, но не проверяет подпись токена и не интерпретирует утверждения. Преобразование сегмента JWT в байты может выявить JSON; он не может установить, кто издал этот JSON и изменил ли его кто-нибудь.
Что сюда не входит — проверка подписей JWT, base32 и других кодировок RFC 4648.
%2B — процентный код для +; %2F — это процентный код для /.. Процентное кодирование превращает TWFu в TWFu без изменений (без специальных символов), а TE9S+g== в TE9S%2Bg%3D%3D (слишком много символов для обработки). Правильное решение — использовать base64url, который уже выдает URL безопасный вывод. Процентное кодирование Base64 является излишним и расточительным. Используйте правильный алфавит для контекста. Кодер и декодер Base64 автоматически принимает оба алфавита.
Если вы вставляете строку, содержащую -, она обрабатывается как base64url; если вставить строку, содержащую +, она будет рассматриваться как стандартная Base64. Инструмент также принимает URL-адреса и обрабатывает их как URL-безопасные входные данные. Таким образом, практическая проверка имеет два независимых результата: проход байтов туда и обратно и выбранное представление соответствует своему каналу. Прохождение первого говорит о том, что преобразование обратимо. Передача второго говорит о том, что пунктуация и заполнение не будут перезаписаны URL, именем файла, файлом cookie или протоколом, в котором они содержатся.
Вывод: два алфавита, один битовый макет — как кодировщик и декодер Base64 обрабатывает стандартный алфавит в браузере и где на его странице инструментов указано, что он принимает.
При декодировании сегмента JWT или безопасного токена URL вы можете вставить его напрямую без преобразования, и инструмент идентифицирует алфавит из контекста. Отладка неудачного декодирования становится простой: вставьте токен, проверьте, принимает ли его инструмент, а если нет, вручную поменяйте местами символы и повторите попытку.
Сама замена представляет собой одну строку кода, но неудачное декодирование также может быть связано с невозможной длиной, неуместным заполнением, повреждением или вводом, отличным от Base64. Инструмент автоматически нормализует оба алфавита, поэтому принятие подтверждает только возможность восстановления байтов. Декодированная полезная нагрузка JWT по-прежнему является неподписанным утверждением, пока отдельный верификатор не проверит ее подпись и ожидаемый алгоритм.