随着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查询如下所示:
基本GraphQL查询
query{ user{ id email firstName lastName } }
而响应是JSON:
基本GraphQL响应
{ "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模式,查找信息泄漏、隐藏的数据以及不再访问的字段。
该工具将生成一个类似于下面的HTML报告:
内省用来请求一个GraphQL模式,来获取关于它所支持的查询、类型等的信息。
作为一个pentester,我建议查找发送到“/graphql”或“/graphql”的请求。因为这些通常是GraphQL的端点名称;还应该搜索“/graphiql”、“graphql/console/”、与后端交互的在线GraphQL IDE,以及 “/graphql.php?debug=1”(附加错误报告的调试模式),因为这些可能会被开发人员以打开的状态搁置。
在测试应用程序时,验证是否可以在没有通常的授权令牌头的情况下发出请求:
由于GraphQL框架没有提供任何方法来保护你的数据,开发人员负责实现文档中所述的访问控制:
但是,对于产品代码库来说,将授权逻辑委托给业务逻辑层。
这可能会出现错误,因此需要验证没有适当身份验证和/或授权的用户是否可以从服务器请求整个底层数据库。
在使用GraphQL构建应用程序时,开发人员必须将数据映射到所选数据库技术中的查询。这就是安全漏洞很容易被引入的地方,导致访问控制的中断、不安全的直接对象引用,甚至SQL/NoSQL注入。
作为一个中断实现的示例,以下请求/响应表明我们可以为平台的任何用户获取数据(通过ID参数循环),同时转储密码哈希:
查询
query{ user(id: 165274){ id email firstName lastName password } }
响应
{ "data": { "user": { "id": "165274", "email": "johndoe@mail.com", "firstName": "John", "lastName": "Doe" "password": "5F4DCC3B5AA765D61D8327DEB882CF99" } } }
另一件你需要检查的事情是在试图执行非法查询时的相关信息披露:
信息披露
{ "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注入仍然是可能的,因为GraphQL只是客户应用程序和数据库之间的一层。问题可能存在于为了从GraphQL查询中提取变量所开发的层中,开发该层的目的是询问数据库;没有正确检查的变量会导致较老的简单SQL注入。对于Mongodb, NoSQL注入可能不是那么简单,因为我们不能“处理”类型(例如,将字符串转换成数组。请参阅PHP MongoDB注入)。
GraphQL SQL注入
mutation search($filters Filters!){ authors(filter: $filters) viewer{ id email firstName lastName } } { "filters":{ "username":"paolo' or 1=1--" "minstories":0 } }
谨防嵌套查询!该查询允许带有恶意的客户端通过过度复杂的查询执行DoS(拒绝服务)攻击,该攻击将消耗服务器的所有资源:
嵌套查询
query { stories{ title body comments{ comment author{ comments{ author{ comments{ comment author{ comments{ comment author{ comments{ comment author{ name } } } } } } } } } } } }
可以设置一个超时、最大深度或查询复杂性阈值,对DoS攻击进行一个简单的补救。
在PHP GraphQL实现中请谨记:
· 默认情况下禁用复杂性分析。
· 默认情况下禁用限制查询深度。
· 默认情况下内省是启用的。这意味着任何人都可以通过发送包含元字段类型和模式的特殊查询来获取对你的模式的完整描述。
总结
GraphQL是一种新的有趣的技术,它可以用来构建安全的应用程序。由于开发人员负责实现访问控制,所以用其构建的应用程序容易受到传统web应用程序的攻击,如破坏访问控制、不安全的直接对象引用、跨站脚本(XSS)和典型的注入错误。与其他任何技术一样,基于GraphQL的应用程序可能容易出现开发实现错误,比如下面这个真实的例子:
通过使用一个脚本,整个国家(我测试了美国、英国和加拿大)可能的数字组合可以通过这些url来运行,并且如果一个数字与Facebook账户相关联,那么它就很可能与一个名字和更多的细节(图像,等等)有联系。