Skip to Content

Protegiendo la Estrella de la Muerte: Cómo Asegurar Endpoints Públicos en Odoo sin Vulnerar la Seguridad

No todas las compuertas necesitan estar abiertas — ni siquiera en la Estrella de la Muerte
June 12, 2026 by
BloVox

Protegiendo la Estrella de la Muerte: Cómo Asegurar Endpoints Públicos en Odoo sin Vulnerar la Seguridad

*No todas las compuertas necesitan estar abiertas — ni siquiera en la Estrella de la Muerte*

Toda base rebelde tiene un punto débil. En la Estrella de la Muerte era un conducto de escape térmico de 2 metros. En tu instancia de Odoo, son los endpoints públicos mal configurados. La diferencia es que reparar el tuyo es más fácil que convencer a un ingeniero imperial de que no deje accesos abiertos.

📌 Contexto: La Necesidad de Abrir Compuertas

Llega el día en que necesitás exponer una funcionalidad de Odoo al público. Tal vez sea una consulta de stock para tu tienda online, un webhook para recibir notificaciones de un transportista, o un endpoint para que un sistema externo (como el Halcón Milenario) te envíe datos.

El desafío: abrir la compuerta solo para lo que entra, no para que cualquiera se cuele.

🎯 El Desafío: No es Paranoia si realmente te están Hackeando

**El escenario:** Una empresa mediana de logística necesita que sus clientes puedan consultar disponibilidad de stock sin loguearse en Odoo. Parece simple, pero:

  • Si abrís `@http.route` con `auth='public'`, cualquier ser sensible a la fuerza puede pegarle al endpoint
  • Si dejás todo con `auth='user'`, ningún cliente externo puede consultar
  • Un endpoint público sin control es como dejar la puerta de la cantina de Mos Eisley abierta: entra cualquier cosa

**Lo que NO funciona:**

  • Poner `auth='public'` sin ninguna verificación — es como invitar a los Stormtroopers a tu base de datos
  • Usar contraseñas fijas en los headers — un数据分析 any, any un poco de `curl` y la descubren
  • Esconder el endpoint en una URL críptica — el "security by obscurity" es como esconder la Estrella de la Muerte detrás de una luna. Tarde o temprano la encuentran.

🔍 Análisis Técnico: Cómo Funciona el Sistema de Autenticación de Rutas en Odoo

Por defecto, Odoo tiene tres niveles de `auth` para rutas HTTP:

| auth | Acceso | Uso típico |

|------|--------|------------|

| `user` | Solo usuarios autenticados en Odoo | Backend, formularios internos |

| `public` | Cualquiera, incluso sin sesión | Páginas del website |

| `none` | Sin restricción, para webhooks o APIs externas | Integraciones |

El modelo de Odoo asume que si ponés `auth='public'`, ya sabés lo que hacés. Y como buen sable de luz, un endpoint público mal manejado puede lastimarte a vos también.

💡 La Solución: El Escudo Deflector de tu Endpoint

Como la Estrella de la Muerte, tu endpoint necesita un escudo deflector. Acá te mostramos cómo armarlo.

Opción 1: API Key en Headers (la más simple y efectiva)

import json
from odoo import http
from odoo.http import request

class StockController(http.Controller):

    @http.route('/api/stock/check', type='json', auth='public', methods=['POST'])
    def check_stock(self, product_ids=None, **kw):
        # Validar API key — como el código de acceso al Millennium Falcon
        api_key = request.httprequest.headers.get('X-API-Key')
        if not api_key:
            return {'error': 'missing_api_key', 'message': 'Se requiere API key'}
        
        # Verificar contra un parámetro de sistema (no hardcodeado!)
        valid_key = request.env['ir.config_parameter'].sudo().get_param('api.stock.key')
        if api_key != valid_key:
            return {'error': 'unauthorized', 'message': 'API key inválida'}
        
        # Si llegó hasta acá, es porque es de confianza (como Chewbacca)
        if not product_ids:
            return {'error': 'missing_products'}
        
        products = request.env['product.product'].sudo().search([('id', 'in', product_ids)])
        result = {}
        for p in products:
            result[p.id] = {
                'name': p.name,
                'qty_available': p.qty_available,
                'free_qty': p.free_qty,
            }
        return {'data': result, 'count': len(result)}

Paso a paso: Configuración

  1. **Generá una API key segura** — no uses "admin123" ni "luke_skywalker". Hay generadores online o podés usar Python:
  2. ```python

    import secrets

    print(secrets.token_urlsafe(32))

    # → algo como "xK8mZ2pQ4rS6tU9vW1yA3cE5gH7jL0nB"

    ```

    1. **Guardala como parámetro de sistema** en Ajustes → Parámetros Técnicos → Parámetros del Sistema:
    2. Clave: `api.stock.key`
    3. Valor: tu token generado

      1. **Configurá los clientes externos** para que envíen el header `X-API-Key` en cada request.
      2. Opción 2: Rate Limiting + IP Whitelist (para los más precavidos)

        Si querés ir a un nivel Darth Vader de seguridad, combiná la API key con:

        • **Rate limiting:** Limitá a X requests por minuto desde la misma IP
        • **IP whitelist:** Solo aceptá requests desde direcciones conocidas (como la flota imperial)
      3. import time
        from collections import defaultdict
        
        class RateLimiter:
            def __init__(self):
                self.requests = defaultdict(list)
            
            def is_allowed(self, ip, max_requests=60, window_seconds=60):
                now = time.time()
                window_start = now - window_seconds
                self.requests[ip] = [t for t in self.requests[ip] if t > window_start]
                if len(self.requests[ip]) >= max_requests:
                    return False
                self.requests[ip].append(now)
                return True
        

        ⚠️ Consideraciones: Lo que el Lado Oscuro te puede hacer

        • **Loggeo de accesos:** Siempre registrá cada request con IP, timestamp y resultado. Si pasa algo, tenés la evidencia.
        • **Rotación de keys:** Cambiá las API keys periódicamente. Como el código de la Alianza Rebelde, si se filtra, cambiálo.
        • **Timeout de sesión:** Para endpoints que usen sesión, asegurate de que expiren.
        • **HTTPS obligatorio:** Si no usás HTTPS, la key viaja en texto plano. Es como mandar los planos de la Estrella de la Muerte por correo de superficie.
      4. ✅ Resultado: Un Endpoint Seguro

        Con esta implementación:

        • ✅ Endpoint funcional para clientes externos
        • ✅ Solo accesible con API key válida
        • ✅ Sin exponer datos sensibles de Odoo
        • ✅ Logs de todos los accesos (para cuando necesités investigar)
        • ✅ Fácil de revocar si se compromete la key
      5. **Lo que logramos:** La empresa de logística puede dar acceso a sus clientes para consultar stock, sin comprometer la seguridad del sistema. Es como tener una puerta en la Estrella de la Muerte que solo se abre con el código correcto — y no hay conductos de escape térmico a la vista.

        📚 Para Profundizar

        • [Odoo HTTP Routing — documentación oficial](https://www.odoo.com/documentation/19.0/developer/reference/backend/http.html)
        • [Guía de API Keys en Odoo](https://www.odoo.com/documentation/19.0/es/developer/howtos/iap.html)
      6. 💬 ¿Tu Historia de Seguridad?

        ¿Tuviste que asegurar endpoints públicos en Odoo? ¿Usaste otra estrategia? ¿Alguna vez un cliente accedió donde no debía? Contalo en los comentarios — que el lado claro de la seguridad te acompañe. 🚀

        ---

        *Tipo: feature | Audiencia: tecnico | Tags: Seguridad, Tips y Trucos*

        *Este artículo fue escrito por un miembro de la Alianza Rebelde de desarrolladores Odoo*

📬 ¿No querés perderte ningún artículo nuevo?

Dejanos tu correo y te avisamos cuando publiquemos algo.

¡Gracias por suscribirte!