Кодирование

Кодировка Base64: как она работает, где используется и распространённые заблуждения

Вложения в письмах, data URI для изображений и токены JWT — всё это опирается на Base64. В этом руководстве объясняется, что именно делает Base64, почему результат длиннее исходных данных и когда его стоит применять, а когда нет.

Зачем нужен Base64

Любые компьютерные данные в конечном счёте состоят из байтов. Однако многие каналы безопасно передают только текст: тело письма, HTTP-заголовки, JSON-документы и URL. Если пропустить через них «сырые» байты изображения или шифротекст, управляющие символы и переводы строк могут повредить данные, а промежуточная система может их переписать.

Base64 решает эту задачу, отображая любую последовательность байтов на алфавит из 64 символов: заглавные и строчные латинские буквы, цифры, а также + и /. Эти символы почти везде считаются безопасными, поэтому двоичные данные проходят через текстовые каналы без искажений. Формат стандартизирован в RFC 4648.

Три байта превращаются в четыре символа

Основная идея проста. Входные данные берутся по три байта (24 бита), и эти 24 бита делятся на четыре группы по шесть бит. Шестью битами можно записать 64 значения, от 0 до 63, поэтому каждая группа соответствует одному символу: 0–25 — это A–Z, 26–51 — a–z, 52–61 — 0–9, 62 — +, а 63 — /.

Возьмём слово Man. Его байты — 77, 97 и 110. Разбив эти 24 бита на группы по шесть, получаем 19, 22, 5 и 46, что соответствует TWFu. Текст на других языках обрабатывается так же после перевода в байты: корейский символ 한 занимает в UTF-8 три байта (ED 95 9C) и поэтому превращается ровно в четыре символа — 7ZWc.

Man   → TWFu
Hi    → SGk=
한    → 7ZWc
안녕  → 7JWI64WV

Поскольку три байта всегда дают четыре символа, результат Base64 примерно на 33 % больше исходных данных. Файл размером 1000 байт превращается в 1336 символов. Именно поэтому встраивание больших изображений в виде data URI заметно утяжеляет страницу.

Что означает знак = в конце

Если длина входных данных не кратна трём, в последней группе остаётся только один или два байта. Недостающие биты дополняются нулями, а в конец добавляется один или два символа =, чтобы длина результата оставалась кратной четырём. Один оставшийся байт даёт ==, два оставшихся байта — один =. Поэтому Hi (два байта) превращается в SGk=.

Дополнение — лишь подсказка, помогающая декодеру восстановить точную длину; данных в нём нет. Некоторые системы его опускают, и тогда строгие декодеры могут отклонить строку с ошибкой неверной длины. Обычно проблему решает добавление символов = до длины, кратной четырём.

Base64URL для ссылок и имён файлов

Символы + и / имеют особое значение в URL: + может читаться как пробел, а / разделяет сегменты пути. Поэтому вариант Base64URL заменяет + на -, а / на _. Одни и те же два байта FB FF кодируются как +/8= в стандартном Base64 и как -_8= в Base64URL.

Все три части JSON Web Token закодированы в Base64URL, обычно без дополнения. Если декодировать среднюю часть JWT, в открытом виде видны такие данные, как идентификатор пользователя и срок действия. Это подводит нас к самому важному факту о Base64.

Главное заблуждение: Base64 — это не шифрование

Результат Base64 выглядит как случайный набор символов, поэтому его часто принимают за шифрование. Но ключа здесь нет: любой может мгновенно восстановить исходные данные по тем же общедоступным правилам. Хранить или передавать пароли и API-ключи в Base64 — то же самое, что держать их открытым текстом.

Хороший пример — Basic-аутентификация HTTP. Имя пользователя и пароль соединяются двоеточием и кодируются в Base64, но это лишь формат передачи; реальную защиту обеспечивает HTTPS. Если данные нужно скрыть, используйте шифрование, например AES. Если нужно обнаружить подмену, используйте хеш или подпись.

Где Base64 встречается на практике

Зная, где применяется Base64, проще быстро распознать незнакомую строку.

  • Вложения в письмах: MIME кодирует двоичные вложения в Base64 внутри тела сообщения.
  • Data URI: небольшие значки можно встроить в CSS или HTML в виде data:image/png;base64,... Применяйте это только к изображениям размером в несколько килобайт.
  • JWT и OAuth: заголовки и полезная нагрузка токенов используют Base64URL.
  • Тела API-запросов: JSON не может содержать «сырые» байты, поэтому файлы и подписи передаются как строки Base64.
  • Сертификаты и ключи: содержимое PEM-файла, начинающегося с -----BEGIN CERTIFICATE-----, — это Base64.

Что проверить, если строка не декодируется

У большинства ошибок декодирования всего несколько причин. Во-первых, проверьте, нет ли переводов строк или пробелов: в письмах и PEM-файлах строка часто переносится каждые 76 символов. Во-вторых, если вы видите - или _, это Base64URL, и декодировать строку нужно соответствующим способом. В-третьих, если длина не кратна четырём, отсутствует дополнение.

Если декодирование прошло успешно, но текст выглядит как «кракозябры», проблема в исходной кодировке символов. Например, кириллица даёт совершенно разные байты в UTF-8 и Windows-1251, поэтому результат нужно интерпретировать в той же кодировке, что использовалась при кодировании. Инструмент Base64 от AIBIZAP работает с UTF-8, поэтому кириллица, японский, корейский текст и эмодзи корректно преобразуются в обе стороны.

Попробуйте с этими инструментами

Другие руководства

Все руководства