flawopen.com/Deserialización insegura/Seguridad de pickle en Python
¿Es seguro pickle.load() de Python con datos no confiables?
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.
import pickle # Never accept pickle bytes from a request, upload, # shared cache, or other untrusted source. obj = pickle.loads(untrusted_bytes)
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.
Bytes no confiables llegan a pickle
Una carga, solicitud, caché o artefacto puede introducir datos pickle controlados o alterados en el proceso.
El unpickler resuelve globales
El intérprete procesa instrucciones de reconstrucción; find_class() puede importar y devolver globales nombrados, incluidas funciones.
La carga activa comportamiento
Las instrucciones pueden invocar funciones durante load() o loads(), antes de validar el objeto devuelto.
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.
- ✓Elimina
pickle.load()ypickle.loads()de rutas que reciben solicitudes, cargas, cachés compartidas o artefactos de procedencia incierta. - ✓Usa JSON u otro formato de solo datos y aplica límites de tamaño, esquema, campos permitidos, rangos de valores y autorización del endpoint.
- ✓Si un flujo interno confiable conserva pickle temporalmente, verifica HMAC o firma de los bytes exactos antes de cargar, protege la clave y limita los permisos del proceso.
- ✓Busca consumidores de pickle en el código y los flujos; determina quién puede escribir o alterar cada origen y migra o aísla los usos inseguros.
Preguntas frecuentes
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.
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
- Documentación Python — aviso de seguridad de pickle y globales restringidos
- Documentación Python — decodificador JSON
- CWE-502 — Deserialización de Datos No Confiables