La limitación de velocidad es fundamental para proteger los recursos de una aplicación o sitio web de un uso excesivo o indebido. Ya sea resultado de la intervención humana maliciosa, de ataques basados en bots o de una vulnerabilidad pasada por alto, el uso indebido de los recursos puede interferir con el acceso legítimo a tu aplicación e introducir vulnerabilidades graves.

Este artículo explora cómo añadir la limitación de velocidad a una API en una aplicación Laravel.

Limita el Tráfico de tu API con Throttle en Laravel

La limitación de velocidad es un mecanismo diseñado para mitigar la explotación de los recursos de tu aplicación. Aunque tiene muchos usos, es especialmente útil para las API públicas en sistemas grandes y escalables. Garantiza que todos los usuarios legítimos conserven un acceso justo a los recursos del sistema.

La limitación de velocidad también es crucial para la seguridad, el control de costes y la estabilidad general del sistema. Puede ayudar a evitar ataques basados en peticiones, como los ataques distribuidos de denegación de servicio (DDoS). Este ataque se basa en el envío de peticiones repetidas para saturar e interrumpir el acceso a una aplicación o servidor web.

Existen varios métodos para aplicar la limitación de velocidad. Puedes utilizar variables que identifiquen al solicitante para determinar quién puede acceder a tu aplicación y con qué frecuencia. Algunas variables comunes son

  • Dirección IP — Implementar límites de tasa basados en direcciones IP te permite restringir el número de solicitudes por dirección. Este método es especialmente beneficioso en circunstancias en las que los usuarios pueden acceder a una aplicación sin proporcionar credenciales.
  • Clave API — Limitar el acceso mediante claves API implica proporcionar al solicitante claves API pregeneradas y establecer límites de tarifa por clave. Con este enfoque, también puedes aplicar distintos niveles de acceso a las claves API generadas.
  • ID de Cliente — También puedes pregenerar un ID de cliente que un usuario puede incrustar en la cabecera o en el cuerpo de las solicitudes de API. Este método te permite establecer niveles de acceso por ID para garantizar que ningún cliente pueda monopolizar los recursos del sistema.

Middleware Laravel

El middleware proporciona un mecanismo práctico para inspeccionar y filtrar las peticiones HTTP que entran en una aplicación. Esencialmente, es una capa de código entre la aplicación y su infraestructura subyacente para permitir la comunicación entre sus recursos.

Cómo Implementar Límites de Velocidad

Este tutorial utiliza una mini biblioteca API existente en el framework Laravel 10 para demostrar el uso de Laravel Throttle. El proyecto de ejemplo inicial contiene las implementaciones básicas de creación, lectura, actualización y eliminación (CRUD,  create, read, update, and delete) necesarias para gestionar los libros de una colección y dos rutas adicionales para demostrar algunos conceptos de limitación de velocidad.

Requisitos Previos

El tutorial asume que estás familiarizado con los fundamentos del desarrollo de APIs en Laravel. Asegúrate de que tienes lo siguiente:

También puedes utilizar MyKinsta para configurar y desplegar esta API. Puedes seguir la plantilla de proyecto proporcionada y previsualizar el resultado final desde el código fuente completo.

Configuración de la Aplicación Laravel

  1. Para empezar, clona la plantilla de proyecto.
  2. A continuación, crea un archivo .env en el directorio root del proyecto y copia en él el contenido de .env.example.
  3. A continuación, completa la configuración utilizando los siguientes comandos para instalar las dependencias de la aplicación y generar la clave de la app.
composer install
php artisan key:generate

Si este comando no añade automáticamente la clave de la aplicación a tu archivo .env, ejecuta php artisan key:generate --show, copia la clave generada y pégala en tu archivo .env como valor de APP_KEY.

  1. Una vez finalizada la instalación de las dependencias y la generación de la clave de la app, inicia la aplicación con el siguiente comando:
php artisan serve

Este comando inicia la aplicación y la hace accesible a través del navegador en https://127.0.0.1:8000.

  1. Visita la URL para confirmar que se rellena la página de bienvenida de Laravel:

La página de bienvenida de Laravel muestra su logotipo en la parte superior central.
La pantalla de bienvenida de Laravel

Configuración de la Base de Datos

Vamos a configurar y establecer la base de datos de la aplicación en MyKinsta.

  1. Navega al panel de control de tu cuenta MyKinsta y haz clic en el botón Añadir servicio:

El segmento superior de la pestaña Panel de MyKinsta presenta una barra de herramientas superior.
Panel de MyKinsta con varios servicios configurados.

  1. En la lista Añadir servicio, haz clic en Base de datos y configura los parámetros para iniciar tu instancia de base de datos:

El módulo "Crear una base de datos" de Kinsta muestra la primera sección, llamada "Detalles básicos".
Configuración de la base de datos MyKinsta.

Este tutorial utiliza MariaDB, pero puedes elegir cualquiera de las opciones de base de datos compatibles con Laravel que proporciona Kinsta.

  1. Una vez que hayas introducido los detalles de tu base de datos, haz clic en el botón Continuar para finalizar el proceso.

Las bases de datos aprovisionadas en Kinsta tienen parámetros de conexión internos y externos. Debes utilizar parámetros de conexión internos para las aplicaciones alojadas dentro de la misma cuenta de Kinsta y parámetros externos para las conexiones externas. Por lo tanto, utiliza las credenciales de la base de datos externa de Kinsta para tu aplicación.

  1. Copia y actualiza las credenciales .env de la base de datos de la aplicación con las credenciales externas que se muestran en la siguiente captura de pantalla:

El panel de control de Kinsta muestra la sección "Detalles básicos" de la base de datos "library-records" recién creada. Toda la información coincide con la introducida en la imagen de configuración de la base de datos anterior.
Detalles de configuración de la base de datos de MyKinsta.

DB_CONNECTION=mysql
DB_HOST=your_host_name
DB_PORT=your_port
DB_DATABASE=your_database_info
DB_USERNAME=your_username
DB_PASSWORD=your_password
  1. Después de rellenar las credenciales de la base de datos, prueba la conexión aplicando la migración de la base de datos mediante el siguiente comando:
php artisan migrate

Si todo funciona correctamente, deberías ver una respuesta similar a la que se muestra a continuación.

La salida del terminal muestra el comando Bash "php artisan migrate" y su salida.Inmediatamente debajo del comando, una etiqueta "INFO" indica "Running migrations. "Debajo aparecen las cuatro migraciones y sus estados, listados como sigue:2014_10_12_000000_create_users_table...812ms DONE.2014 2019_08_19_000000_create_failed_jobs_table...942ms DONE.2019_12_14_000001_create_personal_access_tokens_table...1,250ms DONE.A continuación, el cursor se sitúa en una línea de comandos vacía para permitir entradas adicionales.
Migración exitosa de la base de datos en un terminal.

  1. A continuación, utiliza el siguiente comando para listar las rutas de la aplicación y ver las rutas ya implementadas.
php artisan route:list

Ahora deberías ver los endpoints de la API disponibles:

El terminal muestra la ruta "php artisan":
Lista de rutas de la aplicación en el terminal.

  1. Inicia la aplicación y confirma que todo sigue funcionando correctamente. Puedes probar estos endpoints a través del terminal utilizando una herramienta como Postman o CURL.

Cómo Limitar la Tasa en una Aplicación Laravel

Existen varias técnicas de limitación de velocidad para las aplicaciones Laravel. Puedes bloquear un conjunto de direcciones IP o aplicar límites de solicitud basados en la duración en función de la dirección IP o el user_id de un usuario. A continuación, aplica cada uno de estos métodos.

  1. Instala el paquete Laravel Throttle con el siguiente comando:
composer require "graham-campbell/throttle:^10.0"
  1. También puedes realizar cambios adicionales en las configuraciones de Laravel Throttle publicando el archivo vendor configurations:
php artisan vendor:publish --provider="GrahamCampbellThrottleThrottleServiceProvider"

Cómo Bloquear Direcciones IP

Una técnica de limitación de velocidad te permite bloquear peticiones de un conjunto específico de direcciones IP.

  1. Para empezar, crea el middleware necesario:
php artisan make:middleware RestrictMiddleware
  1. A continuación, abre el archivo de middleware app/Http/Middleware/RestrictMiddleware.php creado y sustituye el código de la función handle por el fragmento que aparece a continuación. Asegúrate de añadir use App; a la lista de importaciones en la parte superior del archivo.
$restrictedIps = ['127.0.0.1', '102.129.158.0'];
if(in_array($request->ip(), $restrictedIps)){
  App::abort(403, 'Request forbidden');
}
return $next($request);
  1. En el archivo app/Http/Kernel.php, crea un alias para esta aplicación de middleware actualizando el array middlewareAliases como se indica a continuación:
    protected $middlewareAliases = [
    . . .
    'custom.restrict' => AppHttpMiddlewareRestrictMiddleware::class,
    ];
    1. A continuación, aplica este middleware a /restricted-route en el archivo routes/api.php como se indica a continuación y prueba:
    Route::middleware(['custom.restrict'])->group(function () {
      Route::get('/restricted-route', [BookController::class, 'getBooks']);
    });

    Cuando funciona correctamente, este middleware bloquea todas las peticiones procedentes de las IP del array  $restrictedIps: 127.0.0.1 y 102.129.158.0. Las solicitudes procedentes de estas IP devuelven una respuesta 403 Forbidden, como se muestra a continuación:

    La aplicación Postman devuelve una respuesta "403 Request Forbidden" a una solicitud GET a la URL
    Una respuesta 403 Forbidden para el endpoint /restricted-route GET en Postman

    Cómo Usar Throttle para Limitar Solicitudes por Dirección IP

    A continuación, puedes limitar las solicitudes utilizando la dirección IP del usuario.

    1. Aplica el middleware Throttle a las rutas GET y PATCH del endpoint /book en routes/api.php:
    Route::middleware(['throttle:minute'])->group(function () {
      Route::get('/book', [BookController::class, 'getBooks']);
    });
    
    Route::middleware(['throttle:5,1'])->group(function () {
      Route::patch('/book', [BookController::class, 'updateBook']);
    });
    1. También debes actualizar la función configureRateLimiting en el archivo app/Providers/RouteServiceProvider con el middleware que has añadido a las rutas anteriores.
    … 
    RateLimiter::for('minute', function (Request $request) {
      return Limit::perMinute(5)->by($request->ip());
    });

    Esta configuración limita las peticiones al endpoint /book GET a 5 por minuto, como se muestra a continuación.

    La aplicación Postman devuelve una respuesta "429 Too Many Requests" a una solicitud GET a la URL
    Una respuesta «429 Too Many Requests» para el endpoint /book GET en Postman.

    Cómo Usar Throttle Basándose en el ID de Usuario y Sesiones

    1. Para limitar la tasa utilizando los parámetros user_id y session, actualiza la función configureRateLimiting en el archivo app/Providers/RouteServiceProvider con los siguientes limitadores y variables adicionales:
    ...
    RateLimiter::for('user', function (Request $request) {
      return Limit::perMinute(10)->by($request->user()?->id ?: $request->ip());
    });
    RateLimiter::for('session', function (Request $request) {
      return Limit::perMinute(15)->by($request->session()->get('key') ?: $request->ip());
    });
    1. Por último, aplica este código a las rutas /book/{id} GET y /book POST del archivo routes/api.php:
    Route::middleware(['throttle:user'])->group(function () {
      Route::get('/book/{id}', [BookController::class, 'getBook']);
    });
    Route::middleware(['throttle:session'])->group(function () {
      Route::post('/book', [BookController::class, 'createBook']);
    });

    Este código limita las peticiones que utilizan user_id y session, respectivamente.

    Métodos Adicionales en Throttle

    Laravel Throttle cuenta con varios métodos adicionales para un mayor control sobre tu implementación de limitación de velocidad. Estos métodos incluyen:

    • attempt  — Accede al endpoint, incrementa el contador de accesos y devuelve un valor booleano que indica si se ha superado el límite de accesos configurado.
    • hit —  Accede a Throttle, incrementa el contador de accesos y devuelve $this para habilitar otra llamada al método (opcional).
    • clear — Reinicia el contador de Throttle a cero y devuelve $this para que puedas realizar otra llamada al método si lo deseas.
    • count – Devuelve el número total de accesos a Throttle.
    • check – Devuelve un booleano que indica si se ha superado el límite de aciertos a Throttle.
    1. Para explorar la limitación de velocidad utilizando estos métodos, crea una aplicación middleware llamada CustomMiddleware utilizando el comando que aparece a continuación:
    php artisan make:middleware CustomMiddleware
    1. A continuación, añade los siguientes archivos de importación al archivo middleware recién creado en app/Http/Middleware/CustomMiddleware.php:
    use GrahamCampbellThrottleFacadesThrottle;
    use App;
    1. A continuación, sustituye el contenido del método handle por el siguiente fragmento de código:
    $throttler = Throttle::get($request, 5, 1);
    Throttle::attempt($request);
    if(!$throttler->check()){
      App::abort(429, 'Too many requests');
    }
    return $next($request);
    1. En el archivo app/Http/Kernel.php, crea un alias para esta aplicación de middleware actualizando el array middlewareAliases como sigue.
    protected $middlewareAliases = [
    . . .
    'custom.throttle' => AppHttpMiddlewareCustomMiddleware::class, 
    ];
    1. A continuación, aplica este middleware a /custom-route en el archivo routes/api.php:
    Route::middleware(['custom.throttle'])->group(function () {
      Route::get('/custom-route', [BookController::class, 'getBooks']);
    });

    El middleware personalizado que acaba de implementarse verifica si se ha superado el límite de Throttle mediante la función check method. If the limit is exceeded, it responds with a 429 error. Otherwise, it allows the request to continue.

    Cómo Desplegar la Aplicación en el Servidor Kinsta

    Ahora que has explorado cómo implementar la limitación de velocidad en una aplicación Laravel, despliega la aplicación en el servidor Kinsta para que sea accesible globalmente.

    1. Empieza enviando el código actualizado a GitHub, GitLab o Bitbucket.
    2. Desde tu panel de control de Kinsta, haz clic en el botón Añadir servicio y selecciona Aplicación de la lista. Vincula tu cuenta Git a tu cuenta Kinsta y selecciona el repositorio correcto para desplegar.
    3. En Detalles básicos, asigna un nombre a la aplicación y elige tu centro de datos preferido. Además, asegúrate de que has añadido las variables de entorno de la aplicación necesarias. Éstas corresponden a las variables presentes en tu archivo .env local: las variables de configuración APP_KEY y de la base de datos.

    La sección "Detalles de la aplicación" del módulo "Añadir aplicación" de Kinsta.
    Detalles de la aplicación en MyKinsta.

    1. Haz clic en el botón Continuar para seleccionar las variables de entorno de construcción. Puedes dejar los valores por defecto, ya que Kinsta autocompleta los parámetros necesarios.
    2. En la pestaña Procesos, puedes dejar los valores por defecto o introducir un nombre para tu proceso. En esta pestaña también puedes seleccionar el tamaño de los pods y de las instancias.
    3. Por último, la pestaña Pago muestra un resumen de tus selecciones. Añade tu opción de pago preferida para finalizar el proceso.
    4. Una vez completado, haz clic en la pestaña Aplicaciones para ver una lista de las aplicaciones desplegadas.
    5. Haz clic en el nombre de la aplicación para ver los detalles de su despliegue, como se muestra a continuación. Puedes utilizar la URL de la aplicación para acceder a ella.

    La pestaña "Despliegues" de MyKinsta muestra detalles sobre las aplicaciones desplegadas.
    Detalles del despliegue en el panel de MyKinsta.

    Cómo Probar la Aplicación

    1. Para probar la aplicación localmente, utiliza el comando php artisan serve.

    Este comando hace que el navegador de tu aplicación sea accesible en http://localhost:8000. Desde aquí puedes probar los endpoints de la API en los que implementaste la limitación de velocidad, realizando llamadas repetidas para activar la funcionalidad de limitación de velocidad.

    El servidor de Kinsta muestra una respuesta de Acceso Prohibido porque no has añadido detalles de configuración que indiquen a Kinsta cómo servir la aplicación. Añade estos detalles ahora.

    1. Crea un archivo .htaccess en el directorio root de tu aplicación y añade el siguiente código al archivo:
     <IfModule mod_rewrite.c>
      RewriteEngine On
      RewriteRule ^(.*)$ public/$1 [L]
    </IfModule>
    1. Envía estos cambios a GitHub y Kinsta se autodespliega para aplicar el cambio.
    2. Ahora, abre la aplicación utilizando la URL proporcionada y asegúrate de que ves la página de bienvenida de Laravel.

    Ahora puedes probar los endpoints de la API en los que has implementado la limitación de velocidad mediante Postman, realizando llamadas repetidas hasta alcanzar el límite configurado. Recibirás una respuesta 429 Demasiadas Peticiones tras superar el límite.

    Resumen

    Integrar funcionalidades de limitación de velocidad en una API de Laravel ayuda a controlar la velocidad a la que los usuarios consumen los recursos de una aplicación. La limitación de la tasa te ayuda a proporcionar una experiencia de usuario fiable sin gastar de más ni de menos. También garantiza que la infraestructura subyacente de la aplicación siga siendo funcional y eficiente.

    También puedes consultar el blog de Kinsta para conocer otros conceptos interesantes sobre Laravel y otras tecnologías web. Los servicios de alojamiento asequibles y sin problemas son muy recomendables para las necesidades de tu aplicación y de tu equipo.

Marcia Ramos Kinsta

I'm the Editorial Team Lead at Kinsta. I'm a open source enthusiast and I love coding. With more than 7 years of technical writing and editing for the tech industry, I love collaborating with people to create clear and concise pieces of content and improve workflows.