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

7.4 KiB
Raw Blame History

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.