6.5 KiB
6.5 KiB
Proposal — Auditoría de seguridad y hardening (Odoo 18.0)
Why
Detectamos ataques automatizados cada vez más sofisticados que la heurística de fail2ban no frena,
y somos responsables de la seguridad de nuestra infra y la de nuestros clientes. Necesitamos (a) un
proceso de auditoría reproducible tipo "checklist de prevuelo" para verificar la resiliencia
ante fuerza bruta, acceso indebido a datos vía API y vectores inadvertidos; y (b) corregir cinco
hallazgos ya confirmados leyendo el propio código de website_sale_aplicoop.
Objetivo
Dejar la infra Odoo con una postura de seguridad auditable y repetible, y cerrar los hallazgos H1–H5 con tests que impidan su regresión.
Alcance
- Solo nuestra infra (autorización directa, sin terceros). Producción está tras nginx/traefik con TLS.
- Auditoría activa autorizada (fuerza bruta controlada contra cuenta de test y fuzzing de
endpoints) desde la máquina Kali de la red y desde
localhostvía SSH, preferentemente contra un clon de staging o en ventana de mantenimiento con snapshot previo. - Remediación de los hallazgos confirmados en
website_sale_aplicoop(+groups_iden la server action de mandatos SEPA deaccount_banking_mandate_batch).
No-objetivos
- No se audita ni escanea infra de terceros ni hosting ajeno.
- No se corrige aquí ningún hallazgo nuevo que surja durante la auditoría activa: se registra en el findings register y se aborda en un change posterior (salvo severidad crítica, que se escalará).
- No se modifica
ocb/ni los addons OCA originales.
What Changes
- Proceso de auditoría: se añaden entregables de documentación (
docs/SECURITY_AUDIT_CHECKLIST.md,docs/SECURITY_AUDIT_RUNBOOK.md,docs/SECURITY_FINDINGS.md) y scripts no destructivos enscripts/security/(probe de ACL vía API, probe de IDOR, harness de fuerza bruta, PoC de CSRF, recon web) parametrizados con cuentas de test. - Fix H1 (Alta) — ACL con
group_idvacío que concede write+create global sobregroup.orderygroup.order.slot: se reemplaza por ACLs de mínimo privilegio (lectura interna/portal explícitas; escritura solo manager). Los writes de los controladores usansudo()y no dependen de estas ACLs. - Fix H2 (Alta) — record rule de
product.supplierinfocondomain=[(1,'=',1)]que expone todos los precios de proveedor al portal. El portal usasupplierinfopara pintar el origen del producto y el proveedor principal en la web, así que no se elimina sin más: o se preparan esos valores server-side (víasudo()en el controlador, según la regla "sin lógica en QWeb") o se acota el dominio a los productos accesibles por el usuario, sin exponer campos de coste/precio. - Fix H3 (Media) — endpoints de cambio de estado con
csrf=False: se convierten atype="json"(bloquea el POST de formulario cross-site), tomando como plantillaconfirm_order_from_portal. - Fix H4 (Media) — endpoints de lectura/ajax que solo comprueban
exists()+state: se añade comprobación de pertenencia al grupo reutilizando_validate_user_group_access/_get_consumer_group_for_user. - Fix H5 (Baja) —
t-rawinyectado en<script>: se sustituye por un patrón de salida seguro. - Hardening de config:
admin_passwd,list_db=False,proxy_mode=True, password de BD fuerte, rate-limit/cabeceras en nginx, jails de fail2ban (web + API). Documentado como requisitos; los cambios de infra no versionable se ejecutan en el servidor, los versionables (groups_iden la server action) en el repo.
Capabilities
New Capabilities
eskaera-access-control: cómowebsite_sale_aplicooprestringe acceso a datos y acciones — ACL de mínimo privilegio, alcance deproduct.supplierinfo, autorización por pertenencia al grupo de consumo en todos los endpoints, protección CSRF en endpoints de estado, y escapado de salida en plantillas. Cubre H1–H5.security-audit-process: proceso repetible de auditoría — reglas de compromiso/autorización, checklist de prevuelo, runbook de auditoría activa, scripts de prueba y registro de hallazgos.infra-hardening: requisitos de endurecimiento de producción —odoo.conf, reverse proxy (nginx/traefik) con TLS/rate-limit/cabeceras, fail2ban (web + API), y gestión de secretos/BD.
Modified Capabilities
- (ninguna — no existen specs previas en
openspec/specs/)
Impact
- Addons afectados:
website_sale_aplicoop(security CSV + record rules, controladores, plantilla, tests, bump de__manifest__.py);account_banking_mandate_batch(groups_iden la server action). - Addons NO afectados:
ocb/, los addons OCA originales, y el resto de custom (solo se auditan; cualquier hallazgo se registra, no se modifica en este change). - Nuevas rutas en el repo:
docs/SECURITY_*,scripts/security/. - Impacto UI/website/QWeb: al convertir endpoints a
type="json"hay que ajustar el transporte en el JS dewebsite_sale_aplicoop(solo transporte, sin lógica). La plantillaload_from_history_templates.xmlcambia su forma de inyectar JSON. Sin cambios visibles de UX. - Infra (no versionable):
odoo.conf, config de nginx/traefik y fail2ban en el servidor de prod.
Riesgos
- La auditoría activa (fuerza bruta/fuzzing) puede degradar o afectar a producción: mitigado con clon de staging o ventana de mantenimiento, snapshot previo y cuentas de test dedicadas (nunca contra cuentas reales, por riesgo de lockout/DoS de usuarios legítimos).
- Convertir endpoints a
type="json"cambia el contrato de request/response: riesgo de regresión en el carrito/checkout del portal; mitigado con tests y verificación end-to-end. - Recortar el acceso a
product.supplierinfopodría romper la visualización de precios si algún punto del portal dependía de la ACL abierta: verificar que el pricing se computa víasudo().
Criterios de aceptación
- Los probes
odoo_acl_probe.pyeidor_probe.pydeniegan tras los fixes lo que permitían antes (write/create degroup.order, lectura desupplierinfoajeno, datos de grupos ajenos). - El PoC de CSRF funciona antes del fix y falla después.
- El harness de fuerza bruta acaba con la IP de Kali baneada por fail2ban en
/web/loginy en la ruta API. - Tests de
website_sale_aplicoopen verde:docker-compose run odoo odoo -d odoo --test-enable --stop-after-init -u website_sale_aplicoop. - El checklist de prevuelo cubre los tres frentes + infra, con criterio pass/fail por ítem, y el findings register queda con H1–H5 en estado resuelto/verificado.