Hướng dẫn schema
Hướng dẫn schemaBài 21: Không rò rỉ thông tin xác thực khi kết nối đến dịch vụ

Bài 21: Không rò rỉ thông tin xác thực khi kết nối đến dịch vụ

Query GraphQL này lấy thông tin xác thực từ một biến môi trường, và tránh in chúng ra trong phản hồi hoặc nhật ký, từ đó tránh các rủi ro bảo mật:

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}"
    }
  })
}

Dưới đây là giải thích về cách query này hoạt động.

Thông tin xác thực có thể bị rò rỉ như thế nào

Chúng ta thường cần cung cấp thông tin xác thực khi kết nối đến các dịch vụ bên ngoài. Ví dụ, REST API của GitHub yêu cầu access token cho các endpoint nơi dữ liệu là riêng tư hoặc bị thay đổi:

query {
  _sendJSONObjectItemHTTPRequest(input:{
    url: "https://api.github.com/repos/GatoGraphQL/GatoGraphQL",
    method: PATCH,
    options: {
      auth: {
        password: "{ GITHUB_ACCESS_TOKEN }"
      },
      body: "{\"has_wiki\":false}"
    }
  })
}

Chúng ta cần cẩn thận và tránh để lộ thông tin xác thực của mình:

  • Trong query GraphQL: Thông tin xác thực không bao giờ được nhúng vào mã nguồn, vì chúng sẽ ở dạng văn bản thuần túy, tạo ra rủi ro bảo mật
  • Trong phản hồi GraphQL: Nếu field kết nối đến dịch vụ tạo ra lỗi, một thông báo lỗi sẽ được thêm vào phản hồi GraphQL dưới mục errors; thông báo này có thể in tên của field bị lỗi cùng với các đối số của nó, do đó in ra thông tin xác thực
  • Trong nhật ký máy chủ: Nếu thông tin xác thực được truy cập qua một biến, và biến này được cung cấp dưới dạng tham số URL, thì nó có thể được ghi vào nhật ký của máy chủ web

Query GraphQL tránh rò rỉ thông tin xác thực

Query GraphQL này truyền thông tin xác thực đến API của GitHub trong khi tránh rò rỉ thông tin xác thực:

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}"
    }
  })
}

Điều này là vì:

  • Thông tin xác thực được lấy từ biến môi trường GITHUB_ACCESS_TOKEN, do đó không cần nhúng chúng vào mã nguồn
  • Field githubAccessToken được @remove (xóa), do đó nó không được in ra trong phản hồi
  • Input _sendJSONObjectItemHTTPRequest(auth:) tham chiếu đến biến động $__githubAccessToken, do đó nếu field tạo ra lỗi, chính chuỗi ký tự "$__githubAccessToken" sẽ được in trong thông báo lỗi (không phải giá trị của nó)

Để minh họa điểm cuối cùng, việc cung cấp URL của một repository không tồn tại "leoloso/NonExisting" cho API của GitHub sẽ tạo ra lỗi, và chúng ta nhận được phản hồi này (lưu ý auth: {password: $__githubAccessToken} trong thông báo lỗi):

{
  "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
  }
}