Ir al contenido principal
BlogComputeDefienda su servidor GraphQL contra el consumo excesivo de recursos

Defienda su servidor GraphQL contra el consumo excesivo de recursos

Defienda_su_servidor_GraphQL_frente_al_consumo_excesivo_de_recursos (2)

GraphQL ofrece la flexibilidad de solicitar exactamente los recursos y atributos que necesita, ni más ni menos. A diferencia de REST, que a menudo solicita datos de más o de menos. Esta precisión hace que GraphQL sea altamente eficiente. Además, GraphQL ofrece formas estándar de gestionar la paginación, lo que aumenta aún más su flexibilidad. Sin embargo, los usuarios malintencionados pueden explotar estas características de GraphQL, y eso puede plantear riesgos significativos para la estabilidad de su servidor.

En este blog, exploraremos cómo la flexibilidad de GraphQL puede volverse en tu contra. Nos centraremos específicamente en una vulnerabilidad destacada por OWASP API Security Top 10: el consumo de recursos sin restricciones. También discutiremos los pasos prácticos para proteger sus sistemas de este tipo de abuso.

La respuesta de GraphQL a la sobrecarga y la infracarga

GraphQL fue diseñado en parte para resolver los problemas de sobrecarga que normalmente encontramos con REST. Por ejemplo, consideremos una base de datos estándar de comercio electrónico con usuarios, productos y pedidos. Imaginemos que necesitamos obtener el importe total en dólares de un pedido dado en ID de pedido. Con REST, esa petición GET a /orders/17 obtendría no sólo el importe en dólares, sino también lo siguiente:

  • datos del pedido
  • información de facturación
  • información de envío
  • cantidades de producto
  • fiscal
  • estado del pedido
  • ... y más

Eso es ir demasiado lejos.

Con REST, también te encuentras con under-fetching, cuando necesitas juntar datos asociados de múltiples recursos. Imagine que desea mostrar un resumen con la fecha y el estado de un pedido, los nombres y descripciones de todos los productos del pedido y el nombre y el correo electrónico del usuario que realizó el pedido. Para ello, tendría que enviar varias solicitudes:

  • GET /pedidos/17
  • GET /productos/1662527
  • GET /productos/9914188
  • GET /productos/3750021
  • GET /productos/7557109
  • GET /productos/6081142
  • GET /usuarios/3314

GraphQL fue la respuesta a estas deficiencias de REST. Puede consultar exactamente lo que necesita, a través de los recursos asociados. Para lograr lo anterior, su GraphQL podría tener este aspecto:

query {
  order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
}

¡Es tan sencillo y flexible! Sin embargo, este nivel de flexibilidad también significa que un usuario malintencionado puede sobrecargar deliberadamente los datos.

Abusar de la flexibilidad de las consultas

La sintaxis de consulta para GraphQL le permite realizar múltiples consultas dentro de la misma solicitud. Podríamos tomar la consulta anterior y hacer algo como esto:

query {
  Q1: order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
  Q2: order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
}

Esta vez, solicitamos los mismos datos que en la consulta anterior, salvo que los solicitamos dos veces. Naturalmente, la respuesta tendría el doble de tamaño que la petición de una sola consulta. Sin embargo, ¿qué pasaría si repitiéramos la consulta 100 veces en una sola petición?

query {
  Q00: order(id: "17") {    …  }  Q01: order(id: "17") {    …  }  …  Q99: order(id: "17") {    …  }
}

Así de fácil, hemos creado una consulta que nos dará una respuesta 100 veces más grande que nuestra consulta original. Una buena forma de ilustrar este ataque es con la siguiente imagen de hamburguesas con queso. Los panecillos de hamburguesa forman la única petición; pero entre los panecillos, ¡podría haber cientos de hamburguesas de carne!

consulta rellena

Si un usuario malintencionado abusara de esta flexibilidad de consulta, el consumo excesivo de recursos podría colapsar su servidor.

Abuso de las funciones de paginación

GraphQL también tiene algunas formas estándar de manejar la paginación. Un enfoque común es la paginación basada en offset, en la que la persona que llama proporciona el número de elementos a recuperar (límite) y el elemento con el que empezar (offset).

Por ejemplo, una consulta para devolver información de una búsqueda de productos podría tener este aspecto:

query {
  products(searchString: "shirt", limit: 8, offset: 0) {
    id
    name
    description
    sku
    category
    images {
      path
      alt_text
    }
    variations {
      name
      description
      cost
    }
  }
}

¿Y si ajustamos los parámetros de paginación para ejecutar esta consulta en su lugar?

query {
  products(searchString: "shirt", limit: 800, offset: 0) {    …  }}

En un conjunto similar de ejemplos que probé en un sitio de comercio electrónico, comparé las respuestas que recibí:

$ du response*.json
680496  response_big.json
333649  response_small.json

Se podría pensar que el archivo grande sería aproximadamente 100 veces más grande que el pequeño, ya que el límite se fijó en 800 en lugar de 8. Es probable que la búsqueda no arrojara 800 resultados en total (posiblemente sólo entre 16 y 20).

Abusar de la paginación es otro ejemplo de cómo alguien podría manipular los parámetros de consulta GraphQL para añadir carga a su servidor. Al explotar esta característica, los atacantes pueden obligar a su servidor a manejar solicitudes mucho más grandes de lo previsto, lo que podría conducir al agotamiento de los recursos y la denegación de servicio (DoS).

OWASP API4:2023 Consumo de recursos sin restricciones

Lo que hemos estado demostrando entra dentro del Top 10 de seguridad de API de OWASP, en concreto API4:2023 Consumo de recursos sin restricciones. Esta vulnerabilidad se produce cuando las API no limitan ciertos tipos de interacciones o solicitudes, dejando al servidor vulnerable a ataques DoS y otras interrupciones operativas.

Cuando una API permite un exceso de consultas o paginación sin límites, puede provocar una espiral de consumo de recursos. Esto, a su vez, puede causar una degradación del rendimiento o incluso un fallo completo del servidor. Sin los límites adecuados, estos ataques pueden interrumpir el servicio. Podría incurrir en elevados costes operativos, ver cómo los clientes se marchan y perder negocio.

Cómo protegerse

Para hacer frente a estos riesgos, debe regular adecuadamente las solicitudes de API. Implemente controles que restrinjan la cantidad de datos que se pueden solicitar. Esto incluye establecer límites en el tamaño y el número de consultas, así como aplicar la limitación de velocidad y otras medidas de protección.

He aquí algunas sugerencias prácticas para protegerse:

  • Límites de tamaño de la carga útil de solicitud y respuesta: Al establecer límites en el tamaño de los datos que se pueden solicitar y devolver, puedes evitar que las consultas demasiado grandes saturen tu servidor.
  • Límites de paginación: Implementa un límite máximo para la paginación, asegurando que la persona que llama no intente obtener más registros de lo razonable.
  • Cortafuegos de aplicaciones web (WAF): Un WAF puede ayudar a detectar y bloquear actividades maliciosas, frustrando posibles ataques a tu API GraphQL. Considera el uso de un WAF como Haltdos de Linode Marketplace para añadir esta capa adicional de seguridad.
  • Herramientas de seguridad de las API: Las herramientas que pueden detectar y mitigar la actividad maliciosa son esenciales. Pueden ayudar a identificar patrones inusuales que podrían indicar un ataque, lo que le permite tomar medidas antes de que afecte a su sistema.

Tomando estas medidas, puede reducir significativamente el riesgo de explotar su servidor GraphQL a través de un consumo excesivo de recursos. Asegurarse de que las interacciones con la API están correctamente reguladas ayudará a mantener la estabilidad y el rendimiento del servidor.

Para obtener más información sobre la construcción con GraphQL, echa un vistazo a GraphQL Apollo: Una introducción con ejemplos en nuestra documentación.

Comentarios

Dejar una respuesta

Su dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *.