GraphQL isteklerini koruyabilir miyim?
Kısa cevap
Evet; GraphQL'e özgü bir ayrıştırıcı, sorgu derinliği ya da sorgu maliyeti analizi olmadan, JSON ve imza denetimleriyle. GraphQL isteği çoğunlukla application/json gövdeyle ({"query": "…", "variables": {…}}) geldiği için WAF gövdeyi JSON olarak ayrıştırır: query metni ve değişken değerleri JSON kapsamlı imzalarla taranır; GET ile gelen sorgu query parametresi olarak taranır. Kütüphanede introspection (__schema) sorguları, toplu ve alias'lı sorgular, derin iç içe sorgularla hizmet engelleme, yetkisiz mutation'lar ve değişkenlerin içinden SQL ya da NoSQL injection için 34 kural bulunur; bu kurallar tek bir kategoride değil farklı kategorilerdedir ve Signature & Rule Library'de adla aranır. Derin iç içe sorgu kurallarının üçü (Graphql Nested Query Dos, GraphQL Deep Nesting DoS, GraphQL fragment-cycle / entity-expansion DoS) yalnızca URL'deki query parametresinde çalışır; JSON gövdede iç içe sorgu için 4 puanlı bir kural vardır. JSON Depth yalnızca JSON zarfının derinliğini ölçer, GraphQL sorgusunun iç içeliğini ölçmez. Pozitif tarafta GraphQL endpoint'ine yalnızca POST izni verilir, Allowed JSON Keys ile query, operationName ve variables yolları sınırlanır ve query alanına JSON Value Length sınırı konur. application/graphql türüyle gelen düz metin sorgular ham gövde (RAW) olarak taranır.
Sorun: GraphQL Tek Endpoint'te Bütün API'yi Taşır
GraphQL bütün işlemleri tek bir endpoint'ten (genellikle /graphql) alır; hangi verinin isteneceği path ya da query parametreleriyle değil, gövdedeki sorgu metniyle belirlenir. Bu yüzden endpoint ve metot düzeyindeki pozitif denetimler tek başına yetmez; saldırılar sorgu metninin ve değişkenlerin içindedir (OWASP GraphQL Cheat Sheet).
WAF bir GraphQL isteğini şöyle işler:
| İstek biçimi | Nasıl denetlenir |
|---|---|
POST, Content-Type: application/json | Gövde JSON olarak ayrıştırılır; query metni ve variables altındaki her metin değeri JSON kapsamlı imzalarla ayrı ayrı taranır. |
GET, ?query=… | Sorgu metni query parametresi değeri olarak taranır. |
POST, Content-Type: application/graphql | Gövde ham içerik olarak taranır; içerik türü gövdeden belirlenir ve Allowed Raw Body Mime Types listesine göre denetlenir (Allowed Raw Body Mime Types ne işe yarar?). |
| WebSocket üzerinden subscription | Yalnızca bağlantıyı açan ilk HTTP isteği denetlenir. |
GraphQL'e özgü kurallardan bazıları ve kütüphanedeki desenlerle denenmiş örnekler:
| Kural | Kapsam | Puan | Örnek |
|---|---|---|---|
| GraphQL Schema Introspection | Query, JSON, form | 8 | {__schema{types{name}}} |
| GraphQL Introspection Type Query | Query, JSON, form | 8 | __type sorguları |
| GraphQL Dangerous Mutation Privilege Escalation | Query, JSON, form | 8 | mutation { deleteAllUsers } |
| GraphQL Batched Query · GraphQL Aliased Batch Queries | Query, JSON, form | 6 | Toplu ve alias'lı sorgular |
| SQL injection inside a GraphQL argument value | JSON | 8 | Argüman değerinde SQL injection |
| GraphQL Variable NoSQL Injection | Query, JSON, form, ham gövde | 8 | Değişkende NoSQL operatörü |
| GraphQL Deep Nesting DoS · GraphQL fragment-cycle / entity-expansion DoS | Yalnızca query parametresi | 8 | GET ile gelen derin sorgu |
| Graphql Nested Query Dos | Yalnızca query parametresi | 6 | GET ile gelen derin sorgu |
| GraphQL nested-query DoS | JSON, ham gövde | 4 | POST ile gelen derin sorgu |
Kuralların puan dağılımı: 11 kural 8, 19 kural 6, 3 kural 4 ve 1 kural 2 puandır. Bir istekte birden çok kural eşleşirse puanlar toplanır.
Çözüm
İmza taraması GraphQL endpoint'i WAF'ın kapsamına girdiği anda çalışır. Aşağıdaki yapılandırma pozitif denetimleri ekler. Ön koşul: vService'te WAF açıktır (Bir vService'te WAF korumasını nasıl etkinleştiririm?).
GraphQL Endpoint'inin Sayfa Tipi
- Nasıl çalışır
/graphqliçin bir sayfa tipi metotları sınırlar; JSON ortak kuralı gövdede yalnızca beklenen anahtarlara izin verir, değişken kuralı sorgu metninin uzunluğunu sınırlar. - Nerede açılır Left Monitor Panel → WAF-Protected vServices → vService → WAF Management → N page types → Add · kural → JSON sekmesi
- Gereksinim WAF alanında değiştirme yetkisi; Checks'te Structure Checks ve Argument Checks açık; host grubu Monitor ya da Blocking modunda
- vService tipi HTTP
Adım adım yapılandırma
WAF Management sekmesinde Checks kartının kalem ikonu tıklanır; Structure Checks ve Argument Checks işaretli olmalıdır. Değişiklik yapıldıysa Edit tıklanır.
WAF Management sekmesinde host grubunun mod kartı altındaki N page types satırına tıklanır.
Araç çubuğundaki Add tıklanır (Add).
Path = /graphql yazılır; Allowed Methods = Multiple Methods seçilip POST işaretlenir. Uygulama GET ile de sorgu gönderiyorsa GET de seçilir (Bir sayfaya yalnızca belirli HTTP metotlarına izin verebilir miyim (Allowed Methods)?).
Formdaki Add tıklanır.
Listede /graphql kuralına tıklanır; sağdaki detay panelinde JSON sekmesi seçilip Add Common Rule for JSON tıklanır.
Allowed JSON Keys kısıtı açılıp query, operationName, variables ve uygulamanın kullandığı değişken yolları (ör. variables.id, variables.input, variables.input.email) eklenir; kapsayıcı yollar da listede olmalıdır (JSON'da yalnızca belirli anahtarların gelmesine izin verebilir miyim; iç içe anahtar yolları nasıl yazılır?). Değişken sayısı fazlaysa liste Max. Allowed Arguments değerini aşmamalıdır. Block Invalid JSON Contents işaretlenir.
Formdaki Add tıklanır.
Aynı sekmede Add Argument Rule for JSON tıklanır.
Argument Name = query yazılır; JSON Value Length = Less Than or Equal To ile uygulamanın en uzun meşru sorgusunun bayt uzunluğundan biraz büyük bir değer girilir. Uzunluk sınırı aşırı büyük, toplu ya da derin sorguları yapısal ihlal olarak işaretler (Bir parametrenin değerini uzunluk veya regex desenle kısıtlayabilir miyim (Value length / Value pattern)?).
Formdaki Add tıklanır; ayrı bir dağıtım adımı yoktur. Kural seti önce Monitor modunda denenir (Learning modundan Monitor'a, Monitor'dan Blocking'e ne zaman geçmeliyim?). Cluster'da değişiklikler varsayılan auto-sync ile eş cihaza gönderilir; Manual Sync Mode açıksa Synchronize ile gönderilir.
Doğrulama
Introspection sorgusu gönderilir ve Event Logs kaydının Attacks sekmesine bakılır.
Komut: curl -s -o /dev/null -w "%{http_code}\n" -H "Content-Type: application/json" -d '{"query":"{__schema{types{name}}}"}' https://api.example.com/graphql
GraphQL Schema Introspection (8)Gövdeye listede olmayan bir anahtar eklenerek istek gönderilir.
Allowed JSON keys (24)Sık Yapılan Hatalar
- JSON Depth'in GraphQL sorgusunun derinliğini sınırladığını sanmak. JSON Depth yalnızca JSON zarfının (
{"query": …, "variables": {…}}) derinliğini ölçer; sorgu metni JSON'da tek bir metin değeridir. Sorgunun boyutuqueryalanına konan JSON Value Length ile sınırlanır. - GraphQL kurallarını tek bir kategoride aramak. Kurallar Information Disclosure, Application DoS, Data Query Injection, Access Control Bypass gibi kategorilere dağılmıştır; Signature & Rule Library'de Search alanına
GraphQLyazılarak listelenir. - Değişkenler için JSON Value Pattern'i yasak listesi gibi kullanmak. Değer deseni pozitif bir denetimdir: değer desene uymadığında ihlal üretilir; "şunu içermesin" biçiminde yazılmaz.
- Content-Type'ı denetlememek. JSON denetimleri yalnızca Content-Type
…/jsonya da+jsonile bittiğinde çalışır;application/graphqlile gelen sorgu ham gövde olarak taranır ve JSON sekmesindeki denetimlerden geçmez. - Değişken yollarını unutmak.
variablesaltındaki her kullanılan yol Allowed JSON Keys listesinde bulunmalıdır; aksi hâlde meşru istekler 24 puanlık ihlal üretir.
Dokümantasyonda nasıl yapılır
İlgili sorular
- İmzalar isteğin hangi bölümlerinde taranır (Path, Query, Header, JSON, XML, Form ve Raw)?
- JSON'da yalnızca belirli anahtarların gelmesine izin verebilir miyim; iç içe anahtar yolları nasıl yazılır?
- Allowed Raw Body Mime Types ne işe yarar?
- Bir sayfaya yalnızca belirli HTTP metotlarına izin verebilir miyim (Allowed Methods)?
