在使用GraphQL客户端时,请注意查询注入

起源

有人要求我作为GraphQL API的使用者参与API客户端的代码审查,所以我出席了,但是实现结果非常糟糕,让我大吃一惊,所以想要发出警示提醒一下。

首先得出结论

    • クエリの一部にユーザ入力を文字列連結するのはやめましょう!

 

    • 動的パラメータは variables で指定しましょう。

 

    • variables の指定例は以下を参照。

 

    • https://graphql.org/learn/serving-over-http/#post-request

 

    ポピュラーな GraphQL クライアントであれば、 variables に当たる変数を渡すことができるインタフェースが用意されていると思います。

注射发生的机制

不管使用什么实现语言都可以。
假设有以下API客户端实现。

const userInput = 'abc123' // これがユーザの入力値
const result = GraphQLClient.query('{ someQuery(id: "' + userInput + '") { id } }')

在这种情况下,开发者应该期望以下查询被执行。

{
  someQuery(id: "abc123") {
    id
  }
}

但是,如果用户输入是以下这种形式的话…

// こんな文字列だと...
const userInput = 'abc123") { id } users(id: "user1") { creditCardNumber } q2: someQuery(id: "abc123'
const result = GraphQLClient.query('{ someQuery(id: "' + userInput + '") { id } }')

会发出这样的查询!

{
  someQuery(id: "abc123") {
    id
  }
  users(id: "user1") {
    creditCardNumber # ヤバい情報にアクセス
  }
  q2: someQuery(id: "abc123") {
    id
  }
}

实际上,我认为没有直接输出所获得的执行结果的系统,因此攻击者能够查看creditCardNumber的查询结果的情况相当有限。
然而,以下风险仍然存在。

    • ヘビーなクエリを組み合わせて DoS 攻撃できてしまう可能性

 

    実行するのが Mutation であれば、任意の mutation を呼び出せてしまう可能性

那么,我们应该采取什么样的对策呢?

解决方案:使用变量而不是字符串连接。

在中国,动态参数是以变量的形式传递的。

 

假设使用变量,那么将重写上述查询,如下所示。

query($someId: ID!) {
  someQuery(id: $someId) {
    id
  }
}

如果是常用的GraphQL API客户端,应该提供了可以指定变量的接口,如下所示。

const userInput = ...
const variables = { id: userInput }
const result = GraphQLClient.query('query($id: ID!) { someQuery(id: $id) { id } }', { variables })
如果不使用GraphQL API客户端,而是通过HTTP层来组装请求,那么使用字符串连接来组装variables的JSON同样不可取。

变量可以指定为对象。

当在 HTTP 层面查看GraphQL的调用时,查询(看起来像JSON)是以字符串的形式指定的,因此可能会误以为变量也需要以字符串的形式指定,但实际上可以指定一个对象。
因此,甚至可以将自定义的输入类型完全从变量中传递给GraphQL。

mutation AddUser($input: AddUserInput!) {
  addUser(input: $input) {
    id
    errors { message }
  }
}
{
  "input": {
    "username": "Taro",
    "address": "Tokyo",
    "languages": [ "ja", "en" ]
  }
}

概述

由于尝试与GraphQL API进行深度通信的客户端往往从一开始就有引入GraphQL客户端库的动机,所以可能不容易遇到这个问题。
相反,那些只使用1到2个公开的GraphQL API的客户端可能会认为“使用fetch API或curl在HTTP层面上简单处理就行”,而陷入陷阱。

发生机制与其他注入漏洞完全相同呢。
它发生在跨语言边界的地方,就会出现注入问题。
就像在SQL注入防范中使用绑定变量一样,在GraphQL中,我们应该使用variables。

广告
将在 10 秒后关闭
bannerAds