Object Limit Overriding in GraphQL
GraphQL 中的对象限制覆盖
描述
GraphQL 中的对象限制覆盖(Object Limit Overriding)是指攻击者可以操纵查询参数以超过 API 预期限制的漏洞。这通常涉及将极大的值传递给分页或限制参数,从而可能导致拒绝服务(DoS)攻击或过度消耗资源。
潜在风险:
拒绝服务(DoS): 通过请求过多的对象,攻击者可以使服务器不堪重负,导致性能下降或中断。
资源耗尽: 请求大量对象的查询可能会使服务器的内存和处理能力超载。
数据暴露: 在某些情况下,绕过限制可能会导致未经授权访问大量数据。
成本增加: 对于基于云的服务,由于资源使用率高,处理具有极大限制的查询可能会导致意想不到的成本。
存在漏洞的查询示例:
query {
users(first: 1000000) {
id
name
email
}
}
建议
为了缓解 GraphQL 中对象限制覆盖的风险,请实施以下措施:
查询复杂性分析: 使用工具或库来分析并限制传入查询的复杂性。诸如 graphql-query-complexity 之类的库可以提供帮助。
速率限制(Rate Limiting): 实施速率限制,以限制单个用户或 IP 地址在特定时间范围内可以发送的查询数量。
分页和限制: 对单个查询返回的数据量应用限制。确保使用分页来控制数据量。
Example Implementation:
const { ApolloServer, gql } = require('apollo-server');
const { getComplexity, simpleEstimator, fieldExtensionsEstimator } = require('graphql-query-complexity');
const { GraphQLObjectType, GraphQLInt, GraphQLString, GraphQLSchema } = require('graphql');
// Define your GraphQL schema
const typeDefs = gql`
type Query {
hello: String
user(id: ID!): User
}
type User {
id: ID!
name: String
age: Int
}
`;
// Define your resolvers
const resolvers = {
Query: {
hello: () => 'Hello world!',
user: (_, { id }) => ({
id,
name: 'John Doe',
age: 30,
}),
},
};
// Create an Apollo Server instance with query complexity analysis
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [
{
// This plugin computes the complexity of incoming queries
requestDidStart: () => ({
didResolveOperation({ request, document }) {
const complexity = getComplexity({
schema: server.schema,
query: document,
variables: request.variables,
estimators: [
fieldExtensionsEstimator(),
simpleEstimator({ defaultComplexity: 1 }),
],
});
// Define a maximum complexity limit
const maxComplexity = 100;
// Check if the query complexity exceeds the maximum allowed
if (complexity > maxComplexity) {
throw new Error(`Query is too complex: ${complexity}. Maximum allowed complexity: ${maxComplexity}`);
}
},
}),
},
],
});
// Start the server
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
from graphql import parse, execute, validate, GraphQLError
from graphql.language.visitor import visit, Visitor
class ComplexityVisitor(Visitor):
def __init__(self):
self.complexity = 0
self.max_complexity = 100
def enter_field(self, node, key, parent, path, ancestors):
complexity = 1 # Base complexity for each field
self.complexity += complexity
if self.complexity > self.max_complexity:
raise GraphQLError(f"Query complexity exceeds maximum allowed complexity of {self.max_complexity}")
def complexity_middleware(schema, query):
document = parse(query)
visitor = ComplexityVisitor()
visit(document, visitor)
return visitor.complexity
def execute_with_complexity_check(schema, query, variables=None):
complexity = complexity_middleware(schema, query)
if complexity > 100:
raise GraphQLError(f"Query complexity exceeds maximum allowed complexity of 100")
result = execute(schema, parse(query), variable_values=variables)
return result
By using these recommendations and configurations, you can better protect your GraphQL APIs from the risks associated with object limit overriding.
链接
- GraphQL Vulnerabilities and Common Attacks: What You Need to Know
- OWASP GraphQL Security Cheat Sheet
标准
- CWE_TOP_25:
- CWE_20
- CWE_400
- PCI_STANDARDS:
- REQ_6_1
- REQ_6_2
- REQ_6_4
- REQ_11_3
- OWASP_MASVS_L2:
- MSTG_PLATFORM_2
- OWASP_ASVS_L3:
- V13_4_1
- SOC2_CONTROLS:
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5
- CC_9_1
- HIPAA_CONTROLS:
- SECURITY212
- SECURITY213