El módulo base64 en Python convierte bytes binarios en caracteres ASCII imprimibles y realiza la operación inversa. Permite transportar imágenes, identificadores, claves y pequeños blobs a través de formatos orientados a texto como JSON, archivos de configuración, cabeceras y algunos componentes de URL.
Base64 es una codificación, no cifrado. Cualquier persona que vea la cadena puede recuperar los bytes originales. Tampoco autentica al remitente ni protege la integridad de forma fiable. Para confidencialidad usa cifrado; para autenticidad usa MAC o firmas.
Codificación básica
import base64
datos = b"mensaje binario\x00\xff"
codificado = base64.b64encode(datos)
restaurado = base64.b64decode(codificado)
assert restaurado == datos
print(codificado)Las funciones reciben objetos bytes-like y devuelven bytes ASCII. Para guardar el resultado en JSON, convierte en el límite:
texto = base64.b64encode(datos).decode("ascii")
original = base64.b64decode(texto)Base64 aumenta el tamaño
Tres bytes de origen se representan con cuatro caracteres, creando aproximadamente un 33 por ciento de overhead. Base64 no comprime. Si el canal exige texto y el tamaño importa, comprime primero con un formato adecuado como zlib en Python y después codifica.
Decodificación estricta
Por defecto, b64decode() descarta caracteres fuera del alfabeto antes de comprobar el padding. Esto puede servir para texto MIME con saltos de línea, pero también aceptar basura inesperada. En APIs y tokens, utiliza validate=True:
import base64
import binascii
try:
datos = base64.b64decode(valor, validate=True)
except (binascii.Error, ValueError) as error:
raise ValueError("Base64 inválido") from errorLimita además la longitud de entrada y salida. Una cadena enorme puede agotar memoria antes de que los bytes decodificados sean inspeccionados.
Padding
El signo = completa el último grupo. Algunos protocolos URL-safe lo eliminan. Restaura únicamente lo necesario y documenta la regla:
import base64
def decodificar_sin_padding(texto: str) -> bytes:
if len(texto) > 10_000:
raise ValueError("entrada demasiado larga")
padding = "=" * (-len(texto) % 4)
return base64.urlsafe_b64decode(texto + padding)No agregues padding arbitrario sin validar alfabeto y longitud. Un protocolo debe indicar si es obligatorio, opcional o prohibido.
Base64 URL-safe
urlsafe_b64encode() sustituye + por - y / por _:
import base64
identificador = base64.urlsafe_b64encode(b"archivo/2026+version")
print(identificador)
print(base64.urlsafe_b64decode(identificador))La salida todavía puede contener =. URL-safe describe el alfabeto, no la compatibilidad automática con cualquier path o query. Construye URLs completas con urllib.parse en Python.
Alfabetos alternativos
b64encode() acepta dos bytes alternativos para + y /:
import base64
personalizado = base64.b64encode(b"datos", altchars=b"-_")
original = base64.b64decode(personalizado, altchars=b"-_", validate=True)Usa las funciones URL-safe para el alfabeto estándar de URLs. Un alfabeto propio reduce interoperabilidad y debe documentarse.
Archivos binarios en JSON
import base64
import json
from pathlib import Path
ruta = Path("icono.png")
contenido = ruta.read_bytes()
if len(contenido) > 2 * 1024 * 1024:
raise ValueError("el archivo supera el límite")
payload = json.dumps({
"nombre": ruta.name,
"contenido_base64": base64.b64encode(contenido).decode("ascii"),
})Para archivos grandes, utiliza upload binario, multipart o almacenamiento de objetos. Base64 aumenta tráfico y puede mantener simultáneamente bytes originales, texto y bytes restaurados.
Data URLs
import base64
datos = b"..."
tipo = "image/png"
data_url = f"data:{tipo};base64,{base64.b64encode(datos).decode('ascii')}"No confíes en el tipo declarado. Valida el formato real y aplica una allowlist. Una Data URL puede transportar HTML, SVG o scripts y provocar XSS si se inserta sin una política adecuada.
Base32
import base64
codigo = base64.b32encode(b"secreto temporal")
print(codigo)
print(base64.b32decode(codigo))Base32 utiliza un alfabeto más pequeño y legible. b32decode() rechaza minúsculas por defecto. casefold=True las acepta. map01 permite mapear caracteres visualmente parecidos, pero el valor seguro es rechazar sustituciones ambiguas.
Base32 Hex
b32hexencode() y b32hexdecode() usan el alfabeto hexadecimal extendido de RFC 4648. Los dígitos 0 y 1 forman parte real del alfabeto y no se sustituyen por letras.
Base16
import base64
hexadecimal = base64.b16encode(b"ABC")
print(hexadecimal)
print(base64.b16decode(hexadecimal))La decodificación acepta mayúsculas por defecto. Activa casefold solo si el protocolo permite minúsculas. Para identificadores hexadecimales normales, bytes.hex() y bytes.fromhex() pueden ser más directos.
Ascii85, Base85 y Z85
Las familias Base85 representan cuatro bytes con cinco caracteres y tienen menos overhead que Base64. Python ofrece variantes incompatibles:
a85encode(): Ascii85 para PostScript y PDF.b85encode(): variante utilizada por herramientas como Git.z85encode(): Z85 de ZeroMQ, disponible desde Python 3.13.
import base64
datos = b"12345678"
print(base64.a85encode(datos))
print(base64.b85encode(datos))
print(base64.z85encode(datos))No son intercambiables. Sigue la especificación externa para alfabeto, padding, marcadores y espacios.
Reglas de longitud de Z85
Z85 exige entrada múltiplo de cuatro y salida múltiplo de cinco. Si añades padding, conserva también la longitud original o define una regla inequívoca para eliminarlo.
Interfaz MIME antigua
encodebytes() inserta saltos de línea cada 76 caracteres. Para mensajes de correo completos, usa el paquete email, que gestiona cabeceras, transfer encoding y multipart. Las funciones modernas son mejores para APIs.
HTTP Basic Authentication
Basic Authentication codifica usuario:contraseña con Base64. La codificación no protege las credenciales; TLS proporciona confidencialidad durante el transporte.
import base64
credenciales = "usuario:contraseña".encode("utf-8")
header = "Basic " + base64.b64encode(credenciales).decode("ascii")No registres el header y evita contraseñas compartidas de larga duración.
No almacenes contraseñas con Base64
Una contraseña codificada equivale a texto plano. Usa un algoritmo de hash para contraseñas con salt y coste configurable. Las claves y tokens deben almacenarse cifrados o en un gestor de secretos.
Tokens firmados
JWT utiliza Base64URL para representar secciones, pero la seguridad proviene de la firma o MAC. Decodificar un token no lo verifica. Comprueba algoritmo, clave, firma, issuer, audience, expiración y claims con una biblioteca adecuada.
Decodificación con límites
import base64
import binascii
MAX_TEXTO = 4 * 1024 * 1024
MAX_SALIDA = 3 * 1024 * 1024
def decodificar_limitado(texto: str) -> bytes:
if len(texto) > MAX_TEXTO:
raise ValueError("Base64 supera el límite")
try:
datos = base64.b64decode(texto, validate=True)
except binascii.Error as error:
raise ValueError("Base64 inválido") from error
if len(datos) > MAX_SALIDA:
raise ValueError("la salida supera el límite")
return datosLa relación de tamaños ayuda a calcular un máximo, pero los bytes resultantes todavía deben validarse según el formato declarado.
Comparación constante
Si los bytes son un MAC o firma esperada, compara con hmac.compare_digest() después de validar longitud y formato. Esto reduce diferencias de tiempo de una igualdad normal.
Payloads binarios estructurados
Base64 transporta bytes, pero no define el layout. Usa struct en Python para cabeceras versionadas con magic y límites. Los lotes pueden procesarse con queue en Python para aplicar backpressure.
Pruebas recomendadas
Prueba entrada vacía, longitudes módulo cuatro, padding ausente o excesivo, caracteres inválidos, Unicode no ASCII, alfabetos estándar y URL-safe, límites, caracteres ambiguos de Base32, padding de Base85, round trips aleatorios y vectores de RFC 4648.
Buenas prácticas
- Trabaja internamente con bytes.
- Convierte a ASCII en el límite.
- Usa
validate=True. - Define límites antes y después.
- Selecciona el alfabeto según la especificación.
- No confundas encoding con seguridad.
- No registres credenciales ni tokens.
- Valida los bytes decodificados.
Conclusión
base64 en Python ofrece Base16, Base32, Base64, Ascii85, Base85 y Z85 para transportar bytes en canales textuales. La API es simple, pero los sistemas robustos necesitan validación estricta, límites y un protocolo claro.
Consulta la documentación oficial de base64 y la RFC 4648. La codificación resuelve representación; confidencialidad y autenticidad requieren herramientas específicas.







