GraphQL 安全概览与测试技巧

本文深入探讨GraphQL技术的基本原理、常见安全风险及测试方法,包括内省查询、访问控制漏洞、SQL/NoSQL注入和DoS攻击防护,为安全工程师提供实用的测试工具和技巧。

GraphQL - 安全概览与测试技巧

2018年5月17日 - 作者:Paolo Stagno

随着GraphQL技术的日益普及,我们总结了一些关于常见安全错误的文档和技巧。

什么是GraphQL?

GraphQL是Facebook开发的一种数据查询语言,于2015年公开发布。它是REST API的替代方案。即使您没有看到任何GraphQL应用,您可能已经在使用它,因为它运行在Facebook、GitHub、Pinterest、Twitter、HackerOne等许多大型科技公司上。

关于该技术的几个关键点:

  • GraphQL提供了API中数据的完整且易于理解的描述,并赋予客户端精确请求所需数据的能力。查询总是返回可预测的结果。
  • 典型的REST API需要从多个URL加载数据,而GraphQL API在单个请求中获取应用程序所需的所有数据。
  • GraphQL API按类型和字段组织,而不是端点。您可以从单个端点访问所有数据的全部功能。
  • GraphQL是强类型的,确保应用程序只请求可能的内容,并提供清晰有用的错误信息。
  • 可以向GraphQL API添加新字段和类型,而不会影响现有查询。陈旧的字段可以被弃用并从工具中隐藏。

在深入探讨GraphQL安全领域之前,以下是其工作原理的简要回顾。官方文档写得很好,非常有用。

一个GraphQL查询如下所示:

1
2
3
4
5
6
7
8
query{
    user{
        id
        email
        firstName
        lastName
    }
}

而响应是JSON:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "data": {
        "user": {
            "id": "1",
            "email": "paolo@doyensec.com",
            "firstName": "Paolo",
            "lastName": "Stagno"
        }
    }
}

安全测试技巧

由于Burp Suite不太理解GraphQL语法,我推荐使用graphql-ide,这是一个基于Electron的应用程序,允许您编辑和发送请求到GraphQL端点;我还编写了一个小的Python脚本GraphQL_Introspection.py,用于枚举GraphQL端点(通过内省)以提取文档。该脚本可用于检查GraphQL模式,寻找信息泄漏、隐藏数据和不 intended 可访问的字段。

该工具将生成类似于以下的HTML报告:

内省用于询问GraphQL模式关于它支持哪些查询、类型等信息。

作为渗透测试员,我建议查找发送到“/graphql”或“/graphql.php”的请求,因为这些是常见的GraphQL端点名称;您还应该搜索“/graphiql”、“graphql/console/”等在线GraphQL IDE以与后端交互,以及“/graphql.php?debug=1”(调试模式,带有额外的错误报告),因为它们可能被开发人员留下开放。

测试应用程序时,验证是否可以在没有通常的授权令牌头的情况下发出请求:

由于GraphQL框架没有提供任何保护数据的手段,开发人员负责实现访问控制,如文档所述:

“然而,对于生产代码库,将授权逻辑委托给业务逻辑层。”

事情可能出错,因此重要的是验证没有适当身份验证和/或授权的用户是否可以从服务器请求整个底层数据库。

当使用GraphQL构建应用程序时,开发人员必须将数据映射到他们选择的数据库技术中的查询。这是安全漏洞容易被引入的地方,导致 Broken Access Controls、Insecure Direct Object References 甚至 SQL/NoSQL Injections。

作为一个破碎实现的例子,以下请求/响应表明我们可以获取平台上任何用户的数据(通过循环ID参数),同时转储密码哈希:

1
2
3
4
5
6
7
8
9
query{
    user(id: 165274){
        id
        email
        firstName
        lastName
        password
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
    "data": {
        "user": {
            "id": "165274",
            "email": "johndoe@mail.com",
            "firstName": "John",
            "lastName": "Doe"
            "password": "5F4DCC3B5AA765D61D8327DEB882CF99"
        }
    }
}

您必须检查的另一件事是在尝试执行非法查询时的信息泄漏:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
    "errors": [
        {
            "message": "Invalid ID.",
            "locations": [
                {
                    "line": 2,
                    "column": 12
                }
                "Stack": "Error: invalid ID\n at (/var/www/examples/04-bank/graphql.php)\n"
            ]
        }
    ]
}

尽管GraphQL是强类型的,SQL/NoSQL Injections 仍然是可能的,因为GraphQL只是客户端应用程序和数据库之间的一个层。问题可能在于开发的层,用于从GraphQL查询中获取变量以查询数据库;未正确清理的变量导致老式的简单SQL注入。

在Mongodb的情况下,NoSQL注入可能不那么简单,因为我们不能“玩弄”类型(例如,将字符串转换为数组。参见PHP MongoDB Injection)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
mutation search($filters Filters!){
    authors(filter: $filters)
    viewer{
        id
        email
        firstName
        lastName
    } 
}

{
    "filters":{
        "username":"paolo' or 1=1--"
        "minstories":0
    }
}

注意嵌套查询!它们可能允许恶意客户端通过过于复杂的查询执行DoS(拒绝服务)攻击,消耗服务器的所有资源:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
query {
 stories{
  title
  body
  comments{
   comment
   author{
    comments{
     author{
      comments{
       comment
       author{
        comments{
         comment
         author{
          comments{
           comment
           author{
            name
           }
          }
         }
        }
       }
      }
     }
    }
   }
  }
 }
}

针对DoS的简单补救措施可以是设置超时、最大深度或查询复杂性阈值。

请记住,在PHP GraphQL实现中:

  • 复杂性分析默认禁用
  • 限制查询深度默认禁用
  • 内省默认启用。这意味着任何人都可以通过发送包含元字段类型和模式的特殊查询来获取模式的完整描述

结语

GraphQL是一种新的有趣技术,可用于构建安全应用程序。由于开发人员负责实现访问控制,应用程序容易出现经典的Web应用程序漏洞,如 Broken Access Controls、Insecure Direct Object References、跨站脚本(XSS)和经典注入错误。与任何技术一样,基于GraphQL的应用程序可能容易出现开发实现错误,如这个真实例子:

“通过使用脚本,可以运行一个国家(我测试了美国、英国和加拿大)的所有可能数字组合通过这些URL,如果数字与Facebook账户关联,则可以与名称和更多详细信息(图像等)关联。”

@voidsec

资源:

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计