Back to flin
flin

Limitacion de tasa y cabeceras de seguridad

Como FLIN proporciona limitacion de tasa integrada con ventanas deslizantes y cabeceras de seguridad automaticas en cada respuesta -- protegiendo aplicaciones contra abuso, XSS, clickjacking y MIME sniffing por defecto.

Thales & Claude | March 30, 2026 8 min flin
EN/ FR/ ES
flinrust

Dos funciones de seguridad que toda aplicacion web necesita y la mayoria de los desarrolladores olvidan agregar: limitacion de tasa para prevenir abuso, y cabeceras de seguridad para prevenir ataques del lado del cliente. En el ecosistema Node.js, la limitacion de tasa requiere express-rate-limit (o rate-limiter-flexible, o bottleneck). Las cabeceras de seguridad requieren helmet (o configuracion manual de una docena de cabeceras). Ambas deben instalarse, configurarse y mantenerse por separado.

FLIN integra ambas en el runtime. La limitacion de tasa esta disponible como guard o funcion de middleware. Las cabeceras de seguridad se agregan a cada respuesta automaticamente. Sin instalacion. Sin configuracion. Sin forma de olvidarlas.

Limitacion de tasa: el guard

La forma mas simple de agregar limitacion de tasa es el guard rate_limit:

flin// app/api/auth/login.flin

guard rate_limit(5, 60)    // 5 solicitudes por 60 segundos

route POST {
    // Logica de inicio de sesion -- solo 5 intentos por minuto por IP
}

Dos parametros: el numero maximo de solicitudes y la duracion de la ventana en segundos. Si un cliente excede el limite, recibe:

httpHTTP/1.1 429 Too Many Requests
Retry-After: 45
X-RateLimit-Limit: 5
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1711411245

{"error": "Too many requests. Try again in 45 seconds.", "status": 429}

La respuesta incluye cabeceras estandar de limitacion de tasa para que los clientes puedan implementar logica de retroceso, y una cabecera Retry-After indicando cuando se reinicia el limite.

Limitacion de tasa: la funcion de middleware

Para una limitacion de tasa mas flexible, use la funcion rate_limit() en el middleware:

flin// app/api/_middleware.flin

middleware {
    rate_limit(request.ip, limit: 100, window: 60)

    response.headers["X-RateLimit-Limit"] = "100"
    response.headers["X-RateLimit-Remaining"] = to_text(rate_remaining(request.ip))

    next()
}

La funcion de middleware permite claves de limitacion de tasa personalizadas. Se puede limitar por IP, por usuario, por clave API o por cualquier combinacion:

flin// Limitar por usuario en lugar de IP (para endpoints autenticados)
middleware {
    if request.user != none {
        rate_limit(to_text(request.user.id), limit: 1000, window: 60)
    } else {
        rate_limit(request.ip, limit: 100, window: 60)
    }
    next()
}

Este patron otorga a los usuarios autenticados un limite mayor (1000/min) mientras mantiene las solicitudes no autenticadas en un limite mas estricto (100/min).

El algoritmo de ventana deslizante

El limitador de tasa de FLIN usa un algoritmo de ventana deslizante que es mas preciso que las ventanas fijas:

rustpub struct RateLimiter {
    windows: HashMap<String, SlidingWindow>,
}

pub struct SlidingWindow {
    current_count: u32,
    previous_count: u32,
    window_start: Instant,
    window_duration: Duration,
    max_requests: u32,
}

impl SlidingWindow {
    pub fn check(&mut self) -> RateLimitResult {
        let now = Instant::now();
        let elapsed = now.duration_since(self.window_start);

        if elapsed >= self.window_duration {
            // Rotar ventana
            self.previous_count = self.current_count;
            self.current_count = 0;
            self.window_start = now;
        }

        // Estimacion ponderada de solicitudes en la ventana deslizante
        let weight = 1.0 - (elapsed.as_secs_f64() / self.window_duration.as_secs_f64());
        let estimated = (self.previous_count as f64 * weight) + self.current_count as f64;

        if estimated >= self.max_requests as f64 {
            let retry_after = self.window_duration - elapsed;
            RateLimitResult::Exceeded { retry_after }
        } else {
            self.current_count += 1;
            let remaining = self.max_requests - estimated.ceil() as u32;
            RateLimitResult::Allowed { remaining }
        }
    }
}

La ventana deslizante proporciona un limite de tasa suave en lugar del problema de "rafaga en el limite de la ventana" que sufren los algoritmos de ventana fija. Un cliente que envia 5 solicitudes a las 0:59 y 5 mas a las 1:01 es correctamente limitado, aunque cada minuto individual contenga solo 5 solicitudes.

Limites de tasa escalonados

Diferentes endpoints frecuentemente necesitan diferentes limites de tasa. FLIN soporta esto naturalmente a traves del sistema de guards:

flin// app/api/auth/login.flin
guard rate_limit(5, 60)      // Estricto: 5/min para intentos de login

// app/api/auth/register.flin
guard rate_limit(3, 3600)    // Muy estricto: 3/hora para registro

// app/api/products.flin
guard rate_limit(100, 60)    // Generoso: 100/min para listado de productos

// app/api/search.flin
guard rate_limit(30, 60)     // Moderado: 30/min para busqueda (costosa)

Cada guard mantiene su propio contador. Un usuario que agota su limite de busqueda aun puede acceder a productos. Los limites son independientes y tienen alcance por endpoint.

Cabeceras de seguridad automaticas

Cada respuesta HTTP de una aplicacion FLIN en modo produccion incluye un conjunto de cabeceras de seguridad. Estas no son opcionales. No son configurables (aunque pueden extenderse). Son parte de cada respuesta.

httpX-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
Permissions-Policy: camera=(), microphone=(), geolocation=()

Cada cabecera protege contra una clase especifica de ataque:

X-Frame-Options: DENY

Previene ataques de clickjacking donde un sitio malicioso incrusta su aplicacion en un iframe y engana a los usuarios para que hagan clic en botones ocultos. Con DENY, sus paginas no pueden ser enmarcadas en absoluto.

X-Content-Type-Options: nosniff

Previene el sniffing de tipo MIME. Sin esta cabecera, un navegador podria interpretar un archivo de texto como JavaScript si contiene sintaxis JS valida, habilitando ataques XSS a traves de subidas de archivos.

Strict-Transport-Security

Fuerza HTTPS para todas las solicitudes futuras. Una vez que un navegador ve esta cabecera, nunca hara una solicitud HTTP a su dominio durante el proximo ano. La directiva includeSubDomains extiende esto a todos los subdominios, y preload permite la inclusion en listas de precarga del navegador.

Content-Security-Policy

Controla que recursos puede cargar el navegador:

default-src 'self'       -- Solo cargar recursos del mismo origen
script-src 'self'        -- Solo ejecutar scripts del mismo origen
style-src 'self' 'unsafe-inline' -- Estilos del mismo origen + estilos inline

Esto bloquea todos los scripts externos, iframes, fuentes y otros recursos. Una vulnerabilidad XSS que inyecte <script src="evil.com/steal.js"> es neutralizada porque el navegador se niega a cargar scripts de origenes externos.

Permissions-Policy

Deshabilita funciones del navegador que son comunmente abusadas:

camera=()        -- Ninguna pagina puede acceder a la camara
microphone=()    -- Ninguna pagina puede acceder al microfono
geolocation=()   -- Ninguna pagina puede acceder a datos de ubicacion

Estos valores por defecto son restrictivos. Si una aplicacion FLIN necesita acceso a la camara (para un escaner QR, por ejemplo), el desarrollador puede anular estos en flin.config.

Personalizacion de cabeceras de seguridad

Aunque los valores por defecto son apropiados para la mayoria de las aplicaciones, pueden extenderse o anularse:

flin// flin.config

security {
    headers {
        csp = "default-src 'self'; script-src 'self' https://cdn.example.com; img-src 'self' data: https:"
        frame = "sameorigin"

        hsts {
            max_age = 31536000
            include_subdomains = true
            preload = true
        }

        custom = {
            "X-Custom-Header": "value"
        }
    }
}

Note que solo puede hacer la politica mas permisiva, no mas restrictiva. No puede deshabilitar X-Content-Type-Options o eliminar Strict-Transport-Security. La seguridad base no es negociable.

Desarrollo vs. produccion

En modo de desarrollo, algunas cabeceras de seguridad se relajan para facilitar la depuracion:

Desarrollo:
- HSTS no se envia (esta en localhost)
- CSP permite 'unsafe-eval' (para herramientas de desarrollo)
- X-Frame-Options permite sameorigin (para vista previa de desarrollo)

Produccion:
- Cabeceras de seguridad completas en cada respuesta
- Sin excepciones, sin anulaciones para la linea base

El runtime de FLIN detecta el modo de la variable de entorno FLIN_MODE o de la presencia de .env.development vs .env.production.

Mitigacion de DDoS

La limitacion de tasa sola no detiene un ataque de denegacion de servicio distribuido (miles de IPs cada una enviando pocas solicitudes). Pero si mitiga los ataques a nivel de aplicacion:

flin// Proteccion de endpoints costosos
guard rate_limit(10, 60)

route POST "/search" {
    // La busqueda de texto completo consume mucho CPU
    results = search query.q in Article by content limit 20
    results
}

Sin limitacion de tasa, un solo atacante podria enviar 1000 solicitudes de busqueda por segundo y colapsar el servidor. Con limitacion de tasa, cada IP esta limitada a 10 por minuto. El servidor permanece receptivo para usuarios legitimos.

Para DDoS a nivel de red, las aplicaciones FLIN deben desplegarse detras de un CDN o proxy inverso (Cloudflare, Caddy, Nginx) que maneje la proteccion a nivel TCP. La limitacion de tasa en FLIN protege la capa de aplicacion.

El efecto compuesto

La limitacion de tasa y las cabeceras de seguridad son individualmente simples. Su valor esta en el efecto compuesto:

  • La limitacion de tasa previene fuerza bruta -> el bloqueo de cuenta previene credential stuffing -> la comparacion segura de temporizado previene ataques de temporizado -> Argon2 previene el cracking offline. Cada capa hace mas dificil el ataque.
  • CSP previene XSS -> nosniff previene confusion MIME -> HSTS previene ataques de degradacion -> frame-ancestors previene clickjacking. Cada cabecera cierra un vector de ataque diferente.

Cuando cada aplicacion FLIN obtiene estas protecciones por defecto, todo el ecosistema se endurece. Un nuevo desarrollador desplegando su primera aplicacion FLIN obtiene la misma linea base de seguridad que un desarrollador experimentado que ha estado configurando estas cabeceras durante una decada.

En el proximo articulo, cubrimos la autenticacion de dos factores -- como FLIN implementa TOTP (contrasenas de un solo uso basadas en tiempo) como funcion integrada.


Esta es la Parte 109 de la serie "Como construimos FLIN", que documenta como un CEO en Abidjan y un CTO de IA disenaron y construyeron un lenguaje de programacion desde cero.

Navegacion de la serie: - [108] Autenticacion JWT en 3 lineas de FLIN - [109] Limitacion de tasa y cabeceras de seguridad (estas aqui) - [110] Autenticacion de dos factores (TOTP) - [111] OAuth2 y autenticacion social

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles