Brute Force Login Using Alias Batching in GraphQL API
在 GraphQL API 中使用别名批处理进行暴力破解登录
描述
在 GraphQL 中使用别名批处理的暴力登录涉及攻击者利用别名功能来自动进行登录尝试,从而可以更轻松地在单个查询中提交大量凭据组合。
在 GraphQL 中,别名允许客户端在不同的名称下发送相同查询的多个版本。攻击者利用这一点,通过为每次尝试使用不同的别名,在单个查询中批量处理登录请求。这可能导致有效的暴力攻击,绕过传统的速率限制保护(rate limiting)并通过登录尝试压垮身份验证系统。
示例:
query loginBatch {
login1: login(username: "user1", password: "password1") { token }
login2: login(username: "user2", password: "password2") { token }
login3: login(username: "user3", password: "password3") { token }
...
}
建议
为了减轻使用别名批处理进行暴力登录攻击的风险,请考虑实施以下措施:
-
限制别名:在服务器端配置单个 GraphQL 查询中允许的别名数量上限。您可以配置像 GraphQL Armor 这样的工具来限制别名并防止超载。
-
实施 CAPTCHA:引入 CAPTCHA 或其他用户验证机制,在达到一定次数的登录失败尝试后对用户提出质询,从而增加一层额外的保护。
// Configuring rate limiting and alias limits for a GraphQL server
const express = require('express');
const rateLimit = require('express-rate-limit');
const { ApolloServer, gql } = require('apollo-server-express');
const { GraphQLArmorConfig } = require('graphql-armor');
const app = express();
// Rate limit for login attempts
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // limit each IP to 5 requests per windowMs
message: "Too many login attempts, please try again later."
});
// Define your GraphQL schema
const typeDefs = gql`
type Query {
login(username: String!, password: String!): String
}
`;
// Implement the alias limit configuration
GraphQLArmorConfig({
maxAliases: {
enabled: true,
n: 20, // Set the maximum number of aliases allowed per query
onAccept: [],
onReject: [],
propagateOnRejection: true,
}
});
const server = new ApolloServer({ typeDefs, resolvers });
// Apply rate limiter middleware
app.use('/graphql', loginLimiter);
server.applyMiddleware({ app });
app.listen({ port: 4000 }, () =>
console.log(`Server ready at http://localhost:4000${server.graphqlPath}`)
);
import graphql
from graphql.language import ast
from graphql.language import parser
from settings import api
def validate_aliases(query: str) -> None:
"""
This validation prevents the execution of queries containing an excessive
number of aliases to prevent server overload.
"""
class AliasesParser(parser.Parser):
def parse_aliases(self) -> list[ast.FieldNode]:
aliases = 0
while self.peek(graphql.TokenKind.NAME):
aliases += 1
if aliases > api.API_MAX_ALIASES:
raise graphql.GraphQLError("Exception - Max aliases exceeded")
self.parse_field()
return []
ast_parser = AliasesParser(query)
ast_parser.parse_document()
链接
标准
- PCI_STANDARDS:
- REQ_6_2
- REQ_6_4
- REQ_11_3
- OWASP_ASVS_L3:
- V13_4_1
- SOC2_CONTROLS:
- CC_2_1
- CC_4_1
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5
- CC_9_1
- HIPAA_CONTROLS:
- SECURITY221
- SECURITY212
- SECURITY213