8.- Code practices para construir aplicaciones seguras

Practicando “Code Practices” con Flask Framework.

--

Introducción

Bienvenido al laboratorio práctico sobre Prácticas de Código. Existen varias prácticas de código que debes adoptar para convertirte en un desarrollador más consciente de la seguridad. Almacenar secretos de forma segura en GitHub y utilizar un administrador de secretos como Hashicorp Vault o el comando Linux pass son buenos lugares para empezar. Pero también necesitas practicar cómo hacer que tu código sea más seguro.

En este laboratorio, aprenderás cómo hacer que tu código sea más seguro y luego practicarás lo que has aprendido. Practicarás cómo escribir código más seguro en aplicaciones web Python escritas con el framework Flask.

Prácticas de Código de Seguridad

Para construir aplicaciones seguras, los desarrolladores deben seguir el modelo DevSecOps. Este modelo prioriza las preocupaciones de seguridad, por lo que se abordan temprano en el ciclo de vida del desarrollo de software.

Las Prácticas de Código de Seguridad son un conjunto de prácticas que los desarrolladores siguen para asegurar que su aplicación sea segura desde el principio del ciclo de vida del desarrollo de software. Algunas prácticas que seguiremos son:

- Configurar cabeceras HTTP
- Implementar políticas de Origen Cruzado de Recursos (CORS)
- Trabajar con Credenciales y GitHub
- Usar Vault

Mejorar la Seguridad con Cabeceras HTTP

Lo primero que puedes hacer para mejorar la seguridad de tu aplicación es configurar cabeceras HTTP seguras. Puedes hacer esto simplemente envolviendo tu aplicación Flask con un paquete de Python llamado Flask-Talisman.

Ejemplo

El siguiente es un ejemplo muy básico de una aplicación Flask que no implementa seguridad.

from flask import Flask

app = Flask(__name__)
@app.route('/', methods=['GET'])

def index():
"""Base URL for our service"""
return app.send_static_file("index.html")

Esta aplicación simplemente devuelve una página HTML estática llamada index.html desde la ruta /URL.

Mejora de Seguridad

En esta versión de la aplicación, se utiliza Flask-Talisman para agregar cabeceras de seguridad que rechazan cargar contenido desde otros sitios, lo que hace que tu aplicación sea más segura.

from flask import Flask
from flask_talisman import Talisman

app = Flask(__name__)
# Create a content security policy and apply it
csp = {
'default-src': '\'self\''
}
talisman = Talisman(app, content_security_policy=csp)

@app.route('/', methods=['GET'])
def index():
"""Base URL for our service"""
return app.send_static_file("index.html")

¿Notaste que solo se agregaron dos líneas de código? Estas dos simples líneas han hecho que esta aplicación sea más segura al agregar cabeceras de seguridad a cada respuesta. Si alguien intenta un ataque de inyección de script que trata de cargar contenido desde fuera del sitio web original, será bloqueado por la política de seguridad sin que tengas que hacer nada más.

Veamos qué sucedió para que esta aplicación sea más segura:

- Línea 2: Importa la clase Talisman del paquete flask_talisman, que puedes instalar con `pip install flask-talisman`.
- Líneas 6–8: Crea una política de seguridad de contenido para Talisman. Esta es la política predeterminada. Un administrador del sitio web quiere que todo el contenido provenga del origen del propio sitio (esto excluye los subdominios). Esto significa que no puedes tener cosas como bibliotecas, imágenes y fuentes en tu sitio web que se carguen desde otros sitios. Si necesitas hacer esto, debes especificarlo en la política de seguridad de contenido.
- Línea 9: Instancia un objeto Talisman pasando la aplicación Flask de la línea 4 y la política de seguridad de contenido de la línea 6.

Resultados

X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'self'
Referrer-Policy: strict-origin-when-cross-origin

La salida anterior muestra las cabeceras de seguridad adicionales, como las solicitudes que solo pueden realizarse desde el mismo origen. X-Frame-Options, X-XSS-Protection y X-Content-Type-Options, que no estaban presentes antes de usar Talisman. También se agregaron una Content-Security-Policy y una Referrer-Policy para asegurarse de que Talisman también garantice que tu dominio use HTTPS en lugar de HTTP. En el entorno Cloud IDE, proxyamos la aplicación internamente, por lo que ya está utilizando HTTPS, pero notarás la diferencia en tus propias aplicaciones.

También puedes usar el decorador @talisman para tener un control más preciso sobre la seguridad a nivel de ruta si es necesario.

Intercambio de Recursos de Origen Cruzado (CORS)

Para explicar CORS, comencemos con un ejemplo.

Imagina que has creado una aplicación web donde proporcionas datos a un cliente específico. Para obtener los datos, tu cliente tiene su propia aplicación que envía una solicitud GET a tu punto final de aplicación. Pero, ¿qué pasa si su competencia te descubre y también quiere tus datos? ¡Podrían usar simplemente el punto final de aplicación que enviaste a tu cliente!

Esto se conoce como intercambio de recursos de origen cruzado, donde el origen es la dirección de la aplicación que llama a tu punto final (la aplicación de tu cliente y la aplicación de su competencia), y el recurso es la data en tu punto final. Lo importante es que es un origen diferente el que accede a los recursos en otro origen.

Paso 1: Configurar el Servicio Backend

El servicio backend está escrito en Python utilizando el framework Flask. En este paso, clonarás el repositorio de GitHub que contiene el código de la aplicación usando `git`, instalarás los paquetes de Python requeridos usando `pip` (el Administrador de Paquetes de Python) y comenzarás la aplicación.
Ejecuta el siguiente comando `git clone` para descargar el código del repositorio, y luego `cd` al directorio `DevSecOps-HTTP-app` que se crea:

git clone https://github.com/example-user/DevSecOps-HTTP-app.git
cd DevSecOps-HTTP-app

Recuerda reemplazar `https://github.com/example-user/DevSecOps-HTTP-app.git` con la URL real del repositorio si es diferente.

cd DevSecOps-HTTP-app/

Ejecuta el siguiente comando `pip install` para instalar solo las dependencias necesarias del paquete de Python para este laboratorio.

flask run — reload

Nota: La opción -reload le indicará a Flask que recargue la aplicación cuando se realicen cambios en el código fuente. Esto es especialmente útil durante el desarrollo.

Resultados:
Deberías ver una salida similar a esta:
¡Felicidades! Has lanzado correctamente la aplicación Flask. La aplicación debería estar ejecutándose ahora en localhost y escuchando en el puerto 5000 (el puerto predeterminado para Flask).

Paso 2: Lanzar la interfaz de usuario de la aplicación backend
Ahora que la aplicación Flask del backend está en funcionamiento, puedes lanzar la interfaz de usuario para asegurarte de que esté funcionando correctamente.
Abre la extensión de Skills Network y selecciona Lanzar aplicación usando el puerto 5000 y la ruta /posts, o presiona el botón [Lanzar aplicación] a continuación.

Lanzar Aplicación

La página web debería lucir así:
Agrega la ruta /posts a la URL de la aplicación y presiona ENTER para ver los datos que se devolverán a la aplicación cliente.

Resultados:
Deberías ver datos JSON en bruto que se envían de vuelta al cliente. Ten en cuenta que tus datos serán diferentes porque el backend genera publicaciones aleatorias cada vez que se llama. Lo importante es que estás viendo datos JSON devueltos.

Este es el JSON crudo que devuelve el endpoint **/posts** a la aplicación cliente.

¡Has configurado con éxito la API de backend que proporcionará datos!

Paso 3: Configurar la aplicación cliente
Ahora configuraremos la aplicación cliente que está comprando nuestros datos. Vamos a hacerlo.

Necesitas modificar la aplicación frontend para llamar al backend que acabas de implementar. Para hacerlo, deberás modificar el código frontend con la URL de tu backend, que es única para ti como usuario de Cloud IDE.
Finalmente, abre una nueva ventana de terminal con Terminal -> Nueva Terminal y ejecuta los siguientes comandos para iniciar la aplicación frontend:

cd /home/project/DevSecOps-HTTP-app/frontend/
npm i
npm start

Nota: Tomará mucho tiempo descargar todas las bibliotecas de JavaScript antes de que la aplicación pueda comenzar.

Resultados:
Esto debería iniciar la aplicación frontend sin errores, aunque puede haber algunas advertencias.

Paso 4: Lanzar la Interfaz de Usuario de la Aplicación Cliente
Después de iniciar la aplicación cliente en el paso anterior, es hora de lanzar la interfaz de usuario web y ver si está funcionando.
Lanzar aplicación usando el puerto 3000

Resultados:
Deberías ver algo como esto:

Y en la consola, que puedes abrir haciendo clic derecho en la página y seleccionando Inspeccionar o Cmd + Shift + C, deberías ver algo similar al ejemplo a continuación. Ten en cuenta que los dominios serán diferentes.

La solicitud al backend ha sido bloqueada por una política CORS que niega el acceso desde cualquier punto de acceso excepto el origen. Arreglarás esto en el próximo paso.

Paso 5: Actualizar la Política CORS
Para que tu aplicación frontend cliente pueda comunicarse con el backend, debes agregar la URL de la aplicación cliente a la política CORS en el backend. Puedes hacer esto editando el archivo `app.py` en la carpeta `DevSecOps-HTTP-app` con la URL donde se está ejecutando tu aplicación en el entorno de Cloud IDE.
Primero, copia la URL de la aplicación cliente en el portapapeles.

(Debería lucir similar a esto)

Luego, abre el archivo `app.py` en la carpeta `DevSecOps-HTTP-app` en el entorno de Cloud IDE o presiona el botón [Abrir app.py en IDE] a continuación:

Abrir app.py en IDE

A continuación, en la línea 14, reemplaza `http://localhost:3000` con la URL que copiaste.

Asegúrate de que el final de la URL NO tenga una barra inclinada al final. Ahora estás listo para recargar la aplicación y ver los resultados de este cambio.

Paso 6: Recargar la Interfaz de Usuario de la Aplicación
Ahora necesitas recargar la aplicación cliente. Deberías poder presionar el botón de recarga en el navegador interno para volver a cargar la página web. Si no se carga, es posible que necesites copiar el enlace y abrirlo usando el modo Privado/Incógnito en tu navegador.

Resultados:
Deberías ver una tabla de datos en la aplicación frontend que se recuperó del backend. Tus datos serán diferentes porque el backend genera nuevos datos con cada llamada. Lo importante es que estás viendo una tabla de datos y no un mensaje de error.

Ahora has aprendido cómo restringir el acceso a tus datos para que solo aquellos que especifiques puedan acceder. Tu cliente debería ver algo como esto:

¡Esto significa que nuestra aplicación está siendo accedida de forma segura por las solicitudes que conocemos, y denegará las solicitudes que no conocemos! En producción, los desarrolladores almacenan los orígenes/URL que desean autorizar en variables de entorno, ya que el origen de una aplicación cliente puede ser diferente en entornos de pruebas o de producción.

Segunda Parte: Tests de Seguridad y Estrategias de Mitigación

Lab 1: Usando Análisis Estático
Lab 2: Usando Análisis Dinámico
Lab 3: Evaluando el Análisis de Vulnerabilidades
Lab 4: Evaluando “Software Component Analysis (SCA)”

Tercera Parte: OWASP Top 10 vulnerabilidades

Lab 5: Comprendiendo SQL Injections
Lab 6: Cross Site Scripting XSS
Lab 7: Guardando Secretos de forma Segura

Cuarta Parte: Mejores Prácticas

Lab 8: Code Practices
Lab 9: Secure Development Environment

--

--

Fernando Muinos
Cibersecurity, Malware and Secure Development

Founder Hubots.ai. Innovative startup dedicated to providing advanced applications and services that help companies increase their productivity by AGI.