专栏首页Deen的代金券日记我的GraphQL安全学习之旅
原创

我的GraphQL安全学习之旅

GraphQL简介

GraphQL是Facebook的一个开源项目,定义了一种查询语言,用来代替传统的RESTful API。看到QL这样的字眼,很容易产生误解,以为是新的数据库查询语言,但其实GraphQL和数据库没有什么太大关系,GraphQL并不直接操作查询数据库,可以理解为传统的后端代码与数据库之间又多加了一层,这一层就是GraphQL.

传统的RESTful API是一个接口对应一个url,GraphQL是通过一个url接口改变请求所POST的查询参数,来达到多个api的查询效果。

GraphQL初窥

在查找GraphQL资料的过程中,都可以看到一个简单的demo,不过查询结果都是代码写死的,对于理解GraphQL和数据库之间的关系,并不是很有帮助,我写了一个简单和数据库连接的demo,python代码如下:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
import graphene
from graphene_sqlalchemy import SQLAlchemyObjectType, SQLAlchemyConnectionField
from flask_graphql import GraphQLView

app = Flask(__name__)
app.debug = True

basedir = os.path.abspath(os.path.dirname(__file__))

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:root@127.0.0.1:3306/test?charset=utf8mb4'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

db = SQLAlchemy(app)

class UserModel(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(256), index=True, unique=True)
    password = db.Column(db.String(256), index=True)

    def __repr__(self):
        return '<User %r>' % self.username
class User(SQLAlchemyObjectType):
    class Meta:
        model = UserModel
        
class Query(graphene.ObjectType):
    users = graphene.List(User)
        
    def resolve_users(self, info):
        return UserModel.query.all()
        
schema = graphene.Schema(query=Query)

@app.route('/')
def index():
    return '<p> Hello World!</p >'

app.add_url_rule(
    '/graphql',
    view_func=GraphQLView.as_view(
        'graphql',
        schema=schema,
        graphiql=True
    )
)

if __name__ == '__main__':
    app.run(host='0.0.0.0')

访问http://localhost:5000/ 即可看到demo。

query{
  users{
    id,
    password,
    name
  }
}

查询结果如下:

查询结果.png

查询出来的数据即UserModel.query.all()的执行结果。但如果我要在浏览器实现只查询id=2的用户的信息是做不到,因为后端python代码里没有写,也就是说,只有代码里写了接口,定义了相应的schema,才能通过GraphQL查询出对应结果,所以并不是通过GraphQL就能查询获取数据库所有数据

GraphQL的安全问题

如果看过p牛在先知大会上的分享——《攻击GraphQL》,会对GraphQL的安全问题有一个全面的认识。这里,在GraphQL安全问题研究上,我并没有新的发现,可以算是个人的学习笔记以及自己的一些理解。

让我们先回顾一下p牛总结的问题。

GraphQL安全问题总结.png

这ppt中提到的sql注入,个人感觉和GraphQL并不是太大关系,在不了解GraphQL的时候,一度以为看到用了GraphQL就以为找到了注入。如果代码的数据库查询都是像我上面那样的规范操作,自然是不存在sql注入的。若查询返回数据的方式使用的是原生语句查询数据库,一旦用户参数未经安全过滤进入数据库,还是存在sql注入。

至于csrf,GraphQL可以通过Mutation进行数据更改,若graphql接口未做安全校验,自然可以通过构造恶意html进行攻击。ppt中给的poc如下:

<html>
 <body>
 <script>history.pushState('', '', '/')</script>
 <form action="https://graphqlapp.herokuapp.com/" method="POST">
 <input type="hidden" name="query"
value="mutation&#32;&#123;&#10;&#32;&#32;editProfile&#40;name&#58;&quot;hac
ker&quot;&#44;&#32;age&#58;&#32;5&#41;&#32;&#123;&#10;&#32;&#32;&#32;&#32;n
ame&#10;&#32;&#32;&#32;&#32;age&#10;&#32;&#32;&#125;&#10;&#125;" />
 <input type="submit" value="Submit request" />
 </form>
 </body>
</html>

个人在挖掘src的过程中,碰到不少站点有用到GraphQL进行数据查询。发现的漏洞主要是信息泄露,和ddos拒绝服务。

发现的ddos漏洞在黑盒层面无法判断是否和GraphqQL有直接的关系,漏洞很简单,在graphql的query请求当中,有一个limit参数,当我将参数调成一个超大数字时,网站就卡死宕机了,无法判断后端哪一层崩溃了。

再回到信息泄露的问题上,个人觉得这才是大家在用GraphQL进行开发时,常忽略的地方。GraphQL可以使用schema和type查询可用的对象和对象的所有字段

如下,以我上面的demo为例,查询可用对象

query __schema{
  __schema{
    types{
      name
    }
  }
}
image.png

得到User,再查询User的字段。

 {      __type(name: "User") {
            name
            fields {
                name
                type {
                    name
                }
            }
        }
    }
image.png

在实际挖洞过程中,就可判断是否存在敏感字段,如用户的password,phone,address等。再做进一步的漏洞挖掘。

但有时目标网站可能存在几十个对象,一个一个查找出具体的字段显示是太麻烦了,是否可以编写工具进行批量查询呢?本想自己写一下,但发现已经有大佬给我们做好了。

项目在git地址为https://github.com/doyensec/graph-ql,通过这个工具可以详细列出网站的对象还有对应字段。分析他的python源码可以得到这两个payload。

query IntrospectionQuery{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}}
query IntrospectionQuery{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description args{...InputValue}onOperation onFragment onField}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name}}}}

测试效果如下,只需一次请求就可列出对象和字段。

image.png

工具的效果如下:

image.png

在实际使用过程中,常常需要修改脚本,修改post的参数名称以及返回结果的参数名,使之与实际请求结果相对应,若有登陆态校验,则还需要添加cookie,这一块脚本有待改进,有时间就造一个顺手的轮子。

至于嵌套查询导致ddos,在实际挖掘中暂时没有碰到,具体介绍可以参考freebuf的《GraphQL安全指北》这篇文章。

已经造完了

实现很简单,把上一个项目生成html的函数抠出来,再自己重写一个发送payload的请求的函数,避免修改请求头和cookie的麻烦,至于原来项目硬编码取返回包data参数导致有些情况下无法使用的问题,我添加了一个-d参数来解决,即当返回结果不是data参数时,可以指定参数名。

项目地址:https://github.com/deenrookie/x-graphql

参考

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 2020年及未来的软件编程趋势预测

    2020年马上就要到了,这听起来很疯狂。似乎2020年就像是科幻小说里的故事那么遥远,但我们在这里 — 即将敲开它的大门。

    中国DevOps社区
  • PayPal大规模采用GraphQL的探索和实践

    我们通过构建收银台体验开启了我们的 GraphQL 采用之旅。当 我们用 GraphQL 构建收银台应用程序 时,我们看到了采用 GraphQL 的巨大好处,这...

    深度学习与Python
  • 我的渗透学习之旅

    最近发现很多小伙伴都在问我想要学习渗透测试,但是不知道怎么开始,也不知道要学习什么?所以在这里我打算分享一下我的渗透学习之路以及给初学者的一些建议。

    信安之路
  • 第 432 期 Python 周刊

    链接: https://gregoryszorc.com/blog/2020/01/13/mercurial's-journey-to-and-reflecti...

    爱写bug
  • 在 Laravel 应用中构建 GraphQL API

    昨天我们学习了 在 Visual Code 中搭建 Laravel 环境,现在我们来学习 Facebook 的 GraphQL 。

    猿哥
  • 如何利用DVGA研究和学习GraphQL技术的安全实现

    DVGA(Damn Vulnerable GraphQL Application)是一款针对Facebook的GraphQL技术的安全学习工具,该项目中包含大量...

    FB客服
  • GraphQL 的入门指南

    今天最常讨论的术语之一是 API,很多人不知道 API 到底是什么,API 是 Application Programming Interface(应用程序编程...

    前端小智@大迁世界
  • Wyn Enterprise 核心功能:系统集成

    Wyn Enterprise 作为平台型产品,能够满足企业用户安装即用的需要;同时,作为工具型产品,也能够非常方便的与其他系统进行集成,包括:报表/仪表板查看器...

    葡萄城控件
  • Coursera 的 GraphQL 之旅

    Coursera 的客户端开发人员钟情于 GraphQL 的灵活性,类型安全性和良好的社区支持,我们对 GraphQL 的喜爱众~所~周~知。然而,我们并没有过...

    疯狂的技术宅
  • 写在2021: 值得关注/学习的前端框架和工具库

    最近在知乎看到了这么个问题:学完Vue还有必要学习React和Node吗?, 有很奇妙的感觉,因为我在最开始入门前端时,也是以Vue入的门,在“学完”Vue之后...

    用户7365393
  • 写在 2021: 值得关注/学习的前端框架和工具库

    最近在知乎看到了这么个问题:学完Vue还有必要学习React和Node吗?[1], 有很奇妙的感觉,因为我在最开始入门前端时,也是以Vue入的门,在“学完”Vu...

    五月君
  • 在 redux 应用中使用 GraphQL

    在 Redux 应用中获取和管理数据需要做许多工作。正如 Sashko Stubailo 指出的:

    疯狂的技术宅
  • 面对极度复杂的前后端业务场景,使用 GraphQL 正确的姿势

    本次演讲主要介绍如何使用GraphQL,分别从前后端两个角度分析GraphQL的优劣势,对比Restful又能够给前后端协同开发带来哪些好处。

    IT大咖说
  • 2019年要学习的前5个前端开发主题

    TypeScript是2018年最令人惊讶的增长故事之一.npm调查发现,有46%的npm用户使用TypeScript。它现在不仅是使用Angular的默认语言...

    硬核编程
  • JulyNovel-React

    目前,JulyNovel后端框架基本搭建、部署完毕,GraphQL提供的API接口也有着高可用性,数据库里也存了六七百兆爬来的小说数据,是时候开始写前端了。

    从今若
  • GraphQL快速入门教程

    传统的api调用一般获取到的是后端组装好的一个完整对象,而前端可能只需要用其中的某些字段,大部分数据的查询和传输工作都浪费了。graphQL提供一种全新数据查询...

    Fundebug
  • GraphQL 入门详解

    传统的api调用一般获取到的是后端组装好的一个完整对象,而前端可能只需要用其中的某些字段,大部分数据的查询和传输工作都浪费了。graphQL提供一种全新数据查询...

    Nealyang
  • 【译】Graphql, gRPC和端对端类型检验

    StackPath最近发布了新的门户网站,它让用户可以一站式地配置我们所提供的服务(CDN,WAF, DNS以及Monitoring)。这个项目涉及到整合不同的...

    腾讯IVWEB团队
  • Spring认证_什么是Spring GraphQL?

    什么是Spring GraphQL前沿学习部分:https://cloud.tencent.com/developer/article/1857280

    IT胶囊

扫码关注云+社区

领取腾讯云代金券