La seguretat no és una funcionalitat que s'"afegeix al final": és una propietat transversal que ha d'estar present des de la primera línia del disseny. Això és el que significa seguretat per disseny (security by design). Un sistema que funciona, escala i està sempre disponible no serveix de res si un atacant pot robar les dades dels usuaris o suplantar-ne la identitat. En aquesta lliçó aprendràs els principis fonamentals de la seguretat (defensa en profunditat i mínim privilegi), la diferència essencial entre autenticació i autorització, els protocols moderns que les implementen (OAuth2, OIDC i JWT), les vulnerabilitats més freqüents segons OWASP i, finalment, com protegir les dades mitjançant xifratge en trànsit i en repòs.
Nota professional: el contingut d'aquesta lliçó és educatiu sobre arquitectura. Qualsevol implementació real de seguretat en un sistema de producció ha de ser revisada per especialistes en seguretat i complir la normativa aplicable (per exemple GDPR/LOPDGDD).
Contingut
- Principis: defensa en profunditat i mínim privilegi
- Autenticació vs Autorització
- OAuth2, OpenID Connect i JWT
- OWASP Top 10 resumit
- Xifratge en trànsit i en repòs
- Errors habituals i consells
- Exercicis
- Principis: defensa en profunditat i mínim privilegi
Dos principis sostenen tota arquitectura segura.
La defensa en profunditat consisteix a no confiar en una única barrera, sinó a col·locar múltiples capes de seguretat independents. Si una falla, les altres continuen protegint. És el principi del castell medieval: fossat, muralla, portes, torres.
graph LR
A[Internet] --> F[Firewall / WAF]
F --> G[API Gateway + Auth]
G --> S[Validació al servei]
S --> D[(BD amb permisos mínims)]Cada capa del diagrama protegeix de manera independent: encara que un atacant travessi el firewall, encara ha de superar l'autenticació del gateway, la validació del servei i els permisos de la base de dades.
El mínim privilegi (least privilege) estableix que cada usuari, servei o procés ha de tenir només els permisos estrictament necessaris per a la seva funció, ni un més. Un compte de servei que només llegeix informes no ha de poder esborrar taules.
-- MALAMENT: l'aplicació fa servir un usuari totpoderós GRANT ALL PRIVILEGES ON *.* TO 'app'@'%'; -- BÉ: només els permisos que realment necessita, sobre la base concreta GRANT SELECT, INSERT, UPDATE ON tienda.* TO 'app'@'10.0.%';
A l'exemple "MALAMENT", si comprometen l'aplicació, l'atacant té control total de totes les bases de dades. Al "BÉ", només pot llegir i escriure a tienda, ni tan sols esborrar (DELETE), i només des de la xarxa interna 10.0.%. El dany potencial queda contingut.
- Autenticació vs Autorització
Aquests dos conceptes es confonen constantment, però són diferents:
| Autenticació (AuthN) | Autorització (AuthZ) | |
|---|---|---|
| Pregunta | Qui ets? | Què pots fer? |
| Verifica | Identitat | Permisos |
| Passa | Primer | Després (ja identificat) |
| Exemple | Iniciar sessió amb usuari i contrasenya | "Pot aquest usuari esborrar factures?" |
| Resultat típic | Un token d'identitat | Permetre o denegar l'operació |
La regla mnemotècnica: AuthN = autenticNació (qui ets); AuthZ = autoritZació (què pots). Sempre s'autentica primer i s'autoritza després.
Els models d'autorització més habituals són:
- RBAC (Role-Based Access Control): els permisos s'assignen a rols (admin, editor, lector) i els usuaris reben rols. Simple i molt estès.
- ABAC (Attribute-Based Access Control): la decisió es basa en atributs (departament, hora, ubicació, antiguitat). Més flexible i granular, però més complex.
- OAuth2, OpenID Connect i JWT
Aquests tres termes solen barrejar-se. La clau per no confondre's:
| Tecnologia | Per a què serveix | Respon a |
|---|---|---|
| OAuth 2.0 | Autorització delegada (donar accés a recursos) | Què pot fer aquesta app en nom teu? |
| OpenID Connect (OIDC) | Autenticació (capa sobre OAuth2) | Qui és l'usuari? |
| JWT | Format de token (transporta la informació) | (No és un protocol, és un contenidor) |
OAuth 2.0 permet que una aplicació accedeixi a recursos en nom de l'usuari sense conèixer la seva contrasenya (per exemple, "Iniciar sessió amb Google"). OIDC es construeix a sobre d'OAuth2 i afegeix la peça que li faltava: identificar l'usuari, mitjançant un ID Token. JWT (JSON Web Token) és el format més comú en què viatgen aquests tokens.
Un JWT té tres parts separades per punts: capçalera.payload.signatura.
// Capçalera (header): algorisme i tipus
{ "alg": "RS256", "typ": "JWT" }
// Payload (claims): la informació, NO xifrada, només codificada en Base64
{
"sub": "usuario-123", // subject: identificador de l'usuari
"name": "Ana García",
"roles": ["editor"], // usat per a l'autorització
"iat": 1718000000, // issued at: quan es va emetre
"exp": 1718003600 // expiration: quan caduca (1 hora després)
}Punt crític que confon els principiants: el payload d'un JWT no està xifrat, només codificat en Base64. Qualsevol el pot llegir. El que garanteix la signatura (la tercera part) és la integritat i autenticitat: que ningú no ha modificat el contingut i que el va emetre qui diu que és. Per això mai no s'han de posar secrets en un JWT.
// Validar un JWT signat amb RS256 (clau pública/privada)
Claims claims = Jwts.parserBuilder()
.setSigningKey(clavePublica) // Verifiquem la signatura amb la clau pública de l'emissor
.build()
.parseClaimsJws(tokenRecibido) // Llança una excepció si la signatura o l'expiració no són vàlides
.getBody();
String userId = claims.getSubject(); // Extraiem el "sub"
List<String> roles = claims.get("roles", List.class); // i els rols per autoritzarAquest codi verifica que el token no ha estat manipulat (gràcies a la signatura) ni ha caducat (exp), i només llavors extreu l'identificador i els rols. Si la validació falla, llança una excepció i es rebutja la petició.
- OWASP Top 10 resumit
OWASP (Open Worldwide Application Security Project) publica periòdicament el Top 10 dels riscos de seguretat web més crítics. És lectura obligada. Resum de les categories principals:
| # | Categoria | En què consisteix | Mitigació clau |
|---|---|---|---|
| A01 | Pèrdua de control d'accés | Accedir a recursos sense permís | Autorització al servidor, denegar per defecte |
| A02 | Fallades criptogràfiques | Dades sensibles mal protegides | Xifrar en trànsit i repòs, no inventar criptografia |
| A03 | Injecció (SQL, etc.) | Dades malicioses com a codi | Consultes parametritzades, validar entrades |
| A04 | Disseny insegur | Fallades de disseny, no de codi | Modelatge d'amenaces des del disseny |
| A05 | Configuració incorrecta | Valors per defecte, errors exposats | Enduriment (hardening), revisar la configuració |
| A06 | Components vulnerables | Llibreries obsoletes amb CVE | Actualitzar, escanejar dependències |
| A07 | Fallades d'autenticació | Sessions febles, força bruta | MFA, límits d'intents, gestió de sessió segura |
| A08 | Fallades d'integritat | Dades/codi sense verificar | Signatures, verificar la cadena de subministrament |
| A09 | Fallades de registre/monitoratge | No detectar atacs | Logs de seguretat, alertes, observabilitat |
| A10 | SSRF | Forçar el servidor a demanar URL internes | Validar i restringir destinacions de les peticions |
L'exemple clàssic és la injecció SQL (A03):
// MALAMENT: concatenar l'entrada de l'usuari directament a la consulta
String sql = "SELECT * FROM usuarios WHERE email = '" + email + "'";
// Si email = "' OR '1'='1", la consulta retorna TOTS els usuaris.
// BÉ: consulta parametritzada; el motor tracta "email" com a dada, mai com a codi
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM usuarios WHERE email = ?");
ps.setString(1, email); // El driver escapa el valor de manera seguraA la versió "MALAMENT", un atacant pot injectar SQL al camp email i manipular la consulta. A la "BÉ", el ? és un marcador de posició: el motor mai no interpreta el valor de l'usuari com a instruccions SQL, eliminant la vulnerabilitat d'arrel.
- Xifratge en trànsit i en repòs
Les dades s'han de protegir en els seus dos estats:
- En trànsit (in transit): mentre viatgen per la xarxa. Es protegeix amb TLS (el cadenat d'HTTPS). Evita que algú que intercepti el trànsit el pugui llegir (man in the middle).
- En repòs (at rest): mentre estan emmagatzemades al disc, base de dades o còpies de seguretat. Es protegeix xifrant l'emmagatzematge o columnes concretes.
| En trànsit | En repòs | |
|---|---|---|
| Amenaça | Interceptació a la xarxa | Robatori del disc o backup |
| Tecnologia | TLS / HTTPS | Xifratge de disc/columna (AES) |
| Exemple | Connexió https:// |
Base de dades amb xifratge transparent (TDE) |
# Forçar HTTPS i redirigir tot el trànsit HTTP a Nginx
server {
listen 80;
return 301 https://$host$request_uri; # Qualsevol petició HTTP es redirigeix a HTTPS
}
server {
listen 443 ssl;
ssl_protocols TLSv1.2 TLSv1.3; # Només versions modernes i segures de TLS
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/key.pem;
}Aquest fragment garanteix que mai no se serveixi contingut per HTTP sense xifrar: el primer bloc redirigeix (codi 301) tot el trànsit del port 80 a HTTPS. El segon configura TLS permetent només les versions 1.2 i 1.3 (les antigues tenen vulnerabilitats conegudes).
Una regla essencial sobre contrasenyes: mai no es xifren ni es desen en text pla; s'apliquen funcions de hash lentes i amb sal (bcrypt, scrypt, Argon2). Així, encara que robin la base de dades, no poden recuperar les contrasenyes originals.
Errors habituals i consells
- Confiar només en el client. La validació i l'autorització del navegador o l'app mòbil es poden saltar trivialment. Tot es valida i s'autoritza al servidor.
- Creure que el JWT està xifrat. No ho està. No posis dades sensibles al payload; qualsevol el pot llegir.
- Inventar la teva pròpia criptografia. Gairebé sempre acaba malament. Fes servir llibreries i protocols estàndard, revisats i mantinguts.
- Desar contrasenyes amb MD5/SHA o en clar. Fes servir funcions de hash dissenyades per a contrasenyes (bcrypt, Argon2) amb sal.
- Missatges d'error massa detallats. Dir "l'usuari no existeix" davant de "contrasenya incorrecta" ajuda l'atacant. Respon de manera genèrica.
- No actualitzar dependències. Les llibreries obsoletes (A06) són una de les vies d'atac més freqüents. Escaneja i actualitza.
- Consell: pensa com un atacant. A cada entrada de dades pregunta't "què passa si això és maliciós?".
Exercicis
-
AuthN vs AuthZ. Un usuari inicia sessió correctament però, en intentar accedir al panell d'administració, rep un error 403 (Prohibit). Va fallar l'autenticació o l'autorització? Justifica-ho.
-
Detectar la vulnerabilitat. Revisa aquest codi i digues quin risc de l'OWASP Top 10 conté i com el corregiries:
String consulta = "SELECT * FROM productos WHERE nombre = '" + busqueda + "'"; statement.executeQuery(consulta); -
Decisió de xifratge. Una aplicació de missatgeria envia missatges entre usuaris i els emmagatzema a la seva base de dades. Quins tipus de xifratge necessita i per què cadascun?
Solucions
-
Va fallar l'autorització (AuthZ), no l'autenticació. L'error 403 (Prohibit) significa que el sistema sap qui és l'usuari (es va autenticar bé, no és un 401), però aquest usuari no té permisos per accedir al panell d'administració. Si hagués fallat l'autenticació, el codi seria 401 (No autoritzat/no identificat).
-
És injecció SQL (A03): la variable
busquedaes concatena directament a la consulta, permetent que un atacant manipuli el SQL. Correcció amb consulta parametritzada:PreparedStatement ps = conn.prepareStatement( "SELECT * FROM productos WHERE nombre = ?"); ps.setString(1, busqueda); ps.executeQuery();El
?impedeix que el valor de l'usuari s'interpreti com a codi SQL. -
Necessita tots dos. Xifratge en trànsit (TLS/HTTPS) perquè ningú no pugui interceptar els missatges mentre viatgen per la xarxa entre el dispositiu i el servidor. I xifratge en repòs per protegir els missatges emmagatzemats a la base de dades davant del robatori del disc o d'una còpia de seguretat. (Les apps més exigents afegeixen xifratge d'extrem a extrem, on ni el mateix servidor no els pot llegir.)
Conclusió
Has après que la seguretat es dissenya des del principi mitjançant capes (defensa en profunditat) i permisos mínims, que autenticar (qui ets) és diferent d'autoritzar (què pots), que OAuth2/OIDC/JWT són les peces estàndard de la identitat moderna, que l'OWASP Top 10 cataloga els riscos que has de conèixer, i que les dades es xifren tant en trànsit com en repòs. La seguretat mai no és un producte acabat: és un procés continu de prevenció, detecció i millora.
I per detectar tant atacs com problemes de rendiment necessitem veure què passa dins del sistema. A la lliçó següent, Observabilitat: Logging, Mètriques i Traçabilitat, aprendrem a instrumentar l'aplicació per entendre el seu comportament en producció.
Curs d'Arquitectura d'Aplicacions
Mòdul 1: Fonaments de l'Arquitectura d'Aplicacions
- Què és l'Arquitectura d'Aplicacions?
- El Rol de l'Arquitecte de Programari
- Atributs de Qualitat i Requisits No Funcionals
- Decisions Arquitectòniques i Compromisos (Trade-offs)
- Documentació d'Arquitectura: Vistes i el Model C4
Mòdul 2: Principis i Tàctiques de Disseny
- Acoblament, Cohesió i Separació de Responsabilitats
- Principis SOLID Aplicats a l'Arquitectura
- DRY, KISS, YAGNI i Altres Principis de Disseny
- Tàctiques Arquitectòniques per als Atributs de Qualitat
- Gestió del Deute Tècnic
Mòdul 3: Estils i Patrons Arquitectònics
- Arquitectura Monolítica
- Arquitectura en Capes (N-Tier)
- Arquitectura Client-Servidor
- Arquitectura Hexagonal (Ports i Adaptadors)
- Arquitectura Neta i Ceba (Clean & Onion)
Mòdul 4: Arquitectures Distribuïdes i Microserveis
- Introducció als Sistemes Distribuïts
- Arquitectura de Microserveis
- Descomposició de Serveis i Bounded Contexts
- API Gateway, Service Discovery i Comunicació entre Serveis
- Patrons de Resiliència: Circuit Breaker, Retry i Bulkhead
- El Teorema CAP i la Consistència de Dades
Mòdul 5: Arquitectures Dirigides per Esdeveniments i Missatgeria
- Fonaments de l'Arquitectura Orientada a Esdeveniments
- Missatgeria Asíncrona: Cues i Brokers
- Patrons d'Esdeveniments: Event Sourcing i CQRS
- Gestió de Transaccions Distribuïdes: Patró Saga
- Streaming de Dades en Temps Real
Mòdul 6: Disseny Dirigit pel Domini (DDD)
- Conceptes Fonamentals del DDD
- Disseny Estratègic: Bounded Contexts i Llenguatge Ubic
- Disseny Tàctic: Entitats, Agregats i Repositoris
- Mapatge de Contextos (Context Mapping)
Mòdul 7: Dades i Persistència
- Estratègies de Persistència: SQL vs NoSQL
- Patrons d'Accés a Dades: Repository, Unit of Work i DAO
- Base de Dades per Servei i Gestió de Dades Distribuïdes
- Cau i Estratègies d'Invalidació
Mòdul 8: Arquitectura al Núvol i Desplegament
- Fonaments del Cloud Computing (IaaS, PaaS, SaaS)
- Contenidors i Orquestració amb Docker i Kubernetes
- Arquitectura Serverless
- Patrons de Disseny Cloud-Native
- Infraestructura com a Codi (IaC)
Mòdul 9: Qualitat, Seguretat i Observabilitat
- Escalabilitat: Horitzontal vs Vertical i Balanceig de Càrrega
- Alta Disponibilitat i Tolerància a Fallades
- Seguretat per Disseny i Autenticació/Autorització
- Observabilitat: Logging, Mètriques i Traçabilitat
- Rendiment i Proves de Càrrega
