addons-cm/docs/openspec/changes/security-audit-hardening/tasks.md
2026-08-07 16:46:33 +02:00

63 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 1. Pre-flight y preparación (reglas de compromiso)
- [ ] 1.1 Redactar y firmar la autorización (alcance, IPs origen Kali+localhost, ventana, contacto) y guardarla como cabecera de `docs/SECURITY_FINDINGS.md`.
- [ ] 1.2 Tomar snapshot/backup de BD y volumen; probar la restauración. Preparar clon de staging.
- [ ] 1.3 Crear cuentas de test dedicadas (`sec_test_portal`, `sec_test_user`, opcional manager); anotar grupos y partners.
- [ ] 1.4 Confirmar topología de prod vía SSH (`ss -tlnp`, `ps aux | grep odoo`, config nginx/traefik, `odoo.conf`, fail2ban, firewall, versión exacta de Odoo).
## 2. Entregables de documentación (`docs/`)
- [ ] 2.1 Crear `docs/SECURITY_AUDIT_CHECKLIST.md`: checklist de prevuelo con ítems markables por los 3 frentes + infra, cada uno con criterio pass/fail.
- [ ] 2.2 Crear `docs/SECURITY_AUDIT_RUNBOOK.md`: comandos paso a paso de la auditoría activa (nmap, hydra/patator, testssl.sh, nikto, ffuf, invocación de scripts) con las salvaguardas de la sección 1.
- [ ] 2.3 Crear `docs/SECURITY_FINDINGS.md`: registro con severidad/evidencia/estado, sembrado con H1H5 + hallazgos de infra.
## 3. Scripts de auditoría (`scripts/security/`, no destructivos, credenciales por parámetro/env)
- [ ] 3.1 `odoo_acl_probe.py`: autentica como portal/usuario de test vía API externa y prueba matriz read/write/create/unlink sobre `group.order`, `group.order.slot`, `product.supplierinfo`, `res.partner`, `res.users`, `account.move`, `sale.order` (de otro partner), `ir.config_parameter`, `ir.attachment`, `account.banking.mandate`, `res.partner.bank`.
- [ ] 3.2 `idor_probe.py`: como portal de test, itera `order_id`/`group_order_id` en `load_eskaera_page`, `load_products_ajax`, `add_to_eskaera_cart`, `eskaera_checkout`, `check_group_order_status` y detecta fuga de catálogo/precios de grupos ajenos; incluir IDOR vertical sobre `/my/orders/<id>` y `/my/events/<id>`.
- [ ] 3.3 `bruteforce_test.sh`: hydra/patator controlado contra cuenta de test en `/web/login` y contra la ruta API (`/web/session/authenticate`, `/xmlrpc/2/common`); verifica baneo de la IP de Kali por fail2ban.
- [ ] 3.4 `csrf_poc.html`: formulario cross-site que fuerza `POST /eskaera/clear-cart` y `/eskaera/confirm` desde sesión logueada (para demostrar H3 antes del fix).
- [ ] 3.5 `web_recon.sh`: nmap + testssl.sh + nikto + ffuf sobre rutas Odoo conocidas (`/web/database/manager`, `/web/database/selector`, `?debug=1`, `/web/webclient/version_info`, `.git/`) y chequeo de cabeceras/cookies.
## 4. Ejecución de la auditoría activa (registrar todo en el findings register)
- [ ] 4.1 Frente 1 (fuerza bruta): ejecutar 3.3; medir umbral/tiempo de baneo web y API; revisar política de contraseñas (`auth_password_policy`), 2FA (`auth_totp`), `auth_signup` no invitado, gestor de BD.
- [ ] 4.2 Frente 2 (acceso a datos vía API): ejecutar 3.1 y 3.2 (baseline pre-fix); documentar accesos indebidos (valida H1, H2, H4).
- [ ] 4.3 Frente 3 (vectores inadvertidos): ejecutar 3.4 (valida H3), 3.5 (TLS, cabeceras, superficie web, versión/CVEs) y revisar `t-raw`/XSS (valida H5).
## 5. Fixes de código — `website_sale_aplicoop`
- [ ] 5.1 (H1) En `security/ir.model.access.csv`: sustituir la fila `access_group_order_base` (grupo vacío) por lectura interna `base.group_user` `1,0,0,0`; idem `access_group_order_slot_base`; mantener filas de manager para escritura; añadir ACL de portal de solo lectura para el slot solo si el controlador lo lee sin `sudo()`.
- [ ] 5.2 (H2) Identificar en plantillas/controladores qué campos de `product.supplierinfo` lee el portal (origen del producto, proveedor principal vía `product.seller_ids`) y confirmar que el pricing va por `sudo()` en `controllers/website_sale_pricing.py`.
- [ ] 5.3 (H2, preferido) Preparar origen + proveedor principal en el controlador vía `sudo()` y pasarlos resueltos a la plantilla (sin lógica en QWeb); luego eliminar la ACL de portal de `product.supplierinfo` (fila 6 del CSV) y la record rule `rule_product_supplierinfo_portal_read`.
- [ ] 5.4 (H2, fallback si el render no se puede mover al controlador) Sustituir `domain=[(1,'=',1)]` de `rule_product_supplierinfo_portal_read` por un dominio acotado a los productos de los grupos del usuario, sin exponer campos de coste/precio.
- [ ] 5.5 (H3) En `controllers/website_sale.py`: convertir `save-order`, `confirm`, `clear-cart`, `save-cart` de `type="http"`+`csrf=False` a `type="json"` (plantilla: `confirm_order_from_portal`); devolver `dict`.
- [ ] 5.6 (H3) Ajustar el JS de `static/src/js/` (solo transporte: fetch con envelope JSON-RPC y lectura de `result`), sin lógica de negocio en JS.
- [ ] 5.7 (H4) En `controllers/website_sale.py`: añadir comprobación de pertenencia tras `exists()`/`state` en `load_eskaera_page`, `load_products_ajax`, `add_to_eskaera_cart`, `eskaera_checkout`, `check_group_order_status`, reutilizando `_get_consumer_group_for_user` (retorno vacío/redirect) o `_validate_user_group_access` (fallo duro); mantener bypass de usuario interno (`share == False`).
- [ ] 5.8 (H5) En `views/load_from_history_templates.xml`: sustituir `t-raw` en `<script>` por `<script type="application/json">` leído por el JS.
- [ ] 5.9 Bump de versión en `website_sale_aplicoop/__manifest__.py` (`18.0.X.Y.Z`).
## 6. Fix versionable de infra — `account_banking_mandate_batch`
- [ ] 6.1 Añadir `groups_id` a la server action de mandatos SEPA en `account_banking_mandate_batch/data/server_action.xml` para restringir quién puede lanzarla.
## 7. Tests (extender los existentes de `website_sale_aplicoop/tests/`)
- [ ] 7.1 `test_record_rules.py` / `test_multi_company.py`: aserciones de que el portal NO puede write/create `group.order` ni `group.order.slot` (H1) ni leer `product.supplierinfo` ajeno (H2).
- [ ] 7.2 `test_group_order_status_endpoint.py`: un portal fuera del grupo NO obtiene datos de los endpoints de lectura/ajax (H4); un miembro sí.
- [ ] 7.3 Test de que los endpoints de estado convertidos a `type="json"` funcionan same-origin y que el flujo de checkout/carrito sigue operando (H3).
## 8. Hardening de infra (servidor de prod; no versionable — verificar contra el checklist)
- [ ] 8.1 `odoo.conf`: `admin_passwd` fuerte, `list_db=False`, `dbfilter` por host, `proxy_mode=True`, `workers>0`, `limit_*`, `without_demo=True`, `db_password` fuerte; log parseable por fail2ban.
- [ ] 8.2 nginx/traefik: `limit_req` en `/web/login`, `/web/session/authenticate`, `/jsonrpc`, `/xmlrpc`; bloquear/restringir `/web/database/*`; HSTS + cabeceras; TLS fuerte; cookie `session_id` Secure/HttpOnly/SameSite; upgrade de `/websocket`.
- [ ] 8.3 fail2ban: jails para login web y API (IP real vía `proxy_mode`), jail de 429 de nginx y `recidive`; verificar baneo con 3.3.
- [ ] 8.4 BD/secretos: confirmar 5432 no expuesto por firewall; usuario de BD con mínimos privilegios; externalizar secretos fuera de ficheros versionados.
## 9. Verificación y calidad
- [ ] 9.1 Re-ejecutar 3.1/3.2 (deben denegar lo que antes permitían) y 3.4 (debe fallar tras el fix); actualizar el findings register a resuelto/verificado.
- [ ] 9.2 Tests del addon: `docker-compose run odoo odoo -d odoo --test-enable --stop-after-init -u website_sale_aplicoop` (usar `run`, no `exec`).
- [ ] 9.3 Verificación end-to-end del portal (carrito, save-order, confirm, clear-cart, checkout) tras la conversión a `type="json"`.
- [ ] 9.4 Calidad: `make format` / `make lint` (black línea 88 + isort + flake8 + pylint-odoo); sin `_()` en definiciones de campo; `pre-commit run --all-files`.
- [ ] 9.5 Cerrar cada ítem del checklist de prevuelo con evidencia.