Skip to content

Security: Wikidelar/Wikidelar

Security

docs/SECURITY.md

Plan de Seguridad — Wikidelar

Wikidelar es una plataforma open source de uso nacional. Este documento define el modelo de seguridad, los controles implementados, y las guías de operación segura para deployments propios.


Modelo de amenazas

Actores

Actor Nivel de confianza Descripción
Visitante anónimo Ninguno Puede leer contenido público
Usuario registrado Bajo Puede contribuir, votar, comentar
Colaborador Medio Puede subir documentos y editar wikis
Editor Medio-alto Puede aprobar/rechazar contribuciones
Faculty Admin Alto Gestiona una facultad específica
Super Admin Máximo Acceso total al sistema

Superficie de ataque

  • API REST pública (/api/v1/*) — lectura sin auth, escritura con auth
  • Endpoints de administración (/api/v1/admin/*) — solo admins
  • Upload de archivos — superficie especialmente sensible
  • Importación EVA — solo accesible desde roles admin

Autenticación y Autorización

JWT Bearer Tokens

  • Algoritmo: HMAC-SHA256 (HS256)
  • Duración: 60 minutos (configurable via Jwt:ExpiryMinutes)
  • Claims incluidos: sub (UserId), name, email, role
  • La clave Jwt:Key debe tener mínimo 32 caracteres y generarse con CSPRNG en producción
# Generar clave segura en Linux/Mac
openssl rand -base64 48

# PowerShell
[Convert]::ToBase64String((1..48 | ForEach-Object { [byte](Get-Random -Maximum 256) }))

Nunca usar la clave del appsettings.Development.json en producción.

Política de contraseñas

Configurada en Identity:

  • Mínimo 8 caracteres
  • Requiere mayúscula, minúscula, dígito y carácter especial
  • Email único por usuario

Roles y permisos

SuperAdmin
  └─ FacultyAdmin (por facultad)
       └─ Editor
            └─ Collaborator
                 └─ RegisteredUser
                      └─ (Anónimo — solo lectura)

Los endpoints de admin exigen [Authorize(Roles = "SuperAdmin,FacultyAdmin")].


Rate Limiting

Implementado con Microsoft.AspNetCore.RateLimiting (sliding window):

Tipo de cliente Límite Ventana
Anónimo (por IP) 100 req 60 segundos
Autenticado 200 req 60 segundos

Respuesta en exceso: HTTP 429 con header Retry-After.

En producción, considerar un rate limiter a nivel de infraestructura (nginx, Cloudflare) como primera línea.


Headers de Seguridad HTTP

El middleware SecurityHeadersMiddleware aplica en cada respuesta:

X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: default-src 'self'; script-src 'self'; ...

Para configurar CSP más permisivo (ej. si se embeben videos de YouTube), editar SecurityHeadersMiddleware.cs.


CORS

Configurar Cors:AllowedOrigins con los dominios exactos del frontend. No usar * en producción.

{
  "Cors": {
    "AllowedOrigins": ["https://wikidelar.edu.uy"]
  }
}

Auditoría

Todos los cambios a entidades persistidas se registran en la tabla AuditLogs. Ver AUDIT.md para detalles.


Upload de archivos

Aún no implementado en esta versión. Cuando se implemente, aplicar:

  1. Validación de tipo MIME en el servidor (no solo extensión)
  2. Límite de tamaño por archivo (recomendado: 10MB para documentos, 50MB máximo)
  3. Scan antivirus antes de almacenar (ClamAV o servicio externo)
  4. Almacenar en MinIO con bucket privado, nunca en filesystem del servidor
  5. Generar presigned URLs con expiración corta para descarga
  6. No preservar el nombre de archivo original en storage (usar UUID)
  7. Rechazar: .exe, .sh, .bat, .php, .js, .html y similares

Inyección SQL

EF Core con consultas parametrizadas protege contra SQL injection en queries normales. Al usar FromSqlRaw:

// MAL
context.Subjects.FromSqlRaw($"SELECT * FROM subjects WHERE name = '{name}'");

// BIEN
context.Subjects.FromSqlRaw("SELECT * FROM subjects WHERE name = {0}", name);

Variables de entorno sensibles

En producción, nunca poner secretos en appsettings.json. Usar:

  • Docker/Kubernetes: variables de entorno o Secrets
  • Azure: Azure Key Vault + Managed Identity
  • Bare metal: dotnet user-secrets en dev, env vars en prod

Variables críticas:

ConnectionStrings__DefaultConnection
Jwt__Key

Dependency updates

El proyecto es open source. Mantener dependencias actualizadas:

# Revisar dependencias desactualizadas
dotnet list package --outdated

# Frontend
cd web && npm audit

Configurar Dependabot en el repositorio GitHub para PRs automáticos.


Checklist de deploy seguro

Antes de ir a producción:

  • Jwt:Key generada con CSPRNG, mínimo 32 chars, no compartida
  • CORS configurado solo con dominios de producción
  • HTTPS forzado (HSTS habilitado)
  • appsettings.Development.json excluido del container de producción
  • Secrets gestionados vía env vars o vault, no en archivos
  • Revisión de logs para no exponer datos sensibles
  • Backup automatizado de PostgreSQL configurado
  • dotnet ef migrations ejecutado — no usar EnsureCreated() en producción
  • Rate limiting revisado y ajustado al volumen esperado
  • Logs de auditoría monitoreados con alertas para acciones inusuales

Vulnerabilidades conocidas a vigilar

OWASP Top 10 Control implementado
A01 Broken Access Control Roles via Identity + JWT claims
A02 Cryptographic Failures TLS obligatorio, JWT con clave fuerte
A03 Injection EF Core parametrizado, FluentValidation
A04 Insecure Design Clean Architecture, validación en capas
A05 Security Misconfiguration Security headers middleware, CORS restringido
A06 Vulnerable Components Dependabot, npm audit, dotnet list --outdated
A07 Auth Failures Rate limiting, JWT con expiración corta
A08 Software Integrity Verificar hashes de imágenes Docker en CI
A09 Logging Failures Serilog + AuditLog entity
A10 SSRF Pendiente — validar URLs en futuras features

Reporte de vulnerabilidades

Al ser open source, reportar vulnerabilidades de seguridad abriendo un GitHub Security Advisory (privado) en el repositorio, no un issue público. Incluir pasos reproducibles y versión afectada.

There aren't any published security advisories