Для чого ми використовуємо Base64?


275

У Вікіпедії йдеться

Схеми кодування Base64 зазвичай використовуються, коли виникає потреба в кодуванні бінарних даних, які потрібно зберігати та передавати через носії, призначені для обробки текстових даних. Це потрібно для того, щоб дані залишалися цілими без змін під час транспортування.

Але хіба це не те, що дані завжди зберігаються / передаються у двійковій формі, оскільки пам’ять, яку мають наші машини, зберігає двійкові дані, і це просто залежить, як ви її інтерпретуєте? Отже, незалежно від того, чи кодуєте ви бітовий візерунок, 010011010110000101101110як Manв ASCII або як TWFuу Base64, ви зрештою збираєтеся зберігати той же біт.

Якщо кінцеве кодування є з точки зору нулів і одиниць, і кожна машина та медіа можуть мати справу з ними, то як це має значення, якщо дані представлені як ASCII або Base64?

Що це означає "засоби масової інформації, призначені для обробки текстових даних"? Вони можуть мати справу з бінарним => вони можуть мати справу з чим завгодно.


Дякую всім, я думаю, зараз розумію.

Коли ми надсилаємо дані, ми не можемо бути впевнені, що дані будуть інтерпретуватися у тому самому форматі, як і ми задумали. Отже, ми надсилаємо дані, кодовані в якомусь форматі (наприклад, Base64), який розуміють обидві сторони. Таким чином, навіть якщо відправник і одержувач інтерпретують однакові речі по-різному, але оскільки вони узгоджуються з кодованим форматом, дані не будуть інтерпретовані неправильно.

З прикладу Марка Байєрса

Якщо я хочу надіслати

Hello
world!

Один із способів - надіслати його як ASCII

72 101 108 108 111 10 119 111 114 108 100 33

Але байт 10 може не трактуватися правильно як новий рядок на іншому кінці. Отже, ми використовуємо підмножину ASCII, щоб кодувати її так

83 71 86 115 98 71 56 115 67 110 100 118 99 109 120 107 73 61 61

що ціною більшої кількості даних, переданих за однаковий обсяг інформації, гарантує, що приймач може декодувати дані за призначенням, навіть якщо приймач має різні інтерпретації для решти набору символів.


6
Історія історії: Сервери електронної пошти раніше були 7-бітним ASCII. Багато з них встановили б високий біт на 0, тому вам довелося надсилати лише 7-бітні значення. Дивіться en.wikipedia.org/wiki/Email#Content_encoding
Гарольд L,

53
Ми використовуємо base64, оскільки це читабельніше, ніж Perl
Мартін

2
@Martin, ти жартуєш. Perl важко читати, але base64 зовсім не читається.
Пітер Лонг

1
@Lazer Ваше зображення відсутнє
Mick

2
@Lazer, "Але байт 10 може не трактуватися правильно як новий рядок на іншому кінці". чому? обидві сторони домовилися про ASCII, і вони повинні правильно його інтерпретувати!
ProgramCpp

Відповіді:


298

Ваша перша помилка полягає в тому, що кодування ASCII і кодування Base64 взаємозамінні. Вони не. Їх використовують для різних цілей.

  • Коли ви кодуєте текст в ASCII, ви починаєте з текстового рядка і перетворюєте його в послідовність байтів.
  • Коли ви кодуєте дані в Base64, ви починаєте з послідовності байтів і перетворюєте їх у текстовий рядок.

Щоб зрозуміти, чому Base64 був необхідний, в першу чергу нам потрібна невелика історія обчислень.


Комп'ютери спілкуються у двійковій формі - 0 і 1s - але люди, як правило, хочуть спілкуватися з більш багатими формами даних, такими як текст або зображення. Для передачі цих даних між комп'ютерами його спочатку потрібно закодувати в 0 і 1, надіслати, а потім знову розшифрувати. Щоб взяти текст як приклад - існує багато різних способів виконання цього кодування. Було б набагато простіше, якби ми всі могли домовитись про одне кодування, але, на жаль, це не так.

Спочатку було створено багато різних кодувань (наприклад, код Бодо ), які використовували різну кількість біт на символ, поки з часом ASCII не став стандартом із 7 бітами на символ. Однак більшість комп'ютерів зберігають двійкові дані в байтах, що складаються з 8 біт кожен, тому ASCII непридатний для перенесення цього типу даних. Деякі системи видалять навіть найзначніший біт. Крім того, різниця в кодуваннях, що закінчуються рядками, в системах означає, що символи 10 і 13 ASCII також іноді змінювалися.

Для вирішення цих проблем було введено кодування Base64 . Це дозволяє кодувати айтратрійні байти до байтів, які, як відомо, безпечно надсилати без пошкодження (буквено-цифрові символи ASCII та пара символів). Недоліком є ​​те, що кодування повідомлення за допомогою Base64 збільшує його довжину - кожні 3 байти даних кодуються до 4 символів ASCII.

Для того, щоб відправити текст надійно ви можете першим закодувати в байтах , використовуючи кодування тексту за вашим вибором (наприклад , UTF-8) , а потім після цього Base64 кодує отримані виконавчі дані в текстовий рядок , яка є безпечною для відправити закодований як ASCII. Одержувач повинен буде повернути цей процес для відновлення вихідного повідомлення. Звичайно, це вимагає, щоб одержувач знав, які кодування використовувалися, і цю інформацію часто потрібно надсилати окремо.

Історично він використовувався для кодування двійкових даних у повідомленнях електронної пошти, де сервер електронної пошти може змінювати закінчення рядків. Більш сучасний приклад - використання кодування Base64 для вбудовування даних зображення безпосередньо у вихідний код HTML . Тут потрібно кодувати дані, щоб уникнути інтерпретації символів типу "<" та ">" як теги.


Ось робочий приклад:

Я хочу надіслати текстове повідомлення двома рядками:

Здравствуйте
світ!

Якщо я надішлю його як ASCII (або UTF-8), він буде виглядати приблизно так:

72 101 108 108 111 10 119 111 114 108 100 33

Байт 10 пошкоджений у деяких системах, тому ми можемо базувати 64 кодування цих байтів як рядок Base64:

SGVsbG8sCndvcmxkIQ ==

Що при кодуванні за допомогою ASCII виглядає приблизно так:

83 71 86 115 98 71 56 115 67 110 100 118 99 109 120 107 73 61 61

Усі байти тут відомі безпечними байтами, тому дуже мало шансів, що будь-яка система зіпсує це повідомлення. Я можу надіслати це замість свого оригінального повідомлення та дозволити одержувачу змінити процес відновлення вихідного повідомлення.


4
"більшість сучасних протоколів зв'язку не пошкоджуватимуть дані", хоча, наприклад, електронна пошта, агент доставки замінить рядок символів "\ nFrom" на "\ n> From", коли він зберігає повідомлення в поштову скриньку. Або заголовки HTTP закінчуються новим рядком без зворотного способу виходу з нових рядків у дані (продовження рядків конвертує пробіл), тому ви не можете просто скидати до них довільну ASCII. base64 краще, ніж просто 7-бітний безпечний, це альфа-числовий і - = + / безпечний.
Стів Джессоп

1
"Недоліком є ​​те, що кодування повідомлення за допомогою Base64 збільшує його довжину - кожні 3 байти даних кодуються до 4 байт." Як він збільшується до 4 байт? Чи все одно це буде 3 * 8 = 24 біта?
Лазер

4
@Lazer: ні. Подивіться на власний приклад - "Людина" є базовою-64, кодованою як "TWFu". 3 байти -> 4 байти. Це тому, що вхід може бути будь-яким із 2 ^ 8 = 256 можливих байтів, тоді як для виведення використовується лише 2 ^ 6 = 64 з них (і =, щоб допомогти вказати довжину даних). 8 біт на чверть виходу "витрачаються", щоб уникнути, щоб у виході містилися будь-які "хвилюючі" символи, навіть якщо вхід є.
Стів Джессоп

2
Може бути корисним перезавантажити "Коли ви кодуєте дані в Base64, ви починаєте з послідовності байтів і перетворюєте їх у текстовий рядок" як "Коли ви кодуєте дані в Base64, ви починаєте з послідовності байтів і перетворюєте їх у послідовність байтів, що складається лише зі значень ASCII ". Послідовність байтів, що складається тільки з символів ASCII, є тим, що вимагає SMTP, саме тому Base64 (і котирується для друку) використовується як кодування передачі вмісту. Відмінний огляд!
ALEXintlsos

1
Я б проголосував, але має 64 голоси. Вибачте, це ідеально.
Джессі Кетрінк

61

Кодування двійкових даних у XML

Припустимо, ви хочете вставити пару зображень у XML-документ. Зображення є двійковими даними, тоді як XML-документ - це текст. Але XML не може обробити вбудовані двійкові дані. То як же це зробити?

Одним із варіантів є кодування зображень у base64, перетворення бінарних даних у текст, з яким може працювати XML.

Замість:

<images>
  <image name="Sally">{binary gibberish that breaks XML parsers}</image>
  <image name="Bobby">{binary gibberish that breaks XML parsers}</image>
</images>

ти робиш:

<images>
  <image name="Sally" encoding="base64">j23894uaiAJSD3234kljasjkSD...</image>
  <image name="Bobby" encoding="base64">Ja3k23JKasil3452AsdfjlksKsasKD...</image>
</images>

І XML-аналізатор зможе правильно проаналізувати XML-документ і витягти дані зображення.


Можливо, так працює старий .mhtформат Microsoft (файл html + зображення в одному файлі).
Шрідхар Сарнобат

38

Чому б не звернутися до RFC, який наразі визначає Base64 ?

Базове кодування даних використовується в багатьох ситуаціях для зберігання або передачі
даних у середовищах, які, можливо, з застарілих причин обмежені лише даними US-ASCII [1]. Кодування баз може також використовуватися в нових програмах, які не мають застарілих обмежень, просто тому, що це дає можливість маніпулювати об'єктами за допомогою текстових редакторів.

У минулому різні програми мали різні вимоги, і тому іноді реалізовували базові кодування дещо по-різному. Сьогодні специфікації протоколу іноді використовують базові кодування взагалі, а "base64" зокрема, без точного опису чи посилання. Багатоцільові розширення Інтернет-пошти (MIME) [4] часто використовуються як орієнтир для base64 без урахування наслідків для загортання рядків або символів, що не містять алфавіту. Метою цієї специфікації є встановлення загальних міркувань щодо алфавіту та кодування. Це, сподіваємось, зменшить неоднозначність в інших документах, що призведе до кращої сумісності.

Base64 спочатку був розроблений як спосіб дозволити приєднання бінарних даних до електронних листів як частини багатоцільового розширення Інтернет-пошти.


26

Звичайно, медіа, призначені для текстових даних, також є бінарними, але текстові носії часто використовують певні бінарні значення для контрольних символів. Також текстові носії інформації можуть відхиляти певні бінарні значення як нетекстові.

Кодування Base64 кодує бінарні дані як значення, які можна інтерпретувати лише як текст у текстових носіях, і не містить будь-яких спеціальних символів та / або керуючих символів, так що дані також зберігатимуться на текстових носіях.


Так, як і у Base64, здебільшого і джерело, і місце призначення будуть інтерпретувати дані однаково, оскільки, швидше за все, вони будуть інтерпретувати ці 64 символи однаково, навіть якщо вони інтерпретують контрольні символи по-різному. Це так?
Лазер

6
Вони можуть навіть знищити дані. Наприклад, багато програм FTP переписують закінчення рядків від 13,10 до 10 або навпаки, якщо операційна система сервера та клієнта не збігається і передача позначена як текстовий режим. FTP - це лише перший приклад, який прийшов мені на думку, він не дуже хороший, оскільки FTP підтримує бінарний режим.
Гендрік Бруммерман

@nhnb: Я думаю, що FTP - прекрасний приклад, оскільки він показує, що текстовий режим не підходить для речей, які хочуть двійкових даних.
jamesdlin

Що таке текстовий носій інформації?
Корай Тугай

18

Більше того, що ЗМІ підтверджують кодування рядків, тому ми хочемо переконатися, що дані приймаються програмою обробки (а не містить бінарної послідовності, що представляє, наприклад, EOL)

Уявіть, що ви хочете відправити двійкові дані в електронному листі з кодуванням UTF-8 - електронна пошта може відображатися неправильно, якщо потік одиниць і нулів створює послідовність яка не є дійсною Unicode в кодуванні UTF-8.

Один і той же тип відбувається в URL-адресах, коли ми хочемо кодувати символи, недійсні для URL-адреси в самій URL-адресі:

http://www.foo.com/hello мій друг -> http://www.foo.com/hello%20my%20friend

Це тому, що ми хочемо відправити простір над системою, яка вважатиме, що простір смердючий.

Все, що ми робимо, полягає в тому, щоб існувало відображення від 1 до 1 між відомою хорошою, прийнятною та нешкідливою послідовністю бітів до іншої буквальної послідовності бітів, і що програма обробки не розрізняє кодування.

У вашому прикладі manможе бути дійсним ASCII в першій формі; але часто ви можете передати значення, які є випадковими двійковими (тобто надсилання зображення електронною поштою):

MIME-версія: 1.0
Content-Description: "Код Base64 a.gif"
Тип вмісту: image / gif; name = "a.gif"
Content-Transfer-Encoding: Base64
Content-Disposition: вкладення; filename = "a.gif"

Тут ми бачимо, що GIF-зображення закодовано в base64 як фрагмент електронної пошти. Клієнт електронної пошти зчитує заголовки та розшифровує їх. Через кодування ми можемо бути впевнені, що GIF не містить нічого, що може трактуватися як протокол, і ми уникаємо вставляти дані, які SMTP або POP можуть вважати значущими.


1
Це приголомшливо - це пояснення змусило його натиснути. Справа не в тому, щоб придушувати або стискати дані, а просто уникати використання спеціальних послідовностей, які можна інтерпретувати як протокол.
Патрік

13

Base64 замість того, щоб уникати спеціальних символів

Я надам вам зовсім інший, але реальний приклад: я пишу код JavaScript для запуску в браузері. Теги HTML мають значення ідентифікатора, але існують обмеження щодо того, які символи дійсні в ідентифікаторі.

Але я хочу, щоб мій ідентифікатор без втрат посилався на файли в моїй файловій системі. Файли насправді можуть містити в собі всілякі дивні та чудові символи - зі знаків оклику, наголошених символів, тильди, навіть смайлів! Я не можу це зробити:

<div id="/path/to/my_strangely_named_file!@().jpg">
    <img src="http://myserver.com/path/to/my_strangely_named_file!@().jpg">
    Here's a pic I took in Moscow.
</div>

Припустимо, я хочу запустити такий код, як цей:

# ERROR
document.getElementById("/path/to/my_strangely_named_file!@().jpg");

Я думаю, що цей код не вдасться виконати.

З Base64 я можу посилатися на щось складне, не переживаючи, яка мова дозволяє якісь спеціальні символи та які потребують втечі:

document.getElementById("18GerPD8fY4iTbNpC9hHNXNHyrDMampPLA");

На відміну від використання MD5 чи іншої функції хешування, ви можете змінити кодування, щоб дізнатися, які саме дані були корисні.

Я б хотів, щоб я знав про Base64 років тому. Я б уникнув розривати волосся за допомогою ' encodeURIComponent' іstr.replace(‘\n’,’\\n’)

SSH передача тексту:

Якщо ви намагаєтеся передати складні дані через ssh (наприклад, dotfile, щоб ви могли отримати персоналізацію оболонки), удача буде це робити без Base 64. Ось як ви це зробите з базою 64 (я знаю, ви можете використовувати SCP, але це займе декілька команд - що ускладнює прив'язку клавіш для sshing на сервері):


12

Одним із прикладів, коли мені здалося, що це зручно, було намагання вставити бінарні дані в XML . Деякі бінарні дані неправильно трактуються SAX-аналізатором, оскільки ці дані можуть бути буквально будь-якими, включаючи спеціальні символи XML. Base64, що кодує дані на передавальному кінці та декодує їх на приймальному кінці, вирішив цю проблему.


1
+1 - але це аж ніяк не специфічно для SAX. Це відбудеться з будь-яким аналізатором XML, тобто DOM або XLINQ.
Біллі ONeal

1
@Billy: Так, абсолютно. Щойно я використовував аналізатор SAX для цього додатка.
Білл Ящірка

Різні двигуни, наприклад аналізатор SAX, можуть по-різному інтерпретувати деякі значення ASCII (різні символи управління). Отже, ідея полягає у використанні підмножини ASCII, яка має загальне значення загальнолюдським. Правильно?
Лазер

1
@Lazer: Правильно. Невкодовані двійкові дані матимуть у ньому контрольні символи випадково, коли ви спробуєте інтерпретувати її як ASCII (чого в цьому випадку не було).
Білл Ящірка

10

Більшість комп'ютерів зберігають дані у 8-бітовому двійковому форматі, але це не є обов'язковою умовою. Деякі машини та носії передачі можуть одночасно обробляти лише 7 біт (або, можливо, навіть менше). Такий носій інтерпретуватиме потік у кількох 7 біт, тому, якщо ви надсилатимете 8-бітні дані, ви не отримаєте того, що очікуєте з іншого боку. Base-64 - це лише один із способів вирішити цю проблему: ви кодуєте вхід у 6-бітний формат, надсилаєте його через ваш носій та декодуєте його назад у 8-бітний формат на кінці прийому.


3
Чому це проблема, якщо потік переривається через 7 біт. Зрештою, інша машина матиме всі дані, отримані через потік, вона зможе вибрати 8 біт формат для їх відображення? Що з моїм розумом!
mallaudin

6

Окрім інших (дещо тривалих) відповідей: навіть ігноруючи старі системи, які підтримують лише 7-бітний ASCII, основними проблемами з подачею бінарних даних у текстовому режимі є:

  • Нові рядки зазвичай трансформуються в текстовому режимі.
  • Потрібно бути обережними, щоб байт NUL не ставився до кінця текстового рядка, що дуже легко зробити в будь-якій програмі з рядком C.

Є також контрольні символи, такі як ^ C, ^ D і ^ Z, які інтерпретуються як кінцеві файли на деяких платформах.
dan04

5

Що це означає "засоби масової інформації, призначені для обробки текстових даних"?

Щоб ці протоколи були розроблені для обробки тексту (часто лише англійською мовою ) замість бінарних даних (наприклад, .png та .jpg зображення).

Вони можуть мати справу з бінарним => вони можуть мати справу з чим завгодно.

Але зворотне не вірно. Протокол, призначений для представлення тексту, може неправильно обробляти бінарні дані, які містять:

  • Байти 0x0A і 0x0D, використовувані для закінчень рядків, які відрізняються платформою.
  • Інші контрольні символи, такі як 0x00 (NULL = термінальний рядок C), 0x03 (END OF TEXT), 0x04 (END OF TRANSMISSION) або 0x1A (кінець файлу DOS), які можуть передчасно подавати сигнал про кінець даних.
  • Байти вище 0x7F (якщо протокол, який був розроблений для ASCII).
  • Послідовності байтів, які є недійсними UTF-8.

Таким чином, ви не можете просто надсилати двійкові дані через текстовий протокол. Ви обмежуєтесь байтами, які представляють символи ASCII, що не є просторами без контролю, яких налічується 94. .

Хоча одне питання. Як це, що системи досі не погоджуються на загальну техніку кодування, на зразок настільки поширеної UTF-8?

Принаймні, в Інтернеті вони є. Більшість сайтів використовують UTF-8 .

Проблема на Заході полягає в тому, що існує багато старого програмного забезпечення, яке засвоює, що 1 байт = 1 символ і не може працювати з UTF-8.

Проблема на Сході полягає в їх прив’язанні до кодувань, таких як GB2312 та Shift_JIS.

І той факт, що Microsoft, здається, досі не пережила, вибравши неправильне кодування UTF. Якщо ви хочете використовувати API Windows або бібліотеку виконання Microsoft C, ви обмежуєтесь кодуванням UTF-16 або кодуванням "ANSI" локалі. Це робить болісним використання UTF-8, оскільки вам доведеться весь час конвертувати.


5

Чому / як ми використовуємо кодування Base64?

Base64 - одна із схем кодування бінарного тексту, що має 75% ефективності. Він використовується таким чином, що типові двійкові дані (наприклад, зображення) можуть надійно надсилатись по застарілим каналам "не 8-бітних чистих". У попередніх мережах електронної пошти (до початку 1990-х років) більшість повідомлень електронної пошти були звичайним текстом у 7-бітовому наборі символів США-ASCII. Так багато стандартів стандартних протоколів комунікацій були розроблені для роботи над "7-бітовими" посиланнями "не 8-бітними чистими" Ефективність схеми - це співвідношення між кількістю бітів на вході та кількістю бітів у кодованому виході. Шістнадцятковий (Base16) також є однією із схем кодування бінарного тексту до 50% з ефективністю.

Етапи кодування Base64 (спрощено):

  1. Двійкові дані розташовані в безперервних шматках по 24 біта (3 байти) кожен.
  2. Кожен фрагмент 24 біт групується в чотири частини по 6 біт кожна.
  3. Кожна 6-бітова група перетворюється у відповідні їм значення значень Base64, тобто кодування Base64 перетворює три октети в чотири кодовані символи. Співвідношення вихідних байтів до вхідних байтів становить 4: 3 (33% накладні витрати).
  4. Цікаво, що одні і ті ж символи будуть кодуватися по-різному, залежно від їх положення в триоктній групі, кодованої для створення чотирьох символів.
  5. Одержувач повинен буде повернути цей процес для відновлення вихідного повідомлення.

3

Що це означає "засоби масової інформації, призначені для обробки текстових даних"?

Ще в той день, коли ASCII керував світом, що займається значеннями, що не стосуються ASCII, був головний біль. Люди перестрибували всілякі обручі, щоб перенести їх по дроту, не втрачаючи інформації.


3
Насправді, в той час, ASCII навіть не використовувався всюди. Багато протоколів мали окремий текстовий та двійковий режим для передачі даних, на жаль, тоді не надходило повідомлення електронної пошти. Текстовий режим необхідний саме тому, що жодне єдине кодування тексту не керувало світом, а не ASCII; у кожній комп’ютерній мережі є своє улюблене кодування, тому є шлюзи, завдання яких - перетворити обмінений текст у локальне кодування, щоб японська компанія могла відправляти електронний лист американському бізнес-консультанту без mojibake. Це перетворення, очевидно, небажане при надсиланні двійкових даних.
Лежи Райан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.