# Inicio

Apuntes sobre desarrollo seguro de software (SSD - Secure Software Development).


# Seguridad por oscuridad

## Descripción

La seguridad por oscuridad es un antipatrón que consiste en crear una capa de ofuscación en nuestro código o procesos, lo que dificulta que un atacante obtenga la información necesaria para explotar nuestro sistema.

Hay muchos enfoques para lograr la oscuridad. Uno de los más comunes involucra la compresión/minificación y ofuscación de archivos JavaScript. Este paso tiene dos objetivos: primero, optimizar el tráfico de la red y, segundo, hacer que sea más difícil para los atacantes leer y comprender nuestro código del lado del cliente, que siempre es público.

Este enfoque puede ser útil para evitar que los atacantes con niveles más bajos de habilidad y motivación comprometan nuestra aplicación. Sin embargo, no es muy efectivo contra adversarios altamente calificados.

## Herramientas

* [Compresión y ofuscación](https://pentesting.mrw0l05zyn.cl/explotacion/web/compresion-y-ofuscacion)


# Subresource Integrity (SRI)

## Descripción

Subresource Integrity (SRI) es una característica de seguridad que permite a los navegadores web verificar que los recursos que obtienen (por ejemplo, de un Content Delivery Networks) se entregan sin manipulaciones inesperadas. Es decir, le indica al navegador web que no cargue un recurso si el hash del recurso no coincide con un valor proporcionado previamente.

```html
<script src="https://example.com/script.js" integrity="sha384-tnzs0xPwekidEWHMZrWogzv1zrfOzlH18cCW2EMwMZ7uRe3NBceseD4AjA84jIKO" crossorigin="anonymous"></script>
```

El uso de Content Delivery Networks (CDN) para hospedar archivos de scripts y hojas de estilo que se comparten entre varios sitios puede mejorar el rendimiento del sitio. Sin embargo, el uso de CDN también conlleva un riesgo, ya que, si un atacante obtiene el control de una CDN, el atacante puede inyectar contenido malicioso arbitrario en los archivos del CDN (o reemplazar los archivos por completo) y, por lo tanto, también puede atacar potencialmente todos los sitios que obtienen archivos desde el CDN.&#x20;

Subresource Integrity (SRI) permite mitigar algunos riesgos de ataques como este, al garantizar que los archivos que obtiene la aplicación web (desde un CDN o cualquier otro lugar) se hayan entregado sin que un tercero haya inyectado ningún contenido adicional en esos archivos y sin que se hayan realizado otros cambios de ningún tipo en dichos archivos.

Calcular el hash de un archivo con OpenSSL.

```sh
cat <file> | openssl dgst -sha256 -binary | openssl base64 -A
cat <file> | openssl dgst -sha384 -binary | openssl base64 -A
cat <file> | openssl dgst -sha512 -binary | openssl base64 -A
```

## Herramientas

* [SRI hash generator](https://www.srihash.org/)

## Referencias

* [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)


# Codificación de salida

## Recomendaciones

* Utilizar [HTML entities](https://developer.mozilla.org/en-US/docs/Glossary/Entity).

```python
# HTML entities en Python
import html

html.escape('<div>Hack the planet!</div>')
'&lt;div&gt;Hack the planet!&lt;/div&gt;'

html.unescape('&lt;div&gt;Hack the planet!&lt;/div&gt;')
'<div>Hack the planet!</div>'
```


# CORS (Cross-Origin Resource Sharing)

## Descripción

Cuando el valor del encabezado "Access-Control-Allow-Origin" se establece en "\*" (asterisco) o cuando el valor del encabezado "Origin" se refleja en el valor del encabezado "Access-Control-Allow-Origin", el recurso permite la interacción bidireccional desde cualquier dominio (sitios web de terceros). Confiar en orígenes arbitrarios desactiva la política del mismo origen (same-origin policy / SOP). A menos que la respuesta consista exclusivamente en contenido público no protegido, es factible que esta configuración pueda generar un potencial riesgo de seguridad en determinados contextos.

## Recomendaciones

Asociar una lista de validación (lista blanca) para "Access-Control-Allow-Origin" que identifique los dominios confiables, restringiendo así el acceso sólo para dominios autorizados.

* Evite usar el valor wildcard "\*" (asterisco) o valor "null" (nulo) para "Access-Control-Allow-Origin".
* Evite reflejar dinámicamente los orígenes (encabezado "Origin") de solicitudes entre dominios para el encabezado "Access-Control-Allow-Origin".
* Utilice "Access-Control-Allow-Methods" para especificar que métodos son válidos para los dominios autorizados. Es posible que algunos solo necesiten consultar el recurso, mientras otros necesiten actualizar.

## Referencias

* [OWASP Web Security Testing Guide (WSTG)](https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/11-Client_Side_Testing/07-Testing_Cross_Origin_Resource_Sharing)
* [PortSwigger](https://portswigger.net/web-security/cors)


# JSON Web Token (JWT)

## Recomendaciones

### Algoritmos seguros

Utilizar algoritmos de firma robustos y seguros, como HS256 o RS256. Evitar el uso de `none` (ningún algoritmo) ya que no proporciona firma.

* HS256 (HMAC con SHA-256): es un algoritmo simétrico que utiliza una clave secreta compartida entre las partes involucradas. Esta clave se utiliza tanto para generar la firma del JWT como para validarla.
* RS256 (RSA con SHA-256): es un algoritmo asimétrico que utiliza un par de claves pública y privada. La entidad emisora del JWT posee una clave privada para generar la firma, mientras que el receptor del JWT utiliza la clave pública correspondiente para validar dicha firma.&#x20;

Tanto el algoritmo HS256 como el algoritmo RS256 son capaces de verificar la integridad y garantizar la autenticidad del JWT. Sin embargo, en la actualidad se recomienda el uso de RS256 por su capacidad adicional de asegurar el no repudio.

* Integridad: la firma de un JWT tiene como objetivo principal garantizar la autenticidad del token, es decir, asegurar que el contenido del JWT no ha sido modificado desde su generación por el emisor. Tanto HS256 como RS256 proporcionan esta garantía de autenticidad al verificar la integridad del token.
* No repudio: la ventaja adicional que ofrece RS256 es la capacidad de asegurar el no repudio. Esto implica que solo el poseedor de la clave privada correspondiente puede generar la firma del JWT. Con RS256, se obtiene la certeza de que únicamente el titular de la clave privada puede firmar los tokens, evitando así que cualquier otra persona pueda falsificarlos.

### Validación de firma

Asegúrate de que la aplicación realice una verificación completa y adecuada de la firma del token antes de confiar en su contenido.

#### No aceptar firmas arbitrarias

Las librerías que implementan el estándar JSON Web Token (JWT) generalmente ofrecen un par de métodos para realizar operaciones relacionadas con la verificación de los tokens. En particular, se suele proporcionar un método destinado a la validación de la firma del token y otro que únicamente se encarga de decodificarlo. Por ejemplo, la librería "jsonwebtoken" de Node.js, que dispone de las funciones `verify()` y `decode()`.&#x20;

En algunas ocasiones, es posible que los desarrolladores confundan el propósito de estos dos métodos y, erróneamente utilicen únicamente el método `decode()` para manejar los tokens entrantes. Este enfoque, en efecto, implica que la aplicación no realiza una verificación completa de la firma del token, comprometiendo así la seguridad de la aplicación.

#### No aceptar tokens sin firma

Los JSON Web Token (JWT) pueden ser firmados utilizando diversos algoritmos, pero también pueden ser dejados sin firmar. En el caso de no firmarse, el parámetro `alg` se establece como `none` (ningún algoritmo). Bajo esta configuración, cualquier token se considerará válido, aunque la firma se encuentre vacía. Debido a los evidentes riesgos que esto conlleva, se deben rechazar aquellos tokens que carezcan de firma.

### Expiración y renovación

Establecer una fecha de expiración razonable para los tokens JWT y considerar la implementación de un mecanismo de renovación para obtener nuevos tokens después de su vencimiento. Esto ayuda a limitar el tiempo de vida de los tokens y mitigar el riesgo en caso de que sean comprometidos.

### Minimizar la información sensible

Evitar incluir información sensible en el "payload" del token JWT, ya que los tokens son decodificables por cualquiera. Si se requiere transmitir información confidencial, se debe considera el uso de cifrado adicional.

### Almacenamiento seguro de claves

Guardar de manera segura las claves utilizadas para firmar y verificar los tokens. Utilizar medidas como almacenamiento encriptado y restricciones de acceso adecuadas para proteger las claves.

## Referencias

* [OWASP Web Security Testing Guide (WSTG)](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html)
* [OWASP Cheat Sheet Series](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/06-Session_Management_Testing/10-Testing_JSON_Web_Tokens)
* [PortSwigger](https://portswigger.net/web-security/jwt)


# Lectura de archivos

## Recomendaciones

* Validar el formato y la extensión al recuperar un archivo.
* Realizar la normalización de rutas (path normalization).&#x20;
  * Los atacantes pueden intentar manipular las rutas de los archivos al incluir caracteres de rutas relativas (`../`) o incluir rutas de archivos absolutas para acceder a archivos en otros directorios. Por lo tanto, cuando se trata de leer archivos, las aplicaciones deben normalizar las rutas de los archivos antes de realizar cualquier otra acción. El proceso de normalización de una ruta de archivo resuelve cualquier ruta relativa para crear una ruta de archivo absoluta.
  * Una vez que la aplicación ha realizado la normalización de la ruta del archivo, debe verificar si esa ruta es una ubicación válida.

```python
# Normalización de rutas en Python
import os
os.path.normpath("/foo/../bar")
'/bar'
```


# Manejo de errores

## Recomendaciones

* Asegúrese de que los mensajes de error que se muestran a los usuarios no expongan datos críticos, pero sigan siendo lo suficientemente detallados para permitir una respuesta adecuada al usuario.
* Administre las excepciones de manera centralizada.&#x20;
* Asegúrese de que todo el comportamiento inesperado se maneje correctamente dentro de la aplicación.
* Asegúrese de que las excepciones se registren de manera que brinden suficiente información para que los equipos de soporte, control de calidad, análisis forense o respuesta a incidentes comprendan el problema.
* Pruebe y verifique cuidadosamente el código de manejo de errores.

## Referencias

* [OWASP](https://owasp.org/www-community/Improper_Error_Handling)
* [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html)


# SQL injection (SQLi)

## Recomendaciones

* Utilizar consultas parametrizadas, las cuales definen una separación entre el código y los datos. Esto permite que la aplicación trate la entrada proporcionada por el usuario como datos que no pueden modificar el código de la instrucción SQL.
* [Validación de datos de entrada](/recomendaciones/validacion-de-datos-de-entrada). Asegurar que todos los datos de entrada sean validados semántica y sintácticamente previos a ser utilizados.
* No mostrar errores de SQL al usuario ([manejo de errores](/recomendaciones/manejo-de-errores) adecuado).
* Hacer cumplir el privilegio mínimo.


# Subida de archivos (file upload)

## Recomendaciones

* Incorporar validaciones de nombre, extensión, tipo (`Content-Type`), contenido (MIME-Type), tamaño y análisis/escaneo (sandbox) para el proceso de carga de archivos en la aplicación.
* Establezca un límite de longitud para el nombre de archivo. Restrinja los caracteres permitidos.
* Asegúrese que el nombre del archivo no contenga caracteres especiales y subcadenas que puedan interpretarse como un directorio o una secuencia transversal (`../`).&#x20;
* Compruebe el nombre del archivo con una lista negra de extensiones prohibidas.
* Verifique la extensión del archivo con una lista blanca de extensiones permitidas. Solo admita extensiones seguras y necesarias para la funcionalidad del comercio/negocio.&#x20;
* Valide el tipo y contenido del archivo, no confíe en el encabezado de tipo de contenido (`Content-Type`), ya que puede ser falsificado.
* Establezca un límite de tamaño de archivo para evitar ataques de denegación de servicio en el espacio de almacenamiento u otras funciones de la aplicación.
* No revele el directorio o ubicación de cargas y no proporcione acceso directo al archivo cargado. Siempre oculte el directorio de carga de los usuarios finales y solo permita descargar los archivos a través de una página de descarga.
* Aleatorizar los nombres de los archivos cargados y almacene sus nombres originales "sanitizados". Cambiar el nombre del archivo agrega otra capa de complejidad para que los atacantes logren acceder directamente a un archivo y evita que el archivo cargado sobrescriba un archivo existente.
* La carga de archivos solo debe ser accesible para usuarios autenticados y autorizados.
* Almacene los archivos en un host diferente, lo que permite una segregación completa de funciones entre la aplicación que atiende al usuario y el host que maneja las cargas de archivos y su almacenamiento.
* El directorio o lugar de almacenamiento de los archivos no debe tener ningún permiso de "ejecución".
* Analice y escanee (sandbox) los archivos en busca de malware o cadenas maliciosas.
* Utilice un Web Application Firewall (WAF) como una capa secundaria de protección.

## Referencias

* [OWASP](https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload)
* OWASP Web Security Testing Guide (WSTG):
  * [Unexpected file types](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/10-Business_Logic_Testing/08-Test_Upload_of_Unexpected_File_Types)
  * [Malicious files](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/10-Business_Logic_Testing/09-Test_Upload_of_Malicious_Files)
* [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html)
* [PortSwigger](https://portswigger.net/web-security/file-upload)


# Validación de datos de entrada

## Recomendaciones

* Asegurar que todos los datos de entrada sean validados semántica y sintácticamente previos a ser utilizados.
* La validación semántica implica garantizar que los datos de entrada son correctos en términos del contexto en el que se están utilizando, es decir, tengan sentido. Por ejemplo, un monto de una transacción no debe ser negativo.
* La validación sintáctica implica garantizar que los datos de entrada estén estructurados educadamente y sean del tipo correcto. Por ejemplo, si un campo de entrada espera un número de tarjeta de crédito, solo se deben aceptar datos de entrada que contengan dieciséis dígitos. Cualquier otra cosa debe rechazarse como entrada no válida.
  * Si bien es posible realizar verificaciones de tipo de datos manualmente, muchos lenguajes de programación brindan funciones integradas. Por ejemplo, PHP tiene las funciones `ctype_alpha()`, `ctype_digit()` y `ctype_alnum()` para comprobar si una cadena contiene solo letras, solo números o letras y números. Python, por ejemplo, tiene las funciones `isalpha()`, `isnumeric()` y `isalnum()` para el mismo propósito.
* Las validaciones de datos de entrada deben realizarse del lado del servidor. Las validaciones del lado del cliente se pueden omitir.&#x20;
* Rechazar y no limpiar. Las entradas maliciosas pueden crearse para aprovechar esto. Es decir, las tareas de reducción de inconsistencias y errores pueden tener consecuencias negativas. Rechace siempre las entradas no válidas.
* No utilizar igualdad abstracta con variables de tipos imprecisos en operaciones sensibles a la seguridad. Un atacante podría eludir los controles enviando valores que cumplan con las comprobaciones de igualdad abstracta, por lo tanto, las aplicaciones deben convertir la entrada al tipo de datos esperado y usar comparaciones de igualdad estrictas.

```javascript
// Ejemplos de comparación en JavaScript
// comparación de igualdad abstracta
"1" == 1;
true
"1" == true;
true

// comparación de igualdad estricta
"1" === 1;
false

// validación recomendada para valores nulos
if (val === null || val === undefined) {
    ...
}
```

* La validación es la primera línea de defensa. La validación de datos de entrada puede ayudar a filtrar entradas maliciosas. Sin embargo, no se debe utilizar como la única línea de defensa.&#x20;


