Chương 27: GraphQL Security
Khái niệm
GraphQL là query language cho APIs, cho phép client specify exactly data nào muốn nhận. GraphQL có attack surface riêng biệt so với REST APIs.
Mức độ nguy hiểm: Trung bình-Cao — Phụ thuộc vào implementation.
GraphQL vs REST
REST: Nhiều endpoints, server quyết định response format
/api/users → {id, name, email, orders, ...}
GraphQL: 1 endpoint, client quyết định
POST /graphql
{
query: "{ user(id: 1) { name email } }"
}
→ Chỉ trả name và email
Introspection — Information Disclosure
Introspection cho phép query schema của API:
# Lấy toàn bộ schema
query IntrospectionQuery {
__schema {
types {
name
fields {
name
type { name }
}
}
}
}
# Response:
{
"types": [
{"name": "User", "fields": [
{"name": "id"}, {"name": "email"},
{"name": "password"}, {"name": "creditCard"} # ← Nhạy cảm!
]},
{"name": "AdminDashboard", "fields": [...]} # ← Hidden endpoint lộ!
]
}
Tắt introspection trong production:
// Apollo Server
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: process.env.NODE_ENV !== 'production',
});
IDOR qua GraphQL
# Tấn công IDOR
query {
user(id: 1) { # Thay đổi ID
name
email
creditCard { number }
}
}
Nếu resolver không check authorization → IDOR.
Batching Attack — Bypass Rate Limiting
# Gửi nhiều queries trong 1 request
[
{"query": "mutation { login(username: 'admin', password: 'pass1') }"},
{"query": "mutation { login(username: 'admin', password: 'pass2') }"},
{"query": "mutation { login(username: 'admin', password: 'pass3') }"},
... (1000 queries)
]
# Nếu rate limiting per-request (không per-query):
# 1 request với 1000 queries → bypass rate limit
DoS qua Deep Query
# Deeply nested query → exponential resources
query {
users {
friends {
friends {
friends {
friends {
# ... nested 10+ levels
name
}
}
}
}
}
}
Phòng chống
// 1. Disable introspection
introspection: process.env.NODE_ENV === 'production' ? false : true
// 2. Query depth limiting
const depthLimitPlugin = createComplexityLimitRule(1000, {
scalarCost: 1,
objectCost: 2,
listFactor: 10
});
// 3. Query complexity analysis
const { createComplexityLimitRule } = require('graphql-validation-complexity');
const rules = [createComplexityLimitRule(1000)];
// 4. Authorization trong resolvers
const resolvers = {
Query: {
user: async (_, { id }, context) => {
// Check authorization
if (context.user.id !== id && !context.user.isAdmin) {
throw new ForbiddenError('Not authorized');
}
return db.getUser(id);
}
}
};
// 5. Disable batching hoặc limit batch size
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [ApolloServerPluginLandingPageDisabled()],
allowBatchedHttpRequests: false // Disable batching
});
Tóm tắt
- GraphQL: 1 endpoint flexible → larger attack surface.
- Introspection lộ schema → disable in production.
- IDOR trong resolvers nếu không check ownership.
- Batching bypass rate limiting.
- Deep queries → DoS.
- Phòng chống: disable introspection, depth/complexity limits, auth trong resolvers.
Câu hỏi ôn tập
- Clickjacking có thể bypass SameSite cookie như thế nào?
- Cache poisoning với "unkeyed inputs" nghĩa là gì?
- Trong HTTP request smuggling, CL.TE và TE.CL khác nhau như thế nào?
- SSTI khác SQL injection ở điểm nào? Cả hai đều là injection attacks.
- Tại sao GraphQL introspection nên disabled trong production?