Portada de UrsaKit que explica cómo la codificación Base64 convierte bytes en caracteres imprimibles

Base64 aparece por todas partes -adjuntos de correo, data URLs, payloads JSON, segmentos JWT y campos de API que transportan un archivo- y normalmente se pega de un sitio a otro sin que nadie pregunte qué hace. Esta guía explica la codificación en sí: por qué existe, la aritmética exacta, de dónde sale el padding y en qué casos usar Base64 es la decisión equivocada.

Puedes seguirla en el codificador y decodificador Base64 de UrsaKit. La codificación y la decodificación se ejecutan en tu navegador, así que puedes pegar tokens reales mientras lees.

01Por qué existe Base64

Muchos transportes se diseñaron para texto y solo prometen transportar un conjunto limitado de caracteres imprimibles. Los cuerpos de correo, las cabeceras HTTP, los nodos de texto XML y las rutas de URL tienen caracteres que tratan como especiales. Un JPEG en bruto o un archivo comprimido contiene todos los valores de byte de 0 a 255, incluidos caracteres de control y bytes que un canal de texto estropeará sin problema.

Base64 resuelve exactamente un problema: reexpresa bytes arbitrarios usando 64 caracteres imprimibles que son seguros en cualquier canal de texto. RFC 4648 define el esquema y señala que el carácter número 65, el signo igual, sirve para indicar padding y no datos.

A-Z  a-z  0-9  +  /      (alfabeto estándar, 64 símbolos)
- y _ sustituyen a + y /  (alfabeto URL-safe, RFC 4648 sección 5)
= rellena el último grupo

Los caracteres se eligieron porque sobreviven a las pasarelas de correo, al parseo HTML y al copiar y pegar. El alfabeto es una prenda de transporte, no cifrado y no arte ASCII.

02La regla de 3 bytes a 4 caracteres

Un byte tiene 8 bits, así que tres bytes tienen 24 bits. Sesenta y cuatro símbolos representan log2(64) = 6 bits cada uno. Por tanto, cuatro símbolos de 6 bits contienen exactamente 24 bits. La sección 4 de RFC 4648 dice lo mismo en una frase: la codificación representa grupos de 24 bits de entrada como cadenas de salida de 4 caracteres codificados. Ese es todo el diseño: entran 3 bytes, salen 4 caracteres.

"Man"  ->  bytes 4D 61 6E  ->  010011 010110 000101 101110  ->  TWFu
"Ma"   ->  bytes 4D 61     ->  010011 010110 0001(00)      ->  TWE=
"M"    ->  bytes 4D        ->  010011 01(0000)             ->  TQ==

Esos tres ejemplos se generaron en local con el codificador base64 de la biblioteca estándar de Python 3 el 2026-10-04. El último grupo tiene menos de 24 bits, así que los bits que faltan se ponen a cero y los caracteres que sobran se sustituyen por un signo igual. La sección 3.2 de RFC 4648 exige ese padding salvo que la especificación que lo referencia diga lo contrario, y RFC 7515 es justo esa excepción para JWT: elimina todos los caracteres de padding finales.

La consecuencia práctica es el sobrecoste de tamaño. La sección 6.8 de RFC 2045, que define Base64 para el correo MIME, sitúa los datos codificados en "consistentemente solo un 33 por ciento más grandes que los datos sin codificar". Un archivo real muestra la misma proporción:

archivo original   63.728 bytes
salida base64      84.972 caracteres   ->  33,34% más

La medición es la portada de UrsaKit publichttps://static.ursakit.com/media/861934dec6614009.jpg, codificada en local con Python el 2026-10-04. Una imagen de 3 MB se convierte por tanto en unos 4 MB de texto, y eso antes de las comillas de JSON. Si controlas ambos extremos, envía el archivo como multipart/form-data o como bytes en bruto por HTTP.

03Padding y el alfabeto URL-safe

Base64 estándar contiene signo más y barra. En una URL, el signo más se decodifica como espacio y la barra es un separador de ruta; en un nombre de archivo, la barra es ilegal. La sección 5 de RFC 4648 define un alfabeto seguro para URL y nombres de archivo que los cambia por guion y guion bajo:

Bytes de entradaEstándarURL-safe
0xFB 0xFF+/8=-_8=
0xFF 0xEF/+8=_-8=
cadena Hi?SGk/SGk_

Los seis valores se generaron en local con base64.b64encode y base64.urlsafe_b64encode de Python el 2026-10-04. El padding también se omite a menudo en modo URL-safe, porque un segmento de URL o un token estructurado puede llevar su propia longitud. JWT usa el alfabeto URL-safe sin padding, y por eso un segmento de cabecera se ve como eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 y nunca termina en signo igual.

Los alfabetos estándar y URL-safe no son intercambiables.

Decodificar la cadena URL-safe -_8= con un decodificador estándar falla o devuelve bytes equivocados, y decodificar +/8= con uno URL-safe tiene el mismo problema. Comprueba cuál usó quien lo generó antes de depurar otra cosa.

04Base64 no es cifrado

Base64 no tiene clave ni secreto. Decodificar es una búsqueda en una tabla que cualquiera puede hacer, así que una cadena Base64 es mejor imaginarla como otra tipografía para los mismos bytes.

Trata como texto plano: una contraseña "ofuscada" con Base64, una clave de API envuelta en Base64 dentro de un archivo de configuración, un registro personal escondido en una data URL. Si los datos deben ser ilegibles, usa cifrado de verdad -TLS en el transporte, AES-GCM o equivalente en reposo- y recuerda que el texto cifrado también irá codificado en Base64 cuando se transmita.

El mismo razonamiento vale para la integridad. Base64 no detecta corrupción más allá de la comprobación del alfabeto; nada en el formato te dice si un byte se giró en tránsito. La sección 12 de RFC 4648 avisa además de lo contrario: un decodificador que ignora en silencio los caracteres fuera del alfabeto en lugar de rechazarlos abre un canal encubierto que puede usarse para filtrar datos. Rechaza la entrada inválida y usa un hash o un MAC para la integridad.

05Decodificar: primero bytes, después texto

Un decodificador devuelve bytes, no una cadena. Convertir esos bytes en texto legible es una segunda decisión, y de ahí viene el clásico "el texto decodificado muestra caracteres raros".

El carácter visible é tiene bytes distintos según la codificación:

UTF-8 "é"        -> bytes C3 A9 -> "w6k="
ISO-8859-1 "é"   -> byte  E9    -> "6Q=="

Ambas cadenas son correctas; solo describen secuencias de bytes diferentes. Verificado en local con Python el 2026-10-04. Al decodificar, elige el charset que usó quien generó la cadena. Si no lo sabes, prueba UTF-8 primero: es el valor por defecto en la web y sus reglas de secuencias inválidas hacen que un error se note rápido.

Dos trampas más al decodificar:

  • Doble codificación. Codificar una cadena ya codificada produce Base64 válido que decodifica a otra cadena Base64. Si la salida parece Base64, decodifica una vez más antes de asumir corrupción.
  • Espacios en blanco. Los saltos de línea y espacios los ignoran casi todos los decodificadores, y RFC 2045 exige que los codificadores MIME partan la salida en líneas de no más de 76 caracteres. Un decodificador estricto que rechaza un salto de línea necesita que le quites el formato primero.

06Cómo reconocer Base64 en el mundo real

Ese mismo alfabeto denso y sin espacios es una señal útil cuando lees un log, un archivo de configuración o un ticket y algo parece un muro de caracteres aleatorios. Cuatro comprobaciones separan un blob Base64 real de un token cualquiera:

  1. Alfabeto. Cada carácter es una letra mayúscula o minúscula, un dígito, y además más barra (estándar) o guion guion bajo (URL-safe). Una cadena con espacios, puntuación o caracteres no ASCII no es Base64.
  2. Longitud. Con padding, la longitud es múltiplo de cuatro. Sin padding, es un múltiplo de cuatro menos 0, 1 o 2 caracteres. Cualquier otra cosa está truncada o mal copiada.
  3. Padding. Cero, uno o dos signos igual al final, nunca en medio.
  4. Contexto. Una data URL empieza con un tipo de medio y el marcador base64, y un JSON Web Token son tres segmentos base64url unidos por puntos. MDN documenta la sintaxis de data URL como data:[<mediatype>][;base64],<data>.

Estas comprobaciones te dicen que una cadena podría ser Base64. No te dicen qué contiene ni si es maliciosa: un blob decodificado puede ser una imagen, un archivo comprimido o una carga que alguien codificó para saltarse un filtro. Decodifícalo en una herramienta de confianza y nunca ejecutes el resultado como código.

07Errores que rompen los decodificadores

SíntomaCausaSolución
Invalid character en la posición 0La entrada empieza con un prefijo de data URL como data:image/png;base64,Quita todo hasta la coma incluida
La imagen decodificada no abreLa cadena se truncó al copiar, o los caracteres URL-safe se sustituyeron por más y barraVuelve a copiar la cadena completa; revisa el alfabeto
La salida es ilegibleCharset equivocado para los bytes decodificadosDecodifica como UTF-8 o elige el charset original
Error de padding en un segmento JWTJWT omite el padding de signos igualAñade padding hasta un múltiplo de 4 antes de decodificar
El tamaño creció y la API lo rechazóSe envió Base64 donde se esperaban bytes en brutoEnvía el archivo como subida multipart

08Cuándo usar otra cosa

NecesidadMejor que Base64
Enviar un archivo entre serviciosmultipart/form-data o un cuerpo binario en bruto
Guardar bytes dentro de JSONBase64 es la respuesta estándar; JSON no tiene literales binarios
Mantener un secreto ilegibleAES-GCM u otro cifrado autenticado
Codificar bytes arbitrarios en una URLPercent-encoding para valores cortos, Base64url para blobs opacos
Comparar o indexar bytesHex: el doble de largo, pero legible y ordenable

09Codificar y decodificar en el navegador

La herramienta Base64 de UrsaKit cubre el flujo completo sin subir nada:

  1. Elige la dirección - Codificar o decodificar. El espacio de trabajo cambia al modo de entrada correspondiente.
  2. Elige texto o archivo - Pega texto o suelta un archivo como una imagen o un PDF. La entrada por archivo evita el truncado del copiar y pegar que rompe las cadenas largas.
  3. Ajusta el alfabeto si lo necesitas - URL-safe sustituye los signos más y barra, el salto a 76 inserta líneas MIME y el modo en vivo vuelve a codificar mientras escribes.
  4. Revisa el charset al decodificar - La detección automática reconoce una cadena Base64 simple o una data URL completa; si el texto se ve mal, cambia entre UTF-8 y charsets de un byte.
  5. Copia o descarga el resultado - El lado decodificado puede guardarse como archivo, que es la forma fiable de recuperar una imagen codificada.

Cuando la cadena esté correcta, el resto del proceso suele ser JSON: compruébalo con el formateador de JSON antes de enviarlo.

10Fuentes

Preguntas frecuentes

¿Base64 reduce el tamaño de mis datos?

No, lo aumenta. Cada 3 bytes se convierten en 4 caracteres, y RFC 2045 describe los datos codificados como consistentemente un 33 por ciento más grandes antes de la compresión del transporte.

¿Base64 es cifrado?

No. Base64 es una codificación reversible sin clave. Cualquiera que tenga la cadena puede decodificarla, así que nunca debe usarse para proteger contraseñas, tokens o datos personales.

¿Por qué mi cadena Base64 termina con uno o dos signos igual?

Los signos igual rellenan el último grupo hasta cuatro caracteres. RFC 4648 exige padding en el caso general, porque permite al decodificador saber cuántos bits había en el último grupo. Las entradas cuya longitud es divisible por tres no necesitan padding.

¿Por qué al decodificar salen caracteres raros?

Los bytes se decodificaron como UTF-8 pero se escribieron originalmente en una codificación de un byte como ISO-8859-1, o al revés. Elige el charset que corresponda al origen.

¿Cuándo debo usar Base64 URL-safe?

Siempre que el resultado viaje en una URL, un nombre de archivo, una query string o un JWT. La sección 5 de RFC 4648 sustituye los signos más y barra por guion y guion bajo; RFC 7515 además elimina el padding final en los segmentos JWT.

¿Importan los saltos de línea en un archivo Base64?

Al decodificador no, pero RFC 2045 exige que la salida base64 de MIME se parta en líneas de no más de 76 caracteres. El salto de línea es una convención de transporte, no parte de la codificación, y los decodificadores lo ignoran.

¿Cómo distingo si una cadena es Base64?

Busca el alfabeto (letras mayúsculas y minúsculas, dígitos, y más barra o guion guion bajo), una longitud múltiplo de cuatro cuando hay padding, y ausencia total de espacios. El segmento de cabecera de un JWT suele empezar por eyJ, que es el base64url de los primeros caracteres de un objeto JSON.

Volver a los artículos

Artículos relacionados

Herramientas relacionadas