
Investigación sobre GraphQL desde el punto de vista de AppSec.
Se ha creado un laboratorio para estudiar los diferentes problemas; este toma el contexto de una clínica veterinaria que gestiona la salud de perros.
El laboratorio fue desarrollado utilizando IntelliJ IDEA Community Edition.
Los dominios utilizados son los siguientes:```text
127.0.0.1 localhost 127.0.0.1 domain1.local 127.0.0.1 domain2.local
Estas son las condiciones y suposiciones del laboratorio:
* Un veterinario puede estar asociado con 0 o N perros.
* Un perro puede estar asociado con 0 o 1 veterinario.
* Un veterinario posee una propiedad llamada **Popularity** presente en el sistema de almacenamiento (base de datos), pero no debe ser accedida por el cliente GraphQL porque es información sensible.
* El punto de vista de consumo de datos de GraphQL es el veterinario. La información del perro es pública.
* El laboratorio es explícitamente una aplicación vulnerable en la que se han implementado varias vulnerabilidades y se identifican usando el marcador `[VULN]` en los comentarios.
* En cuanto a la autenticación, se ha implementado un servicio falso de terceros (a través de un servlet) que devuelve un token JWT que contiene el nombre del veterinario en el token.
Una vez iniciado mediante la configuración de lanzamiento presente en el proyecto o la línea de comandos `mvn spring-boot:run`, el laboratorio está disponible en estos endpoints:
* [GraphiQL](http://localhost:8080/graphiql)
* [GraphQL](http://localhost:8080/graphql)
Para empaquetar la aplicación como un archivo jar portátil, use el comando `mvn package` (un archivo jar preconstruido está disponible [aquí](https://github.com/righettod/poc-graphql/releases)):
* El archivo jar se creará en la carpeta *target* y se llamará *graphql-poc.jar*.
* Use el comando `java -jar graphql-poc.jar` para ejecutar la aplicación.
## Despliegue en Docker
> La imagen se publica todos los días en [DockerHub](https://hub.docker.com/r/righettod/poc-graphql)
Para desplegar la aplicación en un contenedor docker, siga los pasos:
1. Asegúrese de tener `docker` instalado.
2. Ejecute `git clone` del repositorio.
3. Cambie al directorio clonado.
4. Construya la imagen docker usando `docker build -t poc-graphql .`
5. Ahora se ha creado una imagen llamada **poc-graphql:latest** en su máquina.
6. Ejecute el contenedor usando `docker run -p 8080:8080 poc-graphql:latest`
7. Acceda al laboratorio usando los siguientes endpoints:
* [GraphiQL](http://localhost:8080/graphiql)
* [GraphQL](http://localhost:8080/graphql)
## Debilidades de seguridad
### Autorización
*control de acceso roto*
[CWE-285](https://cwe.mitre.org/data/definitions/285.html)
#### Problema
Como GraphQL se basa en un único endpoint al que se envían todas las solicitudes y dado que la autorización está fuera del alcance de la especificación (sin funcionalidades integradas).
Depende de la aplicación implementar una lógica de autorización.
En mi laboratorio tengo una vulnerabilidad en este punto porque la verificación del token de acceso no verifica que el token pertenezca al veterinario pasado en **veterinaryId**
**Ejemplo:**
Solicito un token de acceso para **Dr Julien** que tiene el identificador **3** en el almacenamiento enviando esta solicitud GraphQL:```javascript
query getAccessToken {
auth(veterinaryName: "Julien")
}
Recibo el token de acceso en la siguiente respuesta GraphQL:```javascript { "data": { "auth": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDQyOTAyfQ.H9A-vXRsiivFGShtdhiR3N2lSDDx-sNqbbJxMRNnExI" } }
Envío una solicitud GraphQL a la consulta `myInfo(...)` usando el token de acceso obtenido, PERO especifico el identificador **2** que es el del **Dr Benoit**:```javascript
query brokenAccessControl {
myInfo(accessToken:"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDQyOTAyfQ.H9A-vXRsiivFGShtdhiR3N2lSDDx-sNqbbJxMRNnExI", veterinaryId: 2){
id, name, dogs {
name
}
}
}
Recibo en la respuesta de GraphQL la lista de Dogs asociados con Dr Benoit:```javascript { "data": { "myInfo": { "id": 2, "name": "Benoit", "dogs": [ { "name": "Babou" }, { "name": "Baboune" }, { "name": "Babylon" }, ...
#### Recomendación
Con GraphQL, pasamos de una matriz de autorización usando `Role x Feature` a seguridad a nivel de datos usando `Role x Data` porque también hay un único endpoint. La identidad del usuario y los roles deben pasarse a la capa superior encargada de obtener los datos (o actuar sobre ellos) para aplicar una verificación utilizando la identidad del usuario antes de obtener los datos.
### Injection
[CWE-20](https://cwe.mitre.org/data/definitions/20.html) / [CWE-116](https://cwe.mitre.org/data/definitions/116.html)
#### Issue
Según cómo la información de la consulta/mutación/suscripción de la solicitud GraphQL es utilizada por el servidor GraphQL para actuar sobre los almacenes de datos, existe la posibilidad de inyección.
En mis laboratorios tengo una vulnerabilidad en este punto sobre SQLi en la consulta `dogs(namePrefix: String, limit: Int = 500): [Dog!]` porque el parámetro **namePrefix** se utiliza en la concatenación de cadenas para construir una consulta SQL.
**Ejemplo:**