Lição 21: Não vazar credenciais ao conectar-se a serviços
Esta query GraphQL recupera credenciais de um valor de ambiente e evita que sejam impressas na resposta ou nos logs, evitando assim riscos de segurança:
query {
githubAccessToken: _env(name: "GITHUB_ACCESS_TOKEN")
@remove
_sendJSONObjectItemHTTPRequest(input:{
url: "https://api.github.com/repos/GatoGraphQL/GatoGraphQL",
method: PATCH,
options: {
auth: {
password: $__githubAccessToken
},
body: "{\"has_wiki\":false}"
}
})
}A seguir há uma explicação de como essa query funciona.
Como as credenciais podem ser vazadas
Frequentemente precisamos fornecer credenciais ao conectar-se a serviços externos. Por exemplo, a REST API do GitHub requer um token de acesso para endpoints onde os dados são privados ou são modificados:
query {
_sendJSONObjectItemHTTPRequest(input:{
url: "https://api.github.com/repos/GatoGraphQL/GatoGraphQL",
method: PATCH,
options: {
auth: {
password: "{ GITHUB_ACCESS_TOKEN }"
},
body: "{\"has_wiki\":false}"
}
})
}Precisamos ter cuidado e evitar expor nossas credenciais:
- Na query GraphQL: As credenciais nunca devem ser incorporadas no código-fonte, pois estariam em texto simples, criando um risco de segurança
- Na resposta GraphQL: Se o campo que se conecta ao serviço produzir um erro, uma mensagem de erro será adicionada na resposta GraphQL sob a entrada
errors; essa mensagem pode imprimir o nome do campo que falhou junto com seus argumentos, imprimindo assim as credenciais - Nos logs do servidor: Se as credenciais forem acessadas por meio de uma variável, e essa variável for fornecida como parâmetro de URL, ela poderá ser registrada nos logs do servidor web
Query GraphQL que evita o vazamento de credenciais
Esta query GraphQL passa as credenciais para a API do GitHub evitando o vazamento das credenciais:
query {
githubAccessToken: _env(name: "GITHUB_ACCESS_TOKEN")
@remove
_sendJSONObjectItemHTTPRequest(input:{
url: "https://api.github.com/repos/GatoGraphQL/GatoGraphQL",
method: PATCH,
options: {
auth: {
password: $__githubAccessToken
},
body: "{\"has_wiki\":false}"
}
})
}Isso ocorre porque:
- As credenciais são recuperadas de uma variável de ambiente
GITHUB_ACCESS_TOKEN, portanto não precisam ser incorporadas no código-fonte - O campo
githubAccessTokené removido com@remove, portanto não é impresso na resposta - O input
_sendJSONObjectItemHTTPRequest(auth:)referencia a variável dinâmica$__githubAccessToken, portanto se o campo produzir um erro, é a string literal"$__githubAccessToken"que será impressa na mensagem de erro (não o seu valor)
Para demonstrar o último item, fornecer à API do GitHub a URL de um repositório inexistente "leoloso/NonExisting" gera um erro, e obtemos esta resposta (observe auth: {password: $__githubAccessToken} na mensagem de erro):
{
"errors": [
{
"message": "Client error: `PATCH https://api.github.com/repos/leoloso/NonExisting` resulted in a `404 Not Found` response:\n{\"message\":\"Not Found\",\"documentation_url\":\"https://docs.github.com/rest/repos/repos#update-a-repository\"}\n",
"locations": [
{
"line": 21,
"column": 3
}
],
"extensions": {
"path": [
"_sendJSONObjectItemHTTPRequest(input: {url: \"https://api.github.com/repos/leoloso/NonExisting\", method: PATCH, options: {auth: {password: $__githubAccessToken}, body: \"{\"has_wiki\":false}\"}})",
"query { ... }"
],
"type": "QueryRoot",
"field": "_sendJSONObjectItemHTTPRequest(input: {url: \"https://api.github.com/repos/leoloso/NonExisting\", method: PATCH, options: {auth: {password: $__githubAccessToken}, body: \"{\"has_wiki\":false}\"}})",
"id": "root",
"code": "PoP/ComponentModel@e1"
}
}
],
"data": {
"_sendJSONObjectItemHTTPRequest": null
}
}