Initial commit: SKEEN Derma Experts - Sistema Integral de Gestión Clínica
- Frontend React (SKEEN Brand) con Vite, TypeScript, Tailwind - Frontend Homenest (versión alternativa) - Módulos Odoo 17 custom (citas, pacientes, monedero, pagos, ventas, inventario, whatsapp) - WACRM fork (Next.js 16 + Supabase) - Hermes + Bridge + Skills (Qwen3.6 via Nan Builders) - Scripts de migración y operación - Documentación extensiva en docs/
This commit is contained in:
327
docs/seguridad.md
Normal file
327
docs/seguridad.md
Normal file
@@ -0,0 +1,327 @@
|
||||
# Seguridad — SKEEN Derma Experts
|
||||
|
||||
**Versión:** 2.0
|
||||
**Fecha:** 16 de julio de 2026
|
||||
|
||||
---
|
||||
|
||||
## 1. Principios de Seguridad
|
||||
|
||||
1. **Defensa en profundidad:** Múltiples capas de seguridad.
|
||||
2. **Principio de menor privilegio:** Acceso mínimo necesario.
|
||||
3. **Datos en tránsito cifrados:** HTTPS/TLS en producción.
|
||||
4. **Datos en reposo protegidos:** PostgreSQL con autenticación, backups cifrados.
|
||||
5. **Secretos fuera del código:** Variables de entorno, nunca hardcoded.
|
||||
6. **Auditoría:** Logs de acceso y cambios.
|
||||
|
||||
---
|
||||
|
||||
## 2. Autenticación y Autorización
|
||||
|
||||
### 2.1 Frontend React (JWT)
|
||||
|
||||
- **Algoritmo:** HMAC-SHA256
|
||||
- **Expiración:** 24 horas
|
||||
- **Payload:** `uid`, `login`, `role`, `exp`
|
||||
- **Roles:** `admin`, `recepcion`, `medico`, `lectura`
|
||||
|
||||
**Generación de token:**
|
||||
```python
|
||||
def sign_token(env, user):
|
||||
payload = {
|
||||
'uid': user.id,
|
||||
'login': user.login,
|
||||
'role': user.role,
|
||||
'exp': int(time.time()) + 86400
|
||||
}
|
||||
secret = env['ir.config_parameter'].sudo().get_param('skeen.frontend.jwt_secret')
|
||||
return jwt.encode(payload, secret, algorithm='HS256')
|
||||
```
|
||||
|
||||
### 2.2 Odoo API (API Key)
|
||||
|
||||
- Endpoints JSON-RPC/XML-RPC usan `auth='api_key'`.
|
||||
- API key almacenada en `ir.config_parameter` o header.
|
||||
|
||||
### 2.3 WACRM API (Bearer Token)
|
||||
|
||||
- API keys creadas en Supabase tabla `api_keys`.
|
||||
- Scopes granulares: `messages:send`, `contacts:read`, etc.
|
||||
|
||||
### 2.4 Supabase (JWT)
|
||||
|
||||
- **Anon Key:** Para operaciones públicas.
|
||||
- **Service Role Key:** Para operaciones administrativas (solo backend).
|
||||
- **Row-Level Security (RLS):** Habilitado en tablas sensibles.
|
||||
|
||||
---
|
||||
|
||||
## 3. Webhooks
|
||||
|
||||
### 3.1 Meta → WACRM
|
||||
|
||||
- **Verify Token:** `skeen_webhook_verify_2026`
|
||||
- **Validación:** GET con `hub.mode`, `hub.verify_token`, `hub.challenge`.
|
||||
|
||||
### 3.2 WACRM → Bridge (HMAC-SHA256)
|
||||
|
||||
**Firma:**
|
||||
```javascript
|
||||
function verifySignature(payload, signature) {
|
||||
const [t, v1] = signature.split(',').map(s => s.split('=')[1]);
|
||||
const expected = crypto.createHmac('sha256', WACRM_WEBHOOK_SECRET)
|
||||
.update(`${t}.${payload}`).digest('hex');
|
||||
return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
|
||||
}
|
||||
```
|
||||
|
||||
**Headers:**
|
||||
- `X-WACRM-Signature: t=<timestamp>,v1=<hmac_sha256>`
|
||||
|
||||
**Validación:**
|
||||
1. Extraer timestamp y firma del header.
|
||||
2. Calcular HMAC-SHA256 de `timestamp.payload`.
|
||||
3. Comparar con firma recibida (timing-safe).
|
||||
4. Rechazar si timestamp es muy antiguo (> 5 min).
|
||||
|
||||
---
|
||||
|
||||
## 4. Protección de Datos
|
||||
|
||||
### 4.1 Datos Sensibles
|
||||
|
||||
| Dato | Protección |
|
||||
|------|-----------|
|
||||
| Teléfonos | RLS en Supabase, validación en Odoo |
|
||||
| Emails | RLS, enmascaramiento en logs |
|
||||
| Historial médico | Acceso restringido por rol |
|
||||
| Datos de pago | Nunca almacenar tarjetas, usar tokens |
|
||||
| API keys | Variables de entorno, nunca commiteadas |
|
||||
|
||||
### 4.2 Enmascaramiento en Logs
|
||||
|
||||
```python
|
||||
def mask_phone(phone):
|
||||
if len(phone) > 4:
|
||||
return phone[:3] + '*' * (len(phone) - 7) + phone[-4:]
|
||||
return '***'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Seguridad en Red
|
||||
|
||||
### 5.1 Firewall
|
||||
|
||||
```bash
|
||||
# Solo puertos necesarios
|
||||
sudo ufw allow 22/tcp # SSH
|
||||
sudo ufw allow 80/tcp # HTTP
|
||||
sudo ufw allow 443/tcp # HTTPS
|
||||
sudo ufw enable
|
||||
```
|
||||
|
||||
### 5.2 nginx
|
||||
|
||||
```nginx
|
||||
# Rate limiting
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
||||
|
||||
server {
|
||||
location /api/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
proxy_pass http://localhost:8069;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 HTTPS
|
||||
|
||||
Configurar SSL en producción:
|
||||
|
||||
```bash
|
||||
sudo apt install certbot python3-certbot-nginx
|
||||
sudo certbot --nginx -d skeen.consultoria-as.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Gestión de Secretos
|
||||
|
||||
### 6.1 Variables de Entorno
|
||||
|
||||
**Nunca commitear:**
|
||||
- `.env`
|
||||
- `.env.local`
|
||||
- `*.key`
|
||||
- `*.pem`
|
||||
- Tokens de Meta
|
||||
- Keys de Stripe/MercadoPago
|
||||
|
||||
### 6.2 .gitignore
|
||||
|
||||
```gitignore
|
||||
# Secretos
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
*.key
|
||||
*.pem
|
||||
*.crt
|
||||
*.pfx
|
||||
*.p12
|
||||
*.keystore
|
||||
*.jks
|
||||
```
|
||||
|
||||
### 6.3 Rotación de Secretos
|
||||
|
||||
| Secreto | Frecuencia | Método |
|
||||
|---------|-----------|--------|
|
||||
| Meta Access Token | 60 días | Meta Developers |
|
||||
| WACRM API Key | 90 días | Dashboard WACRM |
|
||||
| Supabase JWT | 180 días | Regenerar |
|
||||
| Odoo admin password | 90 días | Cambiar manual |
|
||||
| ENCRYPTION_KEY | 365 días | Regenerar (requiere re-encrypt) |
|
||||
|
||||
---
|
||||
|
||||
## 7. Auditoría y Logs
|
||||
|
||||
### 7.1 Logs de Odoo
|
||||
|
||||
```bash
|
||||
tail -f /tmp/odoo.log | grep "audit"
|
||||
```
|
||||
|
||||
### 7.2 Logs de WACRM
|
||||
|
||||
```bash
|
||||
tail -f /tmp/wacrm.log
|
||||
```
|
||||
|
||||
### 7.3 Logs del Bridge
|
||||
|
||||
```bash
|
||||
tail -f /tmp/hermes-bridge.log
|
||||
```
|
||||
|
||||
### 7.4 Auditoría de Base de Datos
|
||||
|
||||
```sql
|
||||
-- Cambios en pacientes
|
||||
SELECT * FROM audit_log WHERE model = 'res.partner' ORDER BY create_date DESC LIMIT 100;
|
||||
|
||||
-- Accesos a datos sensibles
|
||||
SELECT * FROM audit_log WHERE model = 'skeen.cita' AND method = 'read' ORDER BY create_date DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Backups
|
||||
|
||||
### 8.1 Estrategia
|
||||
|
||||
| Tipo | Frecuencia | Retención | Ubicación |
|
||||
|------|-----------|-----------|-----------|
|
||||
| PostgreSQL Odoo | Diario | 30 días | Local + remoto |
|
||||
| PostgreSQL Supabase | Diario | 30 días | Local + remoto |
|
||||
| Archivos | Semanal | 12 semanas | Local + remoto |
|
||||
| Configuración | Mensual | 12 meses | Git |
|
||||
|
||||
### 8.2 Scripts
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# backup-daily.sh
|
||||
|
||||
DATE=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_DIR=/root/backups
|
||||
|
||||
# PostgreSQL Odoo
|
||||
pg_dump -U skeen -h localhost skeen_odoo | gzip > $BACKUP_DIR/odoo_$DATE.sql.gz
|
||||
|
||||
# PostgreSQL Supabase
|
||||
docker exec supabase-db pg_dump -U postgres postgres | gzip > $BACKUP_DIR/supabase_$DATE.sql.gz
|
||||
|
||||
# Archivos
|
||||
tar -czf $BACKUP_DIR/files_$DATE.tar.gz \
|
||||
/root/skeen-frontend \
|
||||
/root/skeen-wacrm \
|
||||
/root/skeen-odoo/addons/skeen_* \
|
||||
/root/skeen-roadmap-hermes \
|
||||
/root/migracion
|
||||
|
||||
# Limpiar backups antiguos
|
||||
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete
|
||||
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Respuesta a Incidentes
|
||||
|
||||
### 9.1 Detección
|
||||
|
||||
- Monitoreo Uptime Kuma.
|
||||
- Alertas de errores en logs.
|
||||
- Alertas de uso anormal de API.
|
||||
|
||||
### 9.2 Contención
|
||||
|
||||
1. Identificar componente afectado.
|
||||
2. Aislar componente (stop service, block IP).
|
||||
3. Evaluar impacto (datos expuestos, usuarios afectados).
|
||||
|
||||
### 9.3 Erradicación
|
||||
|
||||
1. Cerrar vulnerabilidad.
|
||||
2. Cambiar secretos comprometidos.
|
||||
3. Restaurar desde backup limpio si es necesario.
|
||||
|
||||
### 9.4 Recuperación
|
||||
|
||||
1. Restaurar servicios.
|
||||
2. Verificar integridad de datos.
|
||||
3. Monitorear post-incidente.
|
||||
|
||||
### 9.5 Lecciones Aprendidas
|
||||
|
||||
1. Documentar incidente.
|
||||
2. Actualizar procedimientos.
|
||||
3. Mejorar controles.
|
||||
|
||||
---
|
||||
|
||||
## 10. Checklist de Seguridad
|
||||
|
||||
### Pre-Producción
|
||||
|
||||
- [ ] HTTPS configurado
|
||||
- [ ] Firewall configurado
|
||||
- [ ] Secretos rotados
|
||||
- [ ] API keys con scopes mínimos
|
||||
- [ ] RLS habilitado en Supabase
|
||||
- [ ] Rate limiting configurado
|
||||
- [ ] Logs de auditoría activos
|
||||
- [ ] Backups automatizados
|
||||
- [ ] Monitoreo configurado
|
||||
|
||||
### Producción
|
||||
|
||||
- [ ] Revisión mensual de logs
|
||||
- [ ] Rotación trimestral de secretos
|
||||
- [ ] Pruebas de penetración anuales
|
||||
- [ ] Actualizaciones de seguridad mensuales
|
||||
- [ ] Verificación de backups mensual
|
||||
- [ ] Revisión de accesos trimestral
|
||||
|
||||
---
|
||||
|
||||
## 11. Contacto de Seguridad
|
||||
|
||||
Para reportar vulnerabilidades:
|
||||
- **Email:** ialcarazsalazar@consultoria-as.com
|
||||
- **PGP:** (a configurar)
|
||||
|
||||
**No divulgar públicamente** hasta que se haya resuelto.
|
||||
Reference in New Issue
Block a user