FlawOpen

flawopen.com/Deserialización insegura/Seguridad de pickle en Python

¿Es seguro pickle.load() de Python con datos no confiables?

CWE-502: Deserialización de Datos No ConfiablesPágina de referencia
Respuesta breve

No. Trata pickle como un programa dentro de un paquete, no como un registro pasivo: al cargarlo puede ejecutarse el comportamiento de reconstrucción antes de que la aplicación valide el objeto. Usa un formato de solo datos para entradas que cruzan un límite de confianza.

INSEGURO — bytes no confiables pueden activar código al cargarse
import pickle

# Never accept pickle bytes from a request, upload,
# shared cache, or other untrusted source.
obj = pickle.loads(untrusted_bytes)
ALTERNATIVA MÁS SEGURA — analiza datos y valida el esquema
import json

def parse_profile(raw: bytes) -> dict[str, str]:
    if len(raw) > 65_536:
        raise ValueError("Payload too large")

    try:
        value = json.loads(raw)
    except (json.JSONDecodeError, UnicodeDecodeError):
        raise ValueError("Invalid JSON") from None

    if not isinstance(value, dict) or set(value) - {"display_name", "theme"}:
        raise ValueError("Invalid profile")

    name = value.get("display_name")
    theme = value.get("theme")
    if not isinstance(name, str) or len(name) > 80:
        raise ValueError("Invalid display name")
    if theme not in {"light", "dark"}:
        raise ValueError("Invalid theme")

    return {"display_name": name, "theme": theme}
Flujo pickle:
Secuencia de bytes propia de Python que describe la reconstrucción de objetos, incluidas referencias a globales y comportamiento de reconstrucción.
Unpickling:
Interpretar el flujo y reconstruir su grafo de objetos; el proceso puede invocar funciones.
Límite de confianza:
Punto donde un usuario, servicio, carga o almacén compartido puede controlar o alterar bytes.
CWE-502:
Deserialización de datos no confiables; el impacto depende de que un atacante pueda suministrar o alterar lo que carga la aplicación.
Paso 1

Bytes no confiables llegan a pickle

Una carga, solicitud, caché o artefacto puede introducir datos pickle controlados o alterados en el proceso.

Paso 2

El unpickler resuelve globales

El intérprete procesa instrucciones de reconstrucción; find_class() puede importar y devolver globales nombrados, incluidas funciones.

Paso 3

La carga activa comportamiento

Las instrucciones pueden invocar funciones durante load() o loads(), antes de validar el objeto devuelto.

Paso 4

El impacto depende de los permisos del proceso

El comportamiento usa los permisos del proceso Python. La red, los secretos, el sistema de archivos y el aislamiento limitan su alcance.

Por qué cargar pickle cruza un límite de ejecución de código

Un flujo pickle puede nombrar globales y funciones de reconstrucción. Durante el unpickling, Unpickler.find_class() resuelve globales, incluidas funciones; los opcodes pueden invocar la reconstrucción. El paso peligroso es pickle.load() o pickle.loads(): no hay una llamada posterior separada para ejecutar. El código resultante usa los permisos del proceso. Es un comportamiento documentado del formato; no uses pickle para intercambiar datos no confiables.

Qué resuelve JSON y qué no

La documentación de Python advierte que cargar datos pickle no confiables o alterados puede ejecutar código arbitrario, mientras que decodificar JSON no crea por sí solo esa vía de ejecución. JSON no valida entradas automáticamente: limita el tamaño, exige el tipo superior y los campos esperados, valida valores con un esquema y aplica autorización por separado. Si un flujo heredado aún necesita pickle, autentica los bytes exactos con una clave protegida antes de cargarlos; una firma solo demuestra origen e integridad bajo las premisas de esa clave, y no vuelve seguro el contenido malicioso firmado por una fuente confiable. Migra a un formato de solo datos.

Preguntas frecuentes

¿Un Unpickler restringido hace seguro el pickle controlado por atacantes?

Sobrescribir find_class() puede reducir riesgos al restringir globales, pero demostrar que un cargador es seguro para todos los protocolos y comportamientos alcanzables es difícil. No uses una lista de permitidos como defensa predeterminada para bytes controlados por usuarios; prefiere un formato de solo datos.

¿También hay que validar JSON?

Sí. JSON evita la ejecución arbitraria propia de pickle al decodificar, pero la aplicación aún debe validar tipos, campos, tamaños, rangos y autorización. Separa el análisis JSON de las reglas de negocio.

Referencias primarias

Véase también Deserialización insegura: riesgos y defensa ¿Es seguro Ruby YAML.load? Versiones de Psych y safe_load .NET BinaryFormatter: riesgos y migración ObjectInputStream en Java: deserialización segura Newtonsoft.Json TypeNameHandling: ¿configuración segura? PHP unserialize() y datos no confiables