Pelajaran 21: Tidak membocorkan kredensial saat terhubung ke layanan
Query GraphQL ini mengambil kredensial dari nilai lingkungan, dan menghindari agar tidak tercetak dalam respons atau log, sehingga menghindari risiko keamanan:
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}"
}
})
}Berikut adalah penjelasan tentang cara kerja query ini.
Bagaimana kredensial bisa bocor
Kita sering perlu menyediakan kredensial saat terhubung ke layanan eksternal. Misalnya, REST API GitHub memerlukan token akses untuk endpoint di mana data bersifat privat atau dimutasi:
query {
_sendJSONObjectItemHTTPRequest(input:{
url: "https://api.github.com/repos/GatoGraphQL/GatoGraphQL",
method: PATCH,
options: {
auth: {
password: "{ GITHUB_ACCESS_TOKEN }"
},
body: "{\"has_wiki\":false}"
}
})
}Kita perlu berhati-hati dan menghindari pemaparan kredensial kita:
- Dalam query GraphQL: Kredensial tidak boleh pernah disematkan dalam kode sumber, karena akan berada dalam teks biasa, menciptakan risiko keamanan
- Dalam respons GraphQL: Jika field yang terhubung ke layanan menghasilkan error, pesan error akan ditambahkan dalam respons GraphQL di bawah entri
errors; pesan ini mungkin mencetak nama field yang gagal beserta argumennya, sehingga mencetak kredensial - Dalam log server: Jika kredensial diakses melalui variabel, dan variabel ini disediakan sebagai parameter URL, maka mungkin akan dicatat dalam log server web
Query GraphQL yang menghindari kebocoran kredensial
Query GraphQL ini meneruskan kredensial ke API GitHub sambil menghindari kebocoran kredensial:
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}"
}
})
}Hal ini karena:
- Kredensial diambil dari variabel lingkungan
GITHUB_ACCESS_TOKEN, sehingga tidak perlu disematkan dalam kode sumber - Field
githubAccessTokendi-@remove, sehingga tidak tercetak dalam respons - Input
_sendJSONObjectItemHTTPRequest(auth:)mereferensikan variabel dinamis$__githubAccessToken, sehingga jika field menghasilkan error, yang akan dicetak dalam pesan error adalah string literal"$__githubAccessToken"(bukan nilainya)
Untuk mendemonstrasikan item terakhir, memberikan URL repositori yang tidak ada "leoloso/NonExisting" ke API GitHub menghasilkan error, dan kita mendapatkan respons ini (perhatikan auth: {password: $__githubAccessToken} dalam pesan error):
{
"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
}
}