¿Por qué usamos Base64?

276

Wikipedia dice

Los esquemas de codificación Base64 se usan comúnmente cuando existe la necesidad de codificar datos binarios que deben almacenarse y transferirse a través de medios diseñados para manejar datos textuales. 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 tienen nuestras máquinas almacena binarios y solo depende de cómo lo interpretes? Entonces, ya sea que codifique el patrón de bits 010011010110000101101110como Manen ASCII o como TWFuen Base64, eventualmente almacenará el mismo patrón de bits.

Si la codificación 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 datos textuales"? Pueden lidiar con binary => pueden lidiar con cualquier cosa.


Gracias a todos, creo que entiendo ahora.

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

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 transferir más datos por la misma cantidad de información, asegura que el receptor puede decodificar los datos de la manera prevista, incluso si el receptor tiene diferentes interpretaciones para el resto del conjunto de caracteres.

Lazer
fuente
66
Antecedentes históricos: los servidores de correo electrónico solían ser ASCII de 7 bits. Muchos de ellos establecerían el bit alto en 0, por lo que solo tenía que enviar valores de 7 bits. Ver en.wikipedia.org/wiki/Email#Content_encoding
Harold L
53
Usamos base64 porque es más legible que Perl
Martin
2
@ Martin, estás bromeando. Perl es difícil de leer, pero base64 no se puede leer en absoluto.
Peter Long
1
@Lazer Falta tu imagen
Mick
2
@Lazer, "Pero el byte 10 podría no interpretarse correctamente como una nueva línea en el otro extremo". ¿por qué? ¡Las dos partes han acordado ASCII y deben interpretarlo correctamente!
ProgramCpp

Respuestas:

299

Su primer error es pensar que la codificación ASCII y la codificación 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 en una secuencia de bytes.
  • Cuando codifica datos en Base64, comienza con una secuencia de bytes y los 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, 0s y 1s, pero las personas generalmente quieren comunicarse con datos de formas más ricas, como texto o imágenes. Para transferir estos datos entre computadoras, primero debe codificarse en 0s y 1s, enviarse y luego descodificarse nuevamente. Para tomar el texto como ejemplo, hay muchas formas diferentes de realizar esta codificación. Sería mucho más simple si todos pudiéramos estar de acuerdo en una sola codificación, pero lamentablemente este no es el caso.

Originalmente, se crearon muchas codificaciones diferentes (por ejemplo, código Baudot ) que usaban 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 consisten en 8 bits cada uno, por lo que ASCII no es adecuado para transferir este tipo de datos. Algunos sistemas incluso borrarían el bit más significativo. Además, la diferencia en las codificaciones de final de línea entre sistemas significa que los caracteres ASCII 10 y 13 también se modificaron a veces.

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

Para enviar mensajes de texto de forma fiable que pueda primera codificación de bytes utilizando una codificación de texto de su elección (por ejemplo, UTF-8) y luego después Base64 codificar los datos binarios resultantes en una cadena de texto que es seguro enviar codificado como ASCII. El receptor tendrá que revertir este proceso para recuperar el mensaje original. Por supuesto, esto 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 en los que el servidor de correo electrónico puede modificar los finales de línea. Un ejemplo más moderno es el uso de la codificación Base64 para incrustar datos de imagen directamente en el código fuente HTML . Aquí es necesario codificar los datos para evitar que caracteres como '<' y '>' se interpreten como etiquetas.


Aquí hay un ejemplo de trabajo:

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 codificar en base 64 estos bytes como una cadena Base64:

SGVsbG8sCndvcmxkIQ ==

Que cuando se codifica 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 algún sistema corrompa este mensaje. Puedo enviar esto en lugar de mi mensaje original y dejar que el receptor invierta el proceso para recuperar el mensaje original.

Mark Byers
fuente
44
"La mayoría de los protocolos de comunicaciones modernos no dañarán los datos", aunque, por ejemplo, el correo electrónico podría hacerlo, con un agente de entrega reemplazando la cadena de caracteres "\ nDe" con "\ n> De" cuando guarda el mensaje en un buzón. O los encabezados HTTP son terminados en línea nueva sin una forma reversible de escapar de las líneas nuevas en los datos (la continuación de la línea combina espacios en blanco), por lo que tampoco puede volcar ASCII arbitrario en ellos. base64 es mejor que solo 7 bits seguro, es alfanumérico y - = + / seguro.
Steve Jessop
1
"La desventaja es que codificar el mensaje usando Base64 aumenta su longitud: cada 3 bytes de datos se codifican en 4 bytes". ¿Cómo aumenta a 4 bytes? ¿No será todavía 3 * 8 = 24 bits solamente?
Lazer
44
@Lazer: no. Mire su propio ejemplo: "Man" está codificado en base 64 como "TWFu". 3 bytes -> 4 bytes. Se debe a que la entrada puede ser cualquiera de los 2 ^ 8 = 256 bytes posibles, mientras que la salida solo usa 2 ^ 6 = 64 de ellos (y =, para ayudar a indicar la longitud de los datos). Se desperdician 8 bits por cuarteto de salida, a fin de evitar que la salida contenga caracteres "emocionantes" aunque la entrada lo haga.
Steve Jessop
3
Puede ser útil repetir "Cuando codifica datos en Base64, comienza con una secuencia de bytes y los convierte en una cadena de texto" como "Cuando codifica datos en Base64, comienza con una secuencia de bytes y los convierte en un secuencia de bytes que consta solo de valores ASCII ". Una secuencia de bytes que consta solo de caracteres ASCII es lo que requiere SMTP, razón por la cual Base64 (y entre comillas) se utilizan como codificaciones de transferencia de contenido. Excelente resumen!
ALEXintlsos
1
Yo votaría, pero tiene 64 votos. Lo siento, esto es perfecto.
Jessé Catrinck el
61

Codificación de datos binarios en XML

Suponga que desea incrustar un par de imágenes en 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 pueda manejar.

En vez de:

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

tú lo haces:

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

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

Yfeldblum
fuente
Así podría ser el .mhtformato antiguo de Microsoft (archivo html + imágenes en un solo archivo).
Sridhar Sarnobat
38

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

La codificación base de datos se usa en muchas situaciones para almacenar o transferir
datos en entornos que, quizás por razones heredadas, están restringidos a datos US-ASCII [1]. La codificación 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, diferentes aplicaciones tenían requisitos diferentes y, por lo tanto, a veces implementaban codificaciones base de maneras ligeramente diferentes. Hoy en día, las especificaciones de protocolo a veces usan codificaciones de base en general, y "base64" en particular, sin una descripción o referencia precisa. Las Extensiones multipropósito de correo de Internet (MIME) [4] se usan a menudo como referencia para base64 sin tener en cuenta las consecuencias de los caracteres de ajuste de línea o no alfabéticos. El propósito de esta especificación es establecer un alfabeto común y consideraciones de codificación. 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 adjunten a correos electrónicos como parte de las Extensiones multipropósito de correo de Internet.

Billy ONeal
fuente
26

Los medios diseñados para datos textuales son, por supuesto, también 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 codificación Base64 codifica los datos binarios como valores que solo pueden interpretarse 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 medios textuales.

Håvard S
fuente
Entonces, al igual que con Base64, principalmente el origen y el destino interpretarán los datos de la misma manera, porque lo más probable es que interpreten estos 64 caracteres de la misma manera, incluso si interpretan los caracteres de control de diferentes maneras. ¿Está bien?
Lazer
66
Estos datos pueden incluso ser destruidos en tránsito. Por ejemplo, muchos programas FTP reescriben los finales de línea del 13,10 al 10 o viceversa si el sistema operativo del servidor y el cliente no coinciden y la transferencia se marca como modo de texto. FTP es solo el primer ejemplo que se me ocurrió, no es bueno porque FTP admite un modo binario.
Hendrik Brummermann
@nhnb: Creo que FTP es un buen ejemplo, ya que muestra que el modo de texto no es adecuado para cosas que desean datos binarios.
jamesdlin
¿Qué es un medio textual?
Koray Tugay
18

Es más que los medios validan la codificación de la cadena, por lo que queremos asegurarnos de que los datos sean aceptables por una aplicación de manejo (y no contengan una secuencia binaria que represente EOL, por ejemplo)

Imagine que desea enviar datos binarios en un correo electrónico con codificación 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 codificación 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 estamos haciendo es asegurarnos de que haya un mapeo 1 a 1 entre una secuencia de bits buena, aceptable y no perjudicial conocida a otra secuencia literal de bits, y que la aplicación de manejo no distinga la codificación.

En su ejemplo, manpuede ser ASCII válido en primera forma; pero a menudo puede querer transmitir valores que sean 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"
Tipo de contenido: imagen / gif; name = "a.gif"
Content-Transfer-Encoding: Base64
Content-Disposition: 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 lo decodifica. Debido a la codificación, podemos estar seguros de que el GIF no contiene nada que pueda interpretarse como protocolo y evitamos insertar datos que SMTP o POP puedan encontrar significativos.

Aiden Bell
fuente
1
Eso es increíble: esta explicación lo hizo clic. No es para ofuscar o comprimir datos, sino simplemente para evitar el uso de secuencias especiales que pueden interpretarse como protocolo.
Patrick Michaelsen
13

Base64 en lugar de escapar caracteres especiales

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

Pero quiero que mi ID haga referencia 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, desde signos de exclamación, caracteres acentuados, tilde, ¡incluso emoji! No puedo hacer esto:

<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>

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é idioma permite qué caracteres especiales y cuáles necesitan escapar:

document.getElementById("18GerPD8fY4iTbNpC9hHNXNHyrDMampPLA");

A diferencia del uso de un MD5 o alguna otra función de hash, puede invertir la codificación para averiguar exactamente qué datos fueron realmente útiles.

Desearía saber sobre Base64 hace años. Hubiera evitado arrancarme el pelo con ' encodeURIComponent' ystr.replace(‘\n’,’\\n’)

Transferencia de texto SSH:

Si está tratando de pasar datos complejos a través de ssh (por ejemplo, un archivo de puntos para que pueda obtener sus personalizaciones de shell), buena suerte haciéndolo sin Base 64. Así es como lo haría con base 64 (sé que puede usar SCP, pero eso requeriría múltiples comandos, lo que complica las combinaciones de teclas para sshing en un servidor):

Sridhar Sarnobat
fuente
12

Un ejemplo de cuando me pareció conveniente fue cuando trataba de incrustar datos binarios en XML . El analizador SAX malinterpretó algunos de los datos binarios porque esos datos podrían ser literalmente cualquier cosa, incluidos caracteres especiales XML. La base64 que codifica los datos en el extremo transmisor y los decodifica en el extremo receptor solucionó ese problema.

Bill el lagarto
fuente
1
+1 - pero esto no es de ninguna manera específico de SAX. Le sucedería a cualquier analizador XML, es decir, DOM o XLINQ.
Billy ONeal
1
@ Billy: Sí, absolutamente. Simplemente estaba usando un analizador SAX para esa aplicación.
Bill the Lizard
Diferentes motores, por ejemplo, el analizador SAX podrían interpretar algunos de los valores ASCII de diferentes maneras (diferentes caracteres de control). Entonces, la idea aquí es usar el subconjunto de ASCII que tiene el significado común universalmente. ¿Correcto?
Lazer
1
@Lazer: Correcto. Los datos binarios sin codificar tendrán caracteres de control por casualidad cuando intente interpretarlos como ASCII (que en este caso no era).
Bill the Lizard
10

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 quizás 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.

casablanca
fuente
3
¿Por qué es un problema si la transmisión se interrumpe después de 7 bits? Al final, la otra máquina tendrá todos los datos recibidos a través de la transmisión, ¿entonces puede elegir el formato de 8 bits para mostrarlos? ¿Qué le pasa a mi mente?
mallaudin
6

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 de texto son:

  • Las nuevas líneas generalmente se transforman en modo texto.
  • Hay que tener cuidado de no tratar un byte NUL como el final de una cadena de texto, lo cual es demasiado fácil de hacer en cualquier programa con linaje C.
jamesdlin
fuente
También hay caracteres de control como ^ C, ^ D y ^ Z que se interpretan como el final del archivo en algunas plataformas.
dan04
5

¿Qué significa "medios diseñados para tratar 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 lidiar con binary => pueden lidiar con cualquier cosa.

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

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

Por lo tanto, no puede simplemente enviar datos binarios a través de un protocolo basado en texto. Está limitado a los bytes que representan los caracteres ASCII sin control sin espacio, 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 con una técnica de codificación común como el tan común UTF-8?

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 una gran cantidad de software antiguo que tiene ese carácter de 1 byte = 1 y no puede funcionar con UTF-8.

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

Y el hecho de que Microsoft parece no haberse superado después de haber elegido la codificación UTF incorrecta. Si desea utilizar la API de Windows o la biblioteca de tiempo de ejecución de Microsoft C, está limitado a UTF-16 o la codificación "ANSI" de la configuración regional. Esto hace que sea doloroso usar UTF-8 porque tienes que convertir todo el tiempo.

dan04
fuente
5

¿Por qué / cómo utilizamos la codificación Base64?

Base64 es uno de los esquemas de codificación de binario a texto que tiene un 75% de eficiencia. Se utiliza para que los datos binarios típicos (como las imágenes) se puedan enviar de forma segura a través de canales heredados "no limpios de 8 bits". En redes de correo electrónico anteriores (hasta principios de la década de 1990), la mayoría de los mensajes de correo electrónico eran texto sin formato en el conjunto de caracteres US-ASCII de 7 bits. Muchos de los primeros estándares de protocolo de comunicación fueron diseñados para funcionar a través de enlaces de comunicación de "7 bits" "no limpios de 8 bits". 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) también es uno de los esquemas de codificación de binario a texto con un 50% de eficiencia.

Pasos de codificación Base64 (simplificados):

  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 codificación 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 dependiendo de su posición dentro del grupo de tres octetos que se codifica para producir los cuatro caracteres.
  5. El receptor tendrá que revertir este proceso para recuperar el mensaje original.
Mushtaq Hussain
fuente
3

¿Qué significa "medios diseñados para tratar datos textuales"?

En el día en que ASCII gobernaba el mundo, lidiar con valores no ASCII era un dolor de cabeza. La gente saltó a través de todo tipo de aros para transferirlos a través del cable sin perder información.

Dirkgently
fuente
3
En realidad, en el pasado, ASCII ni siquiera se usaba en todas partes. Muchos protocolos tenían un modo de texto y un modo binario separados para transferir datos, desafortunadamente el correo electrónico no existía en ese entonces. El modo de texto es necesario precisamente porque ninguna codificación de texto gobernó el mundo, no ASCII; cada red de computadoras tiene su propia codificación favorita, por lo que hay puertas de enlace cuyo trabajo es convertir el texto intercambiado a la codificación local para que una empresa japonesa pueda enviar correos electrónicos a un consultor de negocios estadounidense sin mojibake. Esta conversión, obviamente, no es deseable cuando se envían datos binarios.
Lie Ryan