Inyección de código en Python: ejemplos y prevención
Lucien Chemaly
6 de diciembre de 2023
0 minutos de lecturaA medida que el software se vuelve cada vez más esencial en nuestra vida profesional y personal, también aumenta la necesidad de proteger la información y los sistemas contra ataques maliciosos. Una de las amenazas críticas que deben afrontar quienes desarrollan en Python es el riesgo de inyección de código, una forma sofisticada y a menudo devastadora de ciberataque.
La inyección de código es un problema generalizado que trasciende los lenguajes de programación y las plataformas, pero puede manifestarse de manera especialmente sutil y peligrosa en las aplicaciones de Python.
Como uno de los lenguajes más utilizados para el desarrollo web, el análisis de datos y la automatización, Python ofrece una amplia variedad de funciones y bibliotecas que pueden ser tanto una ventaja como un riesgo. Aunque permite crear sistemas sólidos y eficientes, también ofrece numerosas oportunidades para que los atacantes exploten vulnerabilidades si no se siguen estrictamente las convenciones de programación segura.
El desafío de prevenir la inyección de código en Python se intensifica aún más por el auge y el uso generalizado de componentes y paquetes de código abierto. Estos recursos disponibles aceleran el desarrollo; sin embargo, pueden contener fallas de seguridad ocultas que se pueden explotar para inyectar código.
En este artículo, conocerás los peligros y la importancia de las convenciones de programación segura, en especial en lo que respecta a las vulnerabilidades de inyección de código y cómo se manifiestan en las aplicaciones de Python. Al comprender la naturaleza de la inyección de código y adoptar las prácticas recomendadas de programación segura, puedes contribuir a un ecosistema digital más seguro y proteger tus aplicaciones de posibles brechas.
¿Qué es la inyección de código?
La inyección de código es un ataque sigiloso en el que se inserta código malicioso en un sistema de software para que ejecute comandos no deseados. Al explotar vulnerabilidades, un atacante puede inyectar código dañino y provocar consecuencias graves, como el acceso no autorizado a datos, fraude financiero o la toma total del control del sistema.
Estas vulnerabilidades suelen aparecer cuando una aplicación maneja mal los datos que ingresan los usuarios. Por ejemplo, el uso inseguro de funciones como eval() en Python, sin una validación adecuada, puede provocar una inyección de código. También puede ocurrir al crear código a partir de datos de usuario sin las comprobaciones necesarias, usar código de terceros sin revisar su seguridad o tener vulnerabilidades en la configuración de frameworks web o bases de datos.
Comprender la inyección de código es esencial para quienes trabajan en el desarrollo de software o la seguridad. Para ello, veamos en detalle algunas vulnerabilidades comunes que podrías encontrar.
Vulnerabilidades comunes que pueden provocar una inyección de código
Las vulnerabilidades que pueden provocar una inyección de código son un motivo de preocupación importante en el desarrollo de software. Comprenderlas y abordarlas es fundamental para crear sistemas seguros. En las siguientes secciones, conocerás algunas de las principales causas de la inyección de código y cómo protegerte.
Explotación de datos controlados por el usuario
Cuando se usan datos ingresados por el usuario directamente y sin validarlos, un atacante puede ingresar código Python como entrada y la aplicación lo ejecuta. Por ejemplo, observa este código:
Si los atacantes quisieran explotar este código, podrían ingresar algo como ' OR '1'='1'; DROP TABLE users;. El punto y coma (;) termina la consulta original, y el código SQL que viene después se convierte en una nueva consulta que podría eliminar la tabla users de la base de datos.
Uso inseguro de eval() y funciones relacionadas
Se pueden explotar funciones como eval() si se permite que un usuario ingrese expresiones arbitrarias como esta:
En este ejemplo, un atacante puede ingresar __import__('os').system('any arbitrary command') para ejecutar comandos arbitrarios del sistema operativo. Por ejemplo, podría ingresar un comando como rm -rf /, que intenta eliminar todos los archivos del directorio raíz del sistema donde se encuentra el código.
Falta de validación y limpieza de datos de entrada
Sin una validación adecuada, un atacante puede ingresar la ruta de cualquier archivo y la aplicación lo lee de esta manera:
En este caso, un atacante puede ingresar una ruta como /etc/passwd para leer archivos confidenciales del sistema.
Riesgos asociados a la creación dinámica de código
Crear cadenas de comandos de forma dinámica sin una validación adecuada puede provocar vulnerabilidades de inyección de comandos. Por ejemplo, observa este código:
En este ejemplo, un atacante podría ingresar una cadena de directorio como ; cat /etc/passwd para mostrar el contenido del archivo de contraseñas del sistema o, peor aún, ejecutar otros comandos maliciosos. El punto y coma (;) permite encadenar comandos, lo que posibilita ejecutar comandos arbitrarios en el sistema anfitrión.
Deserialización insegura
La deserialización insegura puede ocurrir cuando se deserializan datos no confiables sin validarlos o limpiarlos de forma adecuada. Un atacante puede aprovechar esto para ejecutar código arbitrario. Por ejemplo, observa este código:
Si un atacante quisiera explotar este código, podría crear un objeto serializado que, al deserializarse, ejecutara código arbitrario, como iniciar una shell inversa. Este tipo de ataque puede ocurrir en aplicaciones cotidianas, como un carrito de compras en línea. Por ejemplo, imagina que usas uno y que guarda tu carrito como un código especial. Si la aplicación no comprueba a fondo que el código sea seguro cuando lo vuelve a cargar, un atacante puede enviar código engañoso que parece un carrito de compras, pero que lleva a cabo acciones maliciosas en secreto. Cuando la aplicación ejecuta sin saberlo este código peligroso, le abre la puerta al atacante. Puede robar tus datos, manipular la aplicación o incluso tomar el control de todo el sistema, lo que representa un riesgo de seguridad importante.
Cómo mitigar las vulnerabilidades de inyección de código
Comprender las vulnerabilidades es el primer paso, pero también es fundamental aprender a mitigarlas de forma eficaz. A continuación, se presentan medidas para contrarrestar las vulnerabilidades mencionadas:
Protege las entradas controladas por el usuario
Evita ejecutar directamente los datos ingresados por los usuarios. Si es necesario, utiliza técnicas estrictas de listas de permitidos que acepten únicamente patrones de entrada específicos:
Usa eval() y las funciones relacionadas de forma segura
Usa alternativas más seguras, como literal_eval(), o evita por completo el uso de eval(). Si no puedes evitarlo, asegúrate de limpiar los datos de entrada:
Implementa la validación y sanitización de datos de entrada
Usa expresiones regulares u otras técnicas de validación para asegurarte de que solo se acepten nombres de archivo o rutas válidos:
Por ejemplo, con literal_eval(), la entrada 2 + 3 se evaluaría como el valor numérico 5, mientras que una entrada como __import__('os').system('rm -rf /') generaría un ValueError en lugar de ejecutar el comando. Esto mitiga eficazmente los problemas de seguridad asociados con el uso de eval() y ofrece una forma más segura de evaluar expresiones que contienen literales.
Aborda la creación dinámica de código
Usa consultas parametrizadas o declaraciones preparadas para prevenir la inyección de SQL:
Deserializa de forma segura
Deserializa únicamente datos confiables. Si necesitas deserializar datos ingresados por el usuario, usa formatos más seguros, como JSON, o asegúrate de validarlos exhaustivamente antes de deserializarlos:
Aplica controles de acceso sólidos
Aplicar el principio de privilegio mínimo garantiza que los usuarios y procesos tengan el acceso (o los permisos) mínimos necesarios para realizar sus tareas. Esto reduce la superficie de ataque al limitar lo que pueden hacer los atacantes si explotan una vulnerabilidad.
Asegúrate de implementar controles de acceso sólidos para restringir el acceso no autorizado a las áreas confidenciales de la aplicación. En la siguiente sección, conocerás otras medidas que pueden mejorar la seguridad de tu base de código.
Convenciones de programación segura en Python
Hasta ahora, analizamos las formas más eficaces de mitigar las vulnerabilidades de inyección de código, pero escribir código seguro implica mucho más. También supone adoptar una serie de prácticas recomendadas y convenciones que ayudan a crear aplicaciones sólidas y seguras. Al escribir código Python, considera lo siguiente:
Usa herramientas de seguridad para desarrolladores para encontrar y corregir problemas
Snyk ofrece herramientas gratuitas de seguridad para Python que ayudan a identificar y corregir vulnerabilidades en tu código de aplicación, dependencias de código abierto, contenedores, configuraciones de IaC y más. Puedes integrar Snyk en tus repositorios de Git, flujos de trabajo de CI/CD, herramientas de línea de comandos e IDE para identificar y corregir vulnerabilidades.
Por ejemplo, Snyk identificará las dependencias de código abierto vulnerables de tu aplicación y te mostrará cómo corregirlas fácilmente. Aquí tienes una lista de código Python vulnerable en paquetes de pip en Snyk Vulnerability Database:

Incorporar herramientas como Snyk a tu flujo de trabajo de desarrollo agrega una capa adicional de defensa y permite desarrollar aplicaciones más sólidas y seguras. Snyk ofrece artículos útiles sobre cómo integrar sus herramientas en tu flujo de trabajo:
Cómo empezar a usar Snyk para desarrollar en Python de forma segura
Prácticas recomendadas para crear contenedores de aplicaciones Python con Docker
Cómo usar la API de Snyk para encontrar y corregir vulnerabilidades
El análisis de seguridad periódico con Snyk ofrece muchas ventajas, como acceso a una base de datos de vulnerabilidades actualizada y herramientas colaborativas de seguridad diseñadas para trabajar en equipo. Los beneficios van más allá de proteger tu código: también mejoran toda la experiencia de desarrollo. Gracias a sus funciones adaptadas a Python y su enfoque en la prevención de la inyección de código, Snyk transforma la manera en que abordas la seguridad en tus prácticas de programación y se convierte en un recurso invaluable para crear software seguro y de alta calidad.
Aplica prácticas seguras de registro de eventos
Evita registrar datos confidenciales de usuarios o información del sistema que podrían ser útiles para un atacante. Asegúrate de usar frameworks de registro que admitan configuraciones seguras.
Fomenta un entorno de programación segura
Estas son algunas estrategias más que puedes aplicar para crear un entorno de programación segura:
Revisiones de código y auditorías de seguridad periódicas: Asegúrate de que expertos en seguridad revisen el código con regularidad para detectar vulnerabilidades cuanto antes.
Mantén el software y las bibliotecas actualizados: Usa siempre las versiones más recientes de bibliotecas y frameworks, ya que suelen incluir parches de seguridad.
Fomenta una mentalidad centrada en la seguridad: Promueve una cultura en la que la seguridad sea una prioridad y asegúrate de que todos los miembros del equipo reciban capacitación sobre prácticas de programación segura.
Conclusión
En este artículo, aprendiste sobre los riesgos de la inyección de código en Python y por qué debes seguir las reglas de programación segura. La inyección de código puede presentarse de muchas formas, pero con los conocimientos adecuados y herramientas como Snyk puedes reducir esos riesgos. No esperes a que un problema arruine tu trabajo. Agrega las herramientas de seguridad de Snyk a tu proceso de desarrollo en Python para que tu código sea más seguro y eficaz.
Encuentra y corrige vulnerabilidades en Python
Protege tus aplicaciones con el análisis de vulnerabilidades de Snyk y recomendaciones para corregirlas.
No se requiere tarjeta de crédito.
O regístrate con Azure AD Docker ID Bitbucket
Al usar Snyk, aceptas cumplir con nuestras políticas, incluidos nuestros Términos de servicio y nuestra Política de privacidad.
