Una dependencia es código ajeno
Una dependencia es una biblioteca escrita por otras personas que tu programa usa para no escribirlo todo. Cuando esa biblioteca tiene un fallo, tu programa lo hereda.
Una academia en línea usa una biblioteca para enviar correos. Si la versión que tiene fallos conocidos sigue instalada, el fallo está en su web aunque nadie lo escribiera allí.
Al final de esta lección
Nota
Puedo juzgar el riesgo de las bibliotecas de un proyecto a partir de sus versiones y de los fallos conocidos.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Dependencia | biblioteca de otros que usa tu proyecto | |
| Versión | número que identifica una edición | 2.19.0 |
| Fijar versión | pedir una versión exacta | requests==2.19.0 |
| Vulnerabilidad conocida | fallo de seguridad ya publicado | |
| Secreto en el código | clave o contraseña escrita en un archivo |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Fijar la versión hace repetible el proyecto
Un archivo de requisitos lista las bibliotecas. Una línea como flask acepta cualquier versión. Una línea como flask==3.0.0 pide justo esa.
Fijar la versión permite saber qué hay instalado. Sin saberlo, no se puede comprobar si esa versión tiene fallos conocidos.
Ejemplo resuelto: tres líneas de requisitos
| Línea | Qué pide | Se puede auditar |
|---|---|---|
| requests==2.19.0 | La versión 2.19.0 exacta | Sí: se sabe qué hay |
| flask | La última que haya | No: cambia con el tiempo |
| django==3.2.1 | La versión 3.2.1 exacta | Sí: se compara con los avisos |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un aviso nombra la versión corregida
Los fallos conocidos se publican en avisos de seguridad. Cada aviso nombra la biblioteca y la primera versión corregida.
Para saber si la tuya es vulnerable, compara números uno a uno. La versión 2.9.0 es anterior a la 2.10.0, aunque como texto parezca mayor.
Comparar versiones número a número
mine = "2.9.0"
fixed = "2.10.0"
# Cambia mine por "2.10.1" y pulsa Run.
a = mine.split(".")
b = fixed.split(".")
older = False
for i in range(3):
if int(a[i]) != int(b[i]):
older = int(a[i]) < int(b[i])
break
print(older)
Mira requisitos y la aplicación
El laboratorio de esta lección es una aplicación que esconde secretos falsos a propósito. Ejecuta estos tres comandos. Solo miran. Los dos primeros leen una lista de requisitos inventada. El tercero pregunta a la aplicación si está sana.
La regla única
Advertencia
Mira solo tu copia privada del laboratorio, que no tiene salida a internet. Probar un sistema ajeno, o sin permiso, es delito en casi todos los países.
Cuántas líneas fijan versión
printf 'requests==2.19.0\nflask\ndjango==3.2.1\n' | grep -c '=='Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Qué líneas no la fijan
printf 'requests==2.19.0\nflask\ndjango==3.2.1\n' | grep -v '=='Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
¿Está sana la aplicación?
curl -s -w "\n" http://wrongsecrets:8080/actuator/healthSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Qué te dicen las tres respuestas
El primero imprime 2: dos líneas fijan versión. El segundo imprime flask: es la que no se puede auditar. El tercero imprime una línea corta que termina en "status":"UP".
Esa aplicación es una pieza más de software con dependencias. Cada una puede traer un fallo o un secreto olvidado.
El historial guarda los secretos
A veces el riesgo no es una biblioteca, sino una clave que alguien escribió en un archivo. Si ese archivo se sube a un repositorio, la clave queda en cada copia y en el historial.
La clave se guarda fuera del código, por ejemplo en una variable de entorno. Y si se expuso, se cambia.
Un error frecuente
Advertencia
Mucha gente cree que actualizar una biblioteca siempre es arriesgado, así que nunca lo hace. No es así. Una versión con fallos conocidos es un riesgo cierto. Actualiza poco a poco y ejecuta tus pruebas después de cada cambio.
Buscar un secreto en un archivo
# Líneas inventadas. Ninguna clave es real.
lines = ["host = db.local", "clave_api = \"abc123\"", "debug = true"]
# Cambia la palabra buscada por "host" y pulsa Run.
number = 0
for line in lines:
number = number + 1
if "clave" in line:
print("revisar la linea", number)