[РУКОВОДСТВО] 9 мин чтения

[РУКОВОДСТВО] Что такое Base64 и как он работает?

Практическое объяснение с первых принципов. Познакомьтесь с приёмом группировки по 6 бит, лежащим в основе Base64, узнайте, почему результат на 33% длиннее, откуда берётся паддинг = и когда стоит использовать эту кодировку.

Апрель 2026 | fundamentals

// ОПРЕДЕЛЕНИЕ В ОДНО ПРЕДЛОЖЕНИЕ

Base64 — это текстовое представление двоичных данных, которое использует всего 64 печатных ASCII-символа: A–Z, a–z, 0–9 и два дополнительных знака (обычно + и /, с = в качестве маркера паддинга). И это вся идея целиком. Каждые три байта двоичных данных перегруппируются в четыре символа Base64, больше ничего не происходит.

Это именно кодирование, а не шифрование — любой может развернуть его за миллисекунды. Цель не в приватности, а в безопасной транспортировке. Base64 позволяет разместить двоичные полезные нагрузки (изображения, сертификаты, PDF-файлы, криптографические ключи) там, где допустим только текст: в атрибутах HTML, строках JSON, URL-адресах, телах электронных писем, конфигах YAML, текстовых колонках базы данных, переменных окружения.

// ЗАЧЕМ ОН ВООБЩЕ НУЖЕН

Чисто текстовые каналы вырезают или искажают байты, которые им незнакомы. Почтовый шлюз, понимающий только 7-битный ASCII, сломает старший бит у каждого неанглийского символа. Парсер JSON отвергнет встроенные нулевые байты. URL, в котором встречается буквальный пробел, кавычка или амперсанд, недействителен, пока эти символы не закодированы процентами. Стандарты SMTP 1990-х исходили из того, что тела писем всегда будут простым английским текстом — но людям хотелось пересылать и фотографии, и таблицы.

Base64 решает задачу, ограничивая выходной алфавит 64 символами, которые без потерь проходят через любой известный текстовый канал: 26 прописных букв, 26 строчных, 10 цифр и два символа, которые (а) печатаемы, (б) не используются распространёнными механизмами экранирования и (в) достаточно различимы, чтобы пройти туда и обратно через ASCII. Плюс символ паддинга =, который тоже безопасен.

// ПРИЁМ ГРУППИРОВКИ ПО 6 БИТ

Вот механическое сердце Base64 в одной строке: берём вход как поток битов, разбиваем его на куски по 6 бит и ищем каждый кусок в алфавите из 64 символов.

Почему именно 6 бит? Потому что 2^6 = 64, и каждый 6-битный фрагмент ровно соответствует одному символу алфавита. Почему не 7 и не 8? 7 бит дают 128 значений (слишком много — не все из них печатаемы), а 8 бит — это снова просто сырое двоичное представление. 6 бит — золотая середина, при которой каждому возможному значению соответствует удобочитаемый символ.

Три входных байта = 24 бита = ровно четыре группы по 6 бит = четыре символа Base64. Соотношение 3 на входе к 4 на выходе фиксированное; именно поэтому результат Base64 примерно в 4/3 раза больше входных данных, то есть примерно на 33%.

// Worked example: encoding the 3 bytes 'Man' (77 97 110)
// ASCII:  M        a        n
// Binary: 01001101 01100001 01101110
// Re-group into 6-bit chunks:
//         010011 010110 000101 101110
// Decimal: 19     22     5      46
// Base64:  T      W      F      u
// Result:  'TWFu'  (stored as 4 ASCII bytes: 84 87 70 117)

// АЛФАВИТ BASE64

RFC 4648 §4 задаёт стандартный алфавит. Позиции 0–25 — это A–Z, 26–51 — a–z, 52–61 — 0–9, позиция 62 — +, позиция 63 — /.

URL-безопасный вариант (RFC 4648 §5, также известный как base64url) меняет + на - и / на _, так что результат можно без дополнительных ухищрений помещать в URL и имена файлов. Оба варианта декодируются одинаково, если применять соответствующий алфавит.

// Standard Base64 alphabet (index → character)
// 0–25:  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
// 26–51: a b c d e f g h i j k l m n o p q r s t u v w x y z
// 52–61: 0 1 2 3 4 5 6 7 8 9
// 62:    +       (or  -  in URL-safe)
// 63:    /       (or  _  in URL-safe)
// pad:   =

// ОТКУДА БЕРЁТСЯ ПАДДИНГ =

Алгоритм ожидает, что длина входных данных кратна 3 байтам (чтобы они ровно разбивались на 4 символа Base64). Когда длина входа не кратна 3, остаётся один или два байта, которых недостаточно, чтобы заполнить последнюю 4-символьную группу вывода. Паддинг символом = показывает, сколько байт не хватило.

• Длина входа mod 3 == 0 → паддинга нет (например, 'Man' → 'TWFu').
• Длина входа mod 3 == 1 → два символа паддинга (например, 'M' → 'TQ==').
• Длина входа mod 3 == 2 → один символ паддинга (например, 'Ma' → 'TWE=').

// Why 'M' becomes 'TQ==':
// Byte: M = 01001101                   (8 bits)
// Padded to 12 bits with zeros: 010011 010000
// Decimal: 19, 16  →  'T', 'Q'
// Output length must be multiple of 4 → add '==' padding
// Result: 'TQ=='
//
// When decoding, the decoder strips '==' and recovers the first 8 bits,
// discarding the trailing zero bits.

// ТОЧНО ЛИ НАКЛАДНЫЕ РАСХОДЫ 33%?

Почти, но не совсем. Точная формула — ceil(n / 3) × 4 символов для входа длиной n байт. Для 100 КБ это ceil(102400 / 3) × 4 = 136 534 символа — на 33,3% больше, чем 100 КБ. На практике, как только добавляется gzip или Brotli на уровне HTTP, сетевая стоимость оказывается ближе к 10–15%, потому что текст Base64 сжимается достаточно хорошо (хотя и не так хорошо, как сырой бинарь).

Для маленьких данных паддинг играет заметную роль: кодирование 1 байта занимает 4 символа (в четыре раза больше), кодирование 2 байт тоже занимает 4 символа. Поэтому совсем короткие Base64-строки выглядят удивительно длинными на фоне исходных данных.

// ГДЕ BASE64 ПРИМЕНЯЕТСЯ В РЕАЛЬНОМ МИРЕ

  • > Data URI в HTML/CSS — встраивание иконок и логотипов прямо в разметку: <img src="data:image/png;base64,…">
  • > Полезные нагрузки JSON и GraphQL — API, которым нужно передавать бинарь (загрузки файлов, превью) внутри текстового протокола
  • > Токены JWT — три части JWT, разделённые точками, являются строками base64url
  • > HTTP Basic Auth — пара username:password кодируется Base64 в заголовке Authorization (всё равно небезопасно без TLS!)
  • > Электронная почта (MIME) — вложения кодируются в Base64, чтобы пережить устаревшие 7-битные SMTP-серверы
  • > Сертификаты и ключи формата PEM — блок -----BEGIN CERTIFICATE----- оборачивает DER-данные, закодированные в Base64
  • > SSH-ключи — строки в id_rsa.pub и authorized_keys — это публичные ключи в Base64
  • > TEXT-колонки базы данных — когда тип BLOB недоступен, Base64 позволяет хранить бинарь в виде текста
  • > Переменные окружения — значения Kubernetes Secrets закодированы в Base64 (но НЕ зашифрованы)
  • > QR-коды и магические ссылки — короткие Base64-токены, безопасные для встраивания в URL

// BASE64 — ЭТО НЕ ШИФРОВАНИЕ

Это самое распространённое заблуждение. Base64 не скрывает содержимое ваших данных — он всего лишь переписывает бинарь в текст по открытому, детально задокументированному отображению. Пароль, закодированный как cGFzc3dvcmQ=, ровно так же уязвим, как и открытый текст password; любой раскодирует его одним вызовом функции. Относитесь к Base64 так же, как к шестнадцатеричному представлению: это форма записи, а не защита.

Если вам нужна приватность, сначала примените к открытому тексту реальный криптографический примитив (AES-GCM, ChaCha20-Poly1305, age, PGP), а потом закодируйте полученный шифротекст в Base64, если его нужно провести через текстовый канал. Шаг Base64 — это последняя миля, а не уровень безопасности.

Kubernetes Secrets — классическая ловушка: Kubernetes хранит значения секретов в Base64, из-за чего они выглядят как бы защищёнными. Но это не так — любой, у кого есть доступ на чтение в неймспейс, развернёт их обратно. Настоящая защита секретов требует инструментов вроде SealedSecrets, Vault, SOPS или облачных интеграций с KMS.

// БЫСТРОЕ КОДИРОВАНИЕ / ДЕКОДИРОВАНИЕ В КАЖДОМ ЯЗЫКЕ

// JavaScript (browser):
//   btoa('Hello')            → 'SGVsbG8='
//   atob('SGVsbG8=')         → 'Hello'
//   (btoa/atob only handle Latin-1; use TextEncoder for Unicode)
//
// Node.js:
//   Buffer.from('Hello').toString('base64')     → 'SGVsbG8='
//   Buffer.from('SGVsbG8=', 'base64').toString() → 'Hello'
//
// Python:
//   import base64
//   base64.b64encode(b'Hello')       → b'SGVsbG8='
//   base64.b64decode('SGVsbG8=')     → b'Hello'
//
// Go:
//   base64.StdEncoding.EncodeToString([]byte("Hello")) → "SGVsbG8="
//
// Ruby:
//   Base64.strict_encode64('Hello')   → 'SGVsbG8='
//
// Shell:
//   echo -n 'Hello' | base64          → 'SGVsbG8='
//   echo 'SGVsbG8=' | base64 -d        → 'Hello'

// ЧАСТЫЕ ОШИБКИ, КОТОРЫХ СТОИТ ИЗБЕГАТЬ

  • > Кодирование URL-безопасной строки стандартным алфавитом — декодер на принимающей стороне отвергнет + и /. Используйте base64url, если результат попадёт в URL, cookie или имя файла.
  • > Двойное кодирование — повторный прогон уже закодированного текста через кодировщик. Всегда проверяйте, не являются ли данные уже Base64.
  • > Забыли про UTF-8btoa('héllo') падает в браузере, потому что é находится за пределами Latin-1. Сначала преобразуйте строку в байты через TextEncoder.
  • > Несовпадения по паддингу — base64url часто отбрасывает паддинг =. Если ваш декодер строгий, добавьте паддинг обратно: input + '==='.slice((input.length + 3) % 4).
  • > Предполагать, что Base64 безопасен — это не так. Шифрование — отдельный уровень. Всегда.
  • > Использовать Base64 для огромных бинарей — кодирование файла в 500 МБ в одну строку исчерпает память. Используйте потоковую обработку.
  • > Перенос строк или его отсутствие — MIME/PEM разбивают Base64 на 64 или 76 колонок символом \n. В большинстве других контекстов ожидается одна строка. Вставляйте или удаляйте переводы строк по ситуации.

// BASE64 ЗА 30 СЕКУНД — ШПАРГАЛКА

  • > 64 печатных ASCII-символа (A–Z, a–z, 0–9, +, /) плюс паддинг =
  • > 3 байта на входе → 4 символа на выходе (фиксированное соотношение)
  • > Результат примерно на 33% длиннее входа
  • > Обратим: это кодирование, а не шифрование
  • > Используйте base64url (заменяете + → -, / → _) для URL и имён файлов
  • > Дополняйте короткий вход 1 или 2 символами =, чтобы длина вывода была кратна 4
  • > Для Unicode-текста: сначала закодируйте строку в байты UTF-8, затем примените Base64
  • > Декодируется стандартной библиотекой любого популярного языка
  • > Безопасен в HTML, JSON, URL, письмах и PEM-файлах
  • > Небезопасен как слой защиты — всегда комбинируйте с настоящим шифрованием для чувствительных данных

// СЛЕДУЮЩИЕ ШАГИ

Теперь, когда вы знаете механику, попробуйте наш кодировщик Base64 или декодер Base64 и разберите вывод символ за символом. Для URL-безопасных данных переключайтесь на base64url. Для изображений см. изображение → Base64.

Связанные подробные материалы:
Base64 URL-safe и стандартный — когда какой использовать
Base64 для UTF-8 и Unicode — как не попасться в ловушку btoa()
Base64 в JavaScript и Node.js — atob, btoa, Buffer
Base64, Base64URL и Base32 в сравнении