Principios de diseño de seguridad: el marco CIAAN
Objetivos: Al terminar este tema, podrás…
- Aplicar los cinco principios fundamentales como criterios de diseño de sistemas seguros
- Seleccionar controles técnicos apropiados para proteger cada principio
- Evaluar arquitecturas de seguridad según su cobertura de los principios CIAAN
- Identificar compromisos (trade-offs) entre principios en decisiones de diseño
El marco CIAAN como herramienta de ingeniería
En temas anteriores analizamos amenazas y actores. Ahora respondemos la pregunta central del diseño de seguridad: ¿qué propiedades debe garantizar un sistema seguro?
El marco CIAAN define cinco propiedades fundamentales que todo sistema debe proteger:
| Principio | Pregunta de diseño |
|---|---|
| Confidencialidad | ¿Quién puede acceder a esta información? |
| Integridad | ¿Cómo garantizo que los datos no fueron alterados? |
| Autenticación | ¿Cómo verifico la identidad de usuarios y sistemas? |
| Availability (Disponibilidad) | ¿Cómo garantizo acceso cuando se necesita? |
| No repudio | ¿Cómo pruebo quién realizó cada acción? |
Como ingeniero, usarás estos principios para:
- Definir requisitos de seguridad — Cada activo necesita protección de uno o más principios
- Seleccionar controles técnicos — Cada control protege principios específicos
- Evaluar arquitecturas — Un sistema bien diseñado cubre los cinco principios
- Justificar decisiones — “Implementamos X para proteger Y”
Los cinco principios en profundidad
1. Confidencialidad
Definición técnica: Propiedad que garantiza que la información solo es accesible para entidades autorizadas.
Pregunta de diseño: ¿Quién debe poder leer esta información, y cómo evito que otros la vean?
Controles técnicos
| Control | Aplicación | Consideraciones de implementación |
|---|---|---|
| Cifrado en reposo | Datos almacenados | AES-256 para bases de datos, discos completos |
| Cifrado en tránsito | Comunicaciones | TLS 1.3, certificados válidos |
| Control de acceso | Autorización | RBAC, listas de control de acceso |
| Clasificación de datos | Política | Etiquetado por sensibilidad (público, interno, confidencial, secreto) |
| Tokenización | Datos sensibles | Reemplazar PII con tokens no reversibles |
Decisiones de diseño
- ¿Dónde almacenar claves? — Hardware Security Modules (HSM), servicios de gestión de secretos (Vault, AWS KMS)
- ¿Qué algoritmos usar? — Preferir estándares actuales (AES-256, RSA-4096, Curve25519)
- ¿Cifrar todo o solo datos sensibles? — Balance entre rendimiento y seguridad
Caso de ingeniería: Sistema de salud
Requisito: Los historiales médicos solo deben ser accesibles por el paciente y médicos autorizados.
Diseño:
1. Cifrado de datos en reposo (AES-256)
2. Cifrado en tránsito (TLS 1.3)
3. Control de acceso basado en roles (médico, paciente, administrador)
4. Logs de acceso para auditoría
5. Segregación de datos por paciente
2. Integridad
Definición técnica: Propiedad que garantiza que la información no ha sido modificada, eliminada o creada sin autorización.
Pregunta de diseño: ¿Cómo detecto si alguien alteró estos datos?
Controles técnicos
| Control | Aplicación | Consideraciones de implementación |
|---|---|---|
| Hashes criptográficos | Verificación de archivos | SHA-256, SHA-3 |
| Firmas digitales | Autenticación de origen | RSA, ECDSA |
| HMAC | Mensajes autenticados | Combina hash con clave secreta |
| Validación de entrada | Aplicaciones web | Sanitización, prepared statements |
| Control de versiones | Archivos y código | Git, sistemas de auditoría |
Decisiones de diseño
- ¿Validar en cliente o servidor? — Siempre en servidor (nunca confiar en el cliente)
- ¿Qué constituye una modificación válida? — Definir reglas de negocio claras
- ¿Cómo manejar conflictos de versiones? — Estrategias de merge, locks optimistas
Caso de ingeniería: Sistema bancario
Requisito: Una transferencia de 10.000.000 en tránsito.
Diseño:
1. Firma digital del cliente sobre la transacción
2. TLS con certificate pinning
3. Validación de montos contra límites de cuenta
4. Hash de la transacción almacenado para verificación
5. Reconciliación automática de transacciones
3. Disponibilidad (Availability)
Definición técnica: Propiedad que garantiza que sistemas y datos estén accesibles para usuarios autorizados cuando los necesiten.
Pregunta de diseño: ¿Cómo garantizo que el sistema funcione bajo condiciones adversas?
Controles técnicos
| Control | Aplicación | Consideraciones de implementación |
|---|---|---|
| Redundancia | Servidores y datos | Clusters, replicación, múltiples zonas |
| Balanceo de carga | Distribución de tráfico | HAProxy, nginx, load balancers en nube |
| Backups | Recuperación de datos | 3-2-1 (3 copias, 2 medios, 1 offsite) |
| CDN | Contenido estático | Distribución geográfica, caché |
| Rate limiting | Protección DoS | Límites por IP, por usuario, por API key |
| Circuit breakers | Resiliencia | Fallar rápido, degradación graceful |
Métricas de disponibilidad
| SLA | Downtime anual | Downtime mensual |
|---|---|---|
| 99% | 3.65 días | 7.3 horas |
| 99.9% | 8.76 horas | 43.8 minutos |
| 99.99% | 52.6 minutos | 4.38 minutos |
| 99.999% | 5.26 minutos | 26.3 segundos |
Caso de ingeniería: Portal de inscripciones
Requisito: El portal debe soportar 10,000 usuarios concurrentes sin degradación durante el período de inscripciones.
Diseño:
1. Arquitectura auto-escalable (Kubernetes, AWS Auto Scaling)
2. Base de datos replicada con read replicas
3. CDN para contenido estático
4. Cola de mensajes para operaciones pesadas
5. Rate limiting por usuario (máx 10 requests/segundo)
6. Plan de capacidad con pruebas de carga previas
4. Autenticación
Definición técnica: Proceso de verificar que una entidad (usuario, dispositivo, sistema) es quien afirma ser.
Pregunta de diseño: ¿Cómo verifico la identidad antes de conceder acceso?
Factores de autenticación
| Factor | Tipo | Ejemplos | Fortaleza |
|---|---|---|---|
| Conocimiento | Algo que sabes | Contraseña, PIN, respuesta secreta | Baja (phisheable) |
| Posesión | Algo que tienes | Teléfono, hardware token, smart card | Media |
| Inherencia | Algo que eres | Huella, rostro, iris, voz | Alta (no transferible) |
| Ubicación | Donde estás | IP, geolocalización, red | Complementario |
| Comportamiento | Cómo actúas | Patrones de escritura, uso | Complementario |
Arquitecturas de autenticación
| Patrón | Uso | Consideraciones |
|---|---|---|
| Autenticación local | Sistemas internos | Almacenamiento seguro de credenciales (bcrypt, Argon2) |
| SSO (Single Sign-On) | Múltiples aplicaciones | SAML, OIDC, reducción de superficie de ataque |
| OAuth 2.0 / OIDC | APIs y aplicaciones modernas | Tokens de acceso, refresh tokens |
| Certificados X.509 | Sistemas y servicios | mTLS, autenticación de máquina a máquina |
Caso de ingeniería: Aplicación bancaria móvil
Requisito: Autenticación fuerte que balance seguridad y usabilidad.
Diseño:
1. Registro con verificación de identidad (KYC)
2. Autenticación primaria: biometría (huella/rostro)
3. Fallback: PIN de 6 dígitos
4. MFA obligatorio para operaciones sensibles
5. Límite de intentos fallidos (bloqueo temporal)
6. Device binding (vincular a dispositivo específico)
7. Notificaciones de acceso desde nuevos dispositivos
5. No repudio
Definición técnica: Propiedad que impide que una entidad niegue haber realizado una acción que efectivamente realizó.
Pregunta de diseño: ¿Cómo pruebo quién hizo qué y cuándo?
Controles técnicos
| Control | Aplicación | Consideraciones de implementación |
|---|---|---|
| Firmas digitales | Documentos y transacciones | PKI, certificados de usuario |
| Logs de auditoría | Todas las acciones | Inmutables, con timestamp verificable |
| Timestamping | Prueba temporal | Autoridades de tiempo certificadas (TSA) |
| Blockchain | Registros distribuidos | Inmutabilidad por consenso |
| Notarización digital | Documentos legales | Servicios de firma electrónica certificada |
Requisitos para no repudio efectivo
- Autenticación fuerte — Saber quién realizó la acción
- Logs inmutables — No poder alterar el registro después del hecho
- Timestamp verificable — Probar cuándo ocurrió
- Integridad del registro — El log mismo no puede ser modificado
Caso de ingeniería: Sistema de votación electrónica
Requisito: Cada voto debe ser verificable, pero el votante debe permanecer anónimo.
Diseño:
1. Autenticación fuerte del votante (identidad verificada)
2. Separación criptográfica entre identidad y voto
3. Recibo verificable para el votante
4. Log inmutable de votos (sin identidad)
5. Auditoría pública del conteo
6. Pruebas de conocimiento cero para verificación
Concesiones entre principios
En la práctica, los principios pueden entrar en conflicto. Como ingeniero, debes balancear:
Confidencialidad vs. Disponibilidad
| Más confidencialidad | Más disponibilidad |
|---|---|
| Cifrado de todo | Datos en texto claro para rapidez |
| Acceso restrictivo | Acceso amplio para productividad |
| Múltiples factores de autenticación | Autenticación simple |
Ejemplo: Un sistema de emergencias médicas debe priorizar disponibilidad sobre confidencialidad estricta en situaciones de vida o muerte.
Integridad vs. Rendimiento
| Más integridad | Más rendimiento |
|---|---|
| Verificación de cada operación | Verificación por muestreo |
| Transacciones ACID completas | Eventual consistency |
| Validación exhaustiva | Validación mínima |
Ejemplo: Un sistema de trading de alta frecuencia puede tolerar eventual consistency a cambio de latencia mínima.
No repudio vs. Privacidad
| Más no repudio | Más privacidad |
|---|---|
| Logs detallados de toda actividad | Logs mínimos |
| Identificación completa | Anonimato |
| Retención prolongada | Eliminación rápida |
Ejemplo: El GDPR requiere minimizar datos retenidos, lo que puede conflictuar con requisitos de auditoría.
Evaluación de arquitecturas con CIAAN
Usa esta matriz para evaluar cobertura de seguridad:
| Componente | C | I | A | A | N | Controles implementados |
|---|---|---|---|---|---|---|
| API Gateway | ✓ | ✓ | ✓ | ✓ | ✓ | TLS, rate limiting, auth, logs |
| Base de datos | ✓ | ✓ | ✓ | - | - | Cifrado, backups, validación |
| Almacenamiento de archivos | ✓ | ✓ | ✓ | - | - | Cifrado, checksums, redundancia |
| Sistema de autenticación | ✓ | ✓ | ✓ | ✓ | ✓ | MFA, logs, disponibilidad |
Conceptos clave
| Término | Definición |
|---|---|
| CIAAN | Marco de cinco principios fundamentales de seguridad |
| Confidencialidad | Información accesible solo para entidades autorizadas |
| Integridad | Información no alterada sin autorización |
| Disponibilidad | Sistemas accesibles cuando se necesitan |
| Autenticación | Verificación de identidad de entidades |
| No repudio | Imposibilidad de negar acciones realizadas |
| MFA | Autenticación que combina múltiples factores |
| SLA | Acuerdo de nivel de servicio con garantías de disponibilidad |
| PKI | Infraestructura de clave pública para firmas y cifrado |
Ponte a prueba
-
Diseño de controles: Una startup de fintech almacena datos financieros de clientes. Diseña controles técnicos para proteger cada uno de los cinco principios CIAAN. Justifica cada decisión.
-
Análisis de trade-offs: Un hospital necesita un sistema de historiales médicos. ¿Cómo balancearías confidencialidad (proteger datos del paciente) con disponibilidad (acceso en emergencias)? Propón una arquitectura.
-
Evaluación de arquitectura: Analiza un sistema que conoces (red social, banco, universidad) y evalúa qué principios están bien protegidos y cuáles podrían mejorarse.
-
Caso de falla: El incidente de Equifax (2017) expuso datos de 147 millones de personas. ¿Qué principios CIAAN fallaron? ¿Qué controles habrían prevenido o mitigado el incidente?
Laboratorio práctico: Fundamentos de criptografía aplicada
Tiempo estimado: 120 minutos Requisitos: Python 3.8+, pip Instalación:
pip install cryptography
Objetivo
Implementar los mecanismos criptográficos fundamentales que protegen confidencialidad, integridad y no repudio.
Parte 1: Hashing para integridad (20 min)
Los hashes permiten verificar que un archivo no ha sido modificado.
import hashlib
def calcular_hash(archivo: str) -> str:
"""Calcula el hash SHA-256 de un archivo."""
sha256 = hashlib.sha256()
with open(archivo, 'rb') as f:
for bloque in iter(lambda: f.read(4096), b''):
sha256.update(bloque)
return sha256.hexdigest()
# Ejercicio 1.1: Calcula el hash de un archivo
hash_original = calcular_hash('documento.pdf')
print(f"Hash original: {hash_original}")
# Ejercicio 1.2: Modifica el archivo (añade un espacio) y recalcula
# ¿Qué observas sobre el nuevo hash?Experimenta:
- Crea un archivo de texto y calcula su hash
- Modifica un solo carácter y recalcula
- ¿Qué porcentaje del hash cambió? ¿Por qué es importante esta propiedad?
Parte 2: Almacenamiento seguro de contraseñas (25 min)
Las contraseñas nunca se almacenan en texto plano. Usamos funciones de derivación de clave (KDF).
import os
import hashlib
def hash_password_inseguro(password: str) -> str:
"""MAL: Nunca usar MD5 para contraseñas."""
return hashlib.md5(password.encode()).hexdigest()
def hash_password_seguro(password: str) -> tuple[bytes, bytes]:
"""BIEN: Usar salt aleatorio + función lenta."""
salt = os.urandom(16)
hash_resultado = hashlib.pbkdf2_hmac(
'sha256',
password.encode(),
salt,
iterations=100000 # Intencionalmente lento
)
return salt, hash_resultado
def verificar_password(password: str, salt: bytes, hash_guardado: bytes) -> bool:
"""Verifica si la contraseña coincide."""
hash_intento = hashlib.pbkdf2_hmac(
'sha256',
password.encode(),
salt,
iterations=100000
)
return hash_intento == hash_guardado
# Ejercicio 2.1: Almacena y verifica una contraseña
salt, hash_pwd = hash_password_seguro("MiContraseña123!")
print(f"Salt: {salt.hex()}")
print(f"Hash: {hash_pwd.hex()}")
# Ejercicio 2.2: Verifica contraseña correcta e incorrecta
print(verificar_password("MiContraseña123!", salt, hash_pwd)) # True
print(verificar_password("ContraseñaIncorrecta", salt, hash_pwd)) # FalseExperimenta:
- ¿Por qué usamos un salt aleatorio para cada usuario?
- ¿Qué pasaría si usamos 10 iteraciones en lugar de 100,000?
- Investiga: ¿Por qué se recomienda Argon2 o bcrypt sobre PBKDF2?
Parte 3: Cifrado simétrico para confidencialidad (30 min)
AES-256 protege datos en reposo y en tránsito.
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import os
def cifrar_aes(datos: bytes, clave: bytes) -> tuple[bytes, bytes]:
"""Cifra datos con AES-256-CBC."""
iv = os.urandom(16) # Vector de inicialización único
cipher = Cipher(algorithms.AES(clave), modes.CBC(iv), backend=default_backend())
encryptor = cipher.encryptor()
# Padding PKCS7 (AES requiere bloques de 16 bytes)
padding_length = 16 - (len(datos) % 16)
datos_padded = datos + bytes([padding_length] * padding_length)
cifrado = encryptor.update(datos_padded) + encryptor.finalize()
return iv, cifrado
def descifrar_aes(iv: bytes, cifrado: bytes, clave: bytes) -> bytes:
"""Descifra datos con AES-256-CBC."""
cipher = Cipher(algorithms.AES(clave), modes.CBC(iv), backend=default_backend())
decryptor = cipher.decryptor()
datos_padded = decryptor.update(cifrado) + decryptor.finalize()
# Remover padding
padding_length = datos_padded[-1]
return datos_padded[:-padding_length]
# Ejercicio 3.1: Cifra y descifra un mensaje
clave = os.urandom(32) # 256 bits
mensaje = b"Datos confidenciales del paciente: Juan Perez, ID: 12345"
iv, cifrado = cifrar_aes(mensaje, clave)
print(f"Cifrado (hex): {cifrado.hex()[:64]}...")
descifrado = descifrar_aes(iv, cifrado, clave)
print(f"Descifrado: {descifrado.decode()}")
# Ejercicio 3.2: Intenta descifrar con clave incorrecta
clave_incorrecta = os.urandom(32)
try:
descifrar_aes(iv, cifrado, clave_incorrecta)
except Exception as e:
print(f"Error con clave incorrecta: {type(e).__name__}")Experimenta:
- ¿Qué pasa si reutilizas el mismo IV para dos mensajes diferentes?
- ¿Dónde almacenarías la clave de cifrado de forma segura?
- ¿Por qué es importante que el IV sea único pero no necesita ser secreto?
Parte 4: Firmas digitales para no repudio (25 min)
Las firmas digitales prueban quién creó un mensaje y que no fue alterado.
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.backends import default_backend
# Generar par de claves RSA
clave_privada = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
clave_publica = clave_privada.public_key()
def firmar(mensaje: bytes, clave_privada) -> bytes:
"""Firma un mensaje con clave privada."""
return clave_privada.sign(
mensaje,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
def verificar_firma(mensaje: bytes, firma: bytes, clave_publica) -> bool:
"""Verifica firma con clave pública."""
try:
clave_publica.verify(
firma,
mensaje,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
return True
except Exception:
return False
# Ejercicio 4.1: Firma y verifica un documento
documento = b"Transfiero $10,000 a la cuenta 123456789"
firma = firmar(documento, clave_privada)
print(f"Firma válida: {verificar_firma(documento, firma, clave_publica)}")
# Ejercicio 4.2: Intenta verificar documento alterado
documento_alterado = b"Transfiero $100,000 a la cuenta 123456789"
print(f"Firma válida (alterado): {verificar_firma(documento_alterado, firma, clave_publica)}")Experimenta:
- ¿Por qué solo la clave privada puede firmar pero cualquiera con la pública puede verificar?
- Si alguien altera el monto de la transacción, ¿qué pasa con la verificación?
- ¿Cómo se relaciona esto con el principio de no repudio?
Entregable
Desarrolla un mini sistema de documentos firmados que:
- Permita crear un “documento” (string con contenido)
- Genere un hash del documento
- Firme el hash con una clave privada
- Exporte el documento + firma a un archivo JSON
- Permita verificar la autenticidad de un documento importado
# Estructura sugerida del archivo JSON
{
"contenido": "Texto del documento...",
"hash": "sha256_del_contenido",
"firma": "firma_digital_en_base64",
"fecha": "2024-01-15T10:30:00Z",
"firmante": "identificador_del_firmante"
}Criterios de evaluación:
- El código funciona correctamente
- Detecta correctamente documentos alterados
- Maneja errores apropiadamente
- Incluye comentarios explicando los principios CIAAN aplicados
Reflexión
Después de completar el laboratorio:
- ¿Qué principio CIAAN protege cada mecanismo criptográfico?
- ¿Por qué no deberías inventar tus propios algoritmos de cifrado?
- ¿Qué pasaría si la clave privada de una organización es comprometida?
Navegación: ← Anterior | Inicio | Siguiente: Taller de proyecto →