¿Por qué usamos Base64?

Wikipedia dice

Los esquemas de encoding de Base64 se usan comúnmente cuando existe la necesidad de codificar datos binarios que deben almacenarse y transferirse a través de medios que están diseñados para tratar con datos de texto. Esto es para garantizar que los datos permanezcan intactos sin modificaciones durante el transporte.

¿Pero no es que los datos siempre se almacenan / transmiten en binario porque la memoria que almacenan nuestras máquinas es binaria y solo depende de cómo la interprete? Entonces, ya sea que codifique el patrón de bits 010011010110000101101110 como Man en ASCII o como TWFu en Base64, eventualmente va a almacenar el mismo patrón de bits.

Si la encoding final es en términos de ceros y unos y cada máquina y medio puede manejarlos, ¿qué importancia tiene si los datos se representan como ASCII o Base64?

¿Qué significa “medios diseñados para tratar con datos textuales”? Pueden tratar con binary => que pueden tratar con cualquier cosa.


Gracias a todos, creo que ahora entiendo.

Cuando enviamos datos, no podemos estar seguros de que los datos se interpretarán en el mismo formato que se pretendía. Entonces, enviamos datos codificados en algún formato (como Base64) que ambas partes entienden. De esta forma, incluso si el emisor y el receptor interpretan las mismas cosas de manera diferente, pero dado que están de acuerdo con el formato codificado, los datos no se interpretarán erróneamente.

Del ejemplo de Mark Byers

Si quiero enviar

 Hello world! 

Una forma es enviarlo en ASCII como

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

Pero el byte 10 podría no interpretarse correctamente como una nueva línea en el otro extremo. Entonces, usamos un subconjunto de ASCII para codificarlo así

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

que a costa de más datos transferidos para la misma cantidad de información asegura que el receptor pueda decodificar los datos de la manera prevista, incluso si el receptor tiene diferentes interpretaciones para el rest del juego de caracteres.

Su primer error es pensar que la encoding ASCII y la encoding Base64 son intercambiables. Ellos no son. Se usan para diferentes propósitos.

  • Cuando codifica texto en ASCII, comienza con una cadena de texto y la convierte a una secuencia de bytes.
  • Cuando codifica datos en Base64, comienza con una secuencia de bytes y la convierte en una cadena de texto.

Para entender por qué Base64 era necesario en primer lugar, necesitamos un poco de historia de la informática.


Las computadoras se comunican en binario – 0 y 1 – pero la gente normalmente quiere comunicarse con datos de formas más ricas como texto o imágenes. Para transferir estos datos entre computadoras, primero tiene que codificarse en 0s y 1s, enviarse y luego decodificarse de nuevo. Para tomar el texto como ejemplo, hay muchas maneras diferentes de realizar esta encoding. Sería mucho más simple si todos estuviéramos de acuerdo en una sola encoding, pero lamentablemente este no es el caso.

Originalmente se crearon muchas codificaciones diferentes (por ejemplo, el código Baudot ) que usaba un número diferente de bits por carácter hasta que finalmente ASCII se convirtió en un estándar con 7 bits por carácter. Sin embargo, la mayoría de las computadoras almacenan datos binarios en bytes que constan de 8 bits cada uno, por lo que ASCII no es adecuado para transferir este tipo de datos. Algunos sistemas incluso limpiarían el bit más significativo. Además, la diferencia en las codificaciones de final de línea en los sistemas significa que los caracteres ASCII 10 y 13 también se modificaron algunas veces.

Para resolver estos problemas, se introdujo la encoding Base64 . Esto le permite codificar bytes aribtrary en bytes que se sabe son seguros de enviar sin corromperse (caracteres alfanuméricos ASCII y un par de símbolos). La desventaja es que codificar el mensaje utilizando Base64 aumenta su longitud: cada 3 bytes de datos se codifica a 4 caracteres ASCII.

Para enviar mensajes de manera confiable, primero puede codificar en bytes utilizando una encoding de texto de su elección (por ejemplo, UTF-8) y luego Base64 codificará los datos binarios resultantes en una cadena de texto que se puede enviar codificada como ASCII. El receptor deberá revertir este proceso para recuperar el mensaje original. Esto, por supuesto, requiere que el receptor sepa qué codificaciones se usaron, y esta información a menudo debe enviarse por separado.

Históricamente se ha utilizado para codificar datos binarios en mensajes de correo electrónico donde el servidor de correo electrónico podría modificar los finales de línea. Un ejemplo más moderno es el uso de la encoding Base64 para incrustar datos de imágenes directamente en código fuente HTML . Aquí es necesario codificar los datos para evitar que caracteres como ‘<' y '>‘ se interpreten como tags.


Aquí hay un ejemplo trabajado:

Deseo enviar un mensaje de texto con dos líneas

 Hola
 ¡mundo!

Si lo envío como ASCII (o UTF-8) se verá así:

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

El byte 10 está dañado en algunos sistemas, por lo que podemos basar 64 codificar estos bytes como una cadena Base64:

  SGVsbG8sCndvcmxkIQ == 

Que cuando está codificado usando ASCII se ve así:

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

Todos los bytes aquí son bytes seguros conocidos, por lo que hay muy pocas posibilidades de que un sistema corrompa este mensaje. Puedo enviar esto en lugar de mi mensaje original y dejar que el receptor revierte el proceso para recuperar el mensaje original.

Codificando datos binarios en XML

Supongamos que desea insertar un par de imágenes dentro de un documento XML. Las imágenes son datos binarios, mientras que el documento XML es texto. Pero XML no puede manejar datos binarios incrustados. Entonces, ¿cómo lo haces?

Una opción es codificar las imágenes en base64, convirtiendo los datos binarios en texto que XML puede manejar.

En lugar de:

  {binary gibberish that breaks XML parsers} {binary gibberish that breaks XML parsers}  

tú lo haces:

  j23894uaiAJSD3234kljasjkSD... Ja3k23JKasil3452AsdfjlksKsasKD...  

Y el analizador XML podrá analizar correctamente el documento XML y extraer los datos de la imagen.

¿Por qué no mirar al RFC que actualmente define a Base64 ?

La encoding de datos base se usa en muchas situaciones para almacenar o transferir
datos en entornos que, tal vez por razones heredadas, están restringidos a los datos de US-ASCII [1]. La encoding de base también se puede usar en nuevas aplicaciones que no tienen restricciones heredadas, simplemente porque permite manipular objetos con editores de texto.

En el pasado, las diferentes aplicaciones tenían diferentes requisitos y, por lo tanto, a veces implementaban codificaciones de base de maneras ligeramente diferentes. Hoy, las especificaciones de protocolo a veces usan codificaciones base en general, y “base64” en particular, sin una descripción o referencia precisa. Las extensiones multipropósito de correo de Internet (MIME) [4] a menudo se utilizan como referencia para base64 sin considerar las consecuencias para el ajuste de línea o caracteres que no sean del alfabeto. El propósito de esta especificación es establecer consideraciones comunes de alfabeto y encoding. Con suerte, esto reducirá la ambigüedad en otros documentos, lo que conducirá a una mejor interoperabilidad.

Base64 se diseñó originalmente como una forma de permitir que los datos binarios se adjuntasen a los correos electrónicos como parte de las Extensiones multipropósito de correo de Internet.

Los medios que están diseñados para datos textuales son, por supuesto, finalmente binarios, pero los medios textuales a menudo usan ciertos valores binarios para los caracteres de control. Además, los medios textuales pueden rechazar ciertos valores binarios como no textuales.

La encoding Base64 codifica datos binarios como valores que solo se pueden interpretar como texto en medios textuales, y está libre de caracteres especiales y / o caracteres de control, de modo que los datos también se conservarán en los medios textuales.

Es más que los medios validan la encoding de cadena, por lo que queremos asegurarnos de que la aplicación de gestión acepte los datos (y no contenga una secuencia binaria que represente EOL, por ejemplo)

Imagine que desea enviar datos binarios en un correo electrónico con encoding UTF-8: es posible que el correo electrónico no se muestre correctamente si la secuencia de unos y ceros crea una secuencia que no es válida Unicode en la encoding UTF-8.

El mismo tipo de cosas sucede en las URL cuando queremos codificar caracteres no válidos para una URL en la propia URL:

http://www.foo.com/hello mi amigo -> http://www.foo.com/hello%20my%20friend

Esto se debe a que queremos enviar un espacio sobre un sistema que pensará que el espacio es maloliente.

Todo lo que hacemos es garantizar que haya una correspondencia de 1 a 1 entre una secuencia de bits conocida buena, aceptable y no perjudicial para otra secuencia literal de bits, y que la aplicación de gestión no distinga la encoding.

En su ejemplo, man puede ser ASCII válido en la primera forma; pero a menudo es posible que desee transmitir valores que son binarios aleatorios (es decir, enviar una imagen en un correo electrónico):

Versión MIME: 1.0
Descripción del contenido: “Codificación Base64 de a.gif”
Content-Type: image / gif; name = “a.gif”
Content-Transfer-Encoding: Base64
Contenido-Disposición: archivo adjunto; filename = “a.gif”

Aquí vemos que una imagen GIF está codificada en base64 como un fragmento de un correo electrónico. El cliente de correo electrónico lee los encabezados y los decodifica. Debido a la encoding, podemos estar seguros de que el GIF no contiene nada que pueda interpretarse como protocolo y evitamos insertar datos que SMTP o POP puedan considerar significativos.

Un ejemplo de cuándo lo encontré conveniente fue cuando intenté incrustar datos binarios en XML . Algunos de los datos binarios estaban siendo malinterpretados por el analizador SAX porque esos datos podrían ser literalmente cualquier cosa, incluidos los caracteres especiales XML. Base64 codificando los datos en el extremo transmisor y decodificándolo en el extremo receptor solucionó ese problema.

La mayoría de las computadoras almacenan datos en formato binario de 8 bits, pero esto no es un requisito. Algunas máquinas y medios de transmisión solo pueden manejar 7 bits (o tal vez incluso menos) a la vez. Tal medio interpretaría el flujo en múltiplos de 7 bits, por lo que si enviara datos de 8 bits, no recibirá lo que espera del otro lado. Base-64 es solo una forma de resolver este problema: codifica la entrada en un formato de 6 bits, la envía a través de su medio y la decodifica de nuevo en formato de 8 bits en el extremo receptor.

Base64 en lugar de escapar caracteres especiales

Le daré un ejemplo muy diferente pero real: escribo el código de JavaScript para que se ejecute en un navegador. Las tags HTML tienen valores de ID, pero existen restricciones sobre qué caracteres son válidos en una ID.

Pero quiero que mi ID se refiera sin pérdida a los archivos en mi sistema de archivos. ¡Los archivos en realidad pueden tener todo tipo de personajes extraños y maravillosos en ellos a partir de exclamaciones, caracteres acentuados, tilde, incluso emoji! No puedo hacer esto:

 
Here's a pic I took in Moscow.

Supongamos que quiero ejecutar un código como este:

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

Creo que este código fallará cuando se ejecute.

Con Base64 puedo referirme a algo complicado sin preocuparme por qué lenguaje permite qué caracteres especiales y cuáles necesitan ser escapados:

 document.getElementById("18GerPD8fY4iTbNpC9hHNXNHyrDMampPLA"); 

A diferencia de usar un MD5 o alguna otra función hash, puede invertir la encoding para averiguar exactamente qué datos eran realmente útiles.

Ojalá supiera de Base64 hace años. Hubiera evitado arrancarme los pelos con ‘ encodeURIComponent ‘ y str.replace('\n','\\n')

¿Qué significa “medios diseñados para tratar con datos textuales”?

Que esos protocolos fueron diseñados para manejar texto (a menudo, solo texto en inglés ) en lugar de datos binarios (como imágenes .png y .jpg).

Pueden tratar con binary => que pueden tratar con cualquier cosa.

Pero la conversación no es verdadera. Un protocolo diseñado para representar texto puede tratar incorrectamente datos binarios que contienen:

  • Los bytes 0x0A y 0x0D, utilizados para las terminaciones de línea, que difieren según la plataforma.
  • Otros caracteres de control como 0x00 (NULL = C terminador de cadena), 0x03 (FIN DE TEXTO), 0x04 (FIN DE TRANSMISIÓN) o 0x1A (DOS al final del archivo) que pueden señalar prematuramente el final de los datos.
  • Bytes por encima de 0x7F (si el protocolo fue diseñado para ASCII).
  • Secuencias de bytes que son inválidas UTF-8.

Entonces no puedes simplemente enviar datos binarios a través de un protocolo basado en texto. Está limitado a los bytes que representan los caracteres ASCII que no son de espacio libre, de los cuales hay 94. La razón por la que se eligió Base 64 fue que es más rápido trabajar con potencias de dos, y 64 es el más grande que funciona .

Una pregunta sin embargo. ¿Cómo es que los sistemas todavía no están de acuerdo en una técnica de encoding común como el UTF-8 tan común?

En la Web, al menos, en su mayoría lo tienen. La mayoría de los sitios usan UTF-8 .

El problema en Occidente es que hay un montón de software antiguo que ass-u-me-s tiene 1 byte = 1 carácter y no puede funcionar con UTF-8.

El problema en el Este es su apego a codificaciones como GB2312 y Shift_JIS.

Y el hecho de que Microsoft parece que todavía no ha superado haber elegido la encoding UTF incorrecta. Si desea usar la API de Windows o la biblioteca de tiempo de ejecución de Microsoft C, está limitado a UTF-16 o la encoding “ANSI” de la configuración regional. Esto hace que sea doloroso usar UTF-8 porque tiene que convertir todo el tiempo.

Además de las otras respuestas (algo largas): incluso ignorando los sistemas antiguos que solo admiten ASCII de 7 bits, los problemas básicos con el suministro de datos binarios en modo texto son:

  • Los Newlines se transforman típicamente en modo texto.
  • Uno debe tener cuidado de no tratar un byte NUL como el final de una cadena de texto, que es demasiado fácil de hacer en cualquier progtwig con linaje C.

¿Qué significa “medios diseñados para tratar con datos textuales”?

Ya en el día en que ASCII dictaminó que el mundo que lidia con valores que no son ASCII era un dolor de cabeza. La gente saltó a través de todo tipo de aros para transferirlos por el cable sin perder información.

¿Por qué / Cómo usamos la encoding Base64?

Base64 es uno de los esquemas de encoding de binario a texto que tiene una eficiencia del 75%. Se utiliza para que los datos binarios típicos (como las imágenes) puedan enviarse de manera segura a través de canales heredados “no de 8 bits limpios”. En las redes de correo electrónico anteriores (hasta principios de los 90), la mayoría de los mensajes de correo electrónico eran texto sin formato en el juego de caracteres US-ASCII de 7 bits. Muchos estándares de protocolo de comunicación temprana se diseñaron para funcionar a través de enlaces de comunicación de “7 bits” “no de 8 bits limpios”. La eficiencia del esquema es la relación entre el número de bits en la entrada y el número de bits en la salida codificada. Hexadecimal (Base16) es también uno de los esquemas de encoding de binario a texto con un 50% de eficiencia.

Pasos de encoding de Base64 (simplificado):

  1. Los datos binarios se organizan en fragmentos continuos de 24 bits (3 bytes) cada uno.
  2. Cada fragmento de 24 bits se agrupa en cuatro partes de 6 bits cada una.
  3. Cada grupo de 6 bits se convierte en sus valores de caracteres Base64 correspondientes, es decir, la encoding Base64 convierte tres octetos en cuatro caracteres codificados. La relación de bytes de salida a bytes de entrada es 4: 3 (33% de sobrecarga).
  4. Curiosamente, los mismos caracteres se codificarán de manera diferente según su posición dentro del grupo de tres octetos codificado para producir los cuatro caracteres.
  5. El receptor deberá revertir este proceso para recuperar el mensaje original.