Modern web ve mobil uygulamalarda tek bir endpoint üzerinden istemciye tam kontrol sunan GraphQL, sunduğu esneklik ve veri çekme verimliliğiyle yazılım mimarilerinin vazgeçilmez bir parçası haline geldi. Ancak bu esneklik, beraberinde ciddi güvenlik risklerini de getirir. Geleneksel REST mimarilerinde IP veya endpoint bazlı korumalar yeterli olabilirken, GraphQL API güvenliği mimarinin dinamik yapısı nedeniyle çok daha detaylı ve katmanlı bir yaklaşım gerektirir. Sadece tek bir HTTP POST isteği içinde sunucuyu çökertecek kadar derin dairesel sorgular (circular queries) gönderilebilir veya veritabanı kaynaklarını tüketen karmaşık istekler yapılabilir. Bu rehberde, GraphQL sistemlerinizi kötü niyetli DoS/DDoS saldırılarına, veri sızıntılarına ve aşırı kaynak kullanımına karşı korumak için GraphQL API güvenliği ve rate limiting stratejilerini somut kod örnekleriyle ele alacağız.
GraphQL Mimarisine Özel Güvenlik Tehditleri
REST API ile geliştirme yaparken istemcinin erişebileceği veriler ve URL hatları bellidir. API Nedir? REST API Temelleri ve Kullanımı yazımızda belirttiğimiz gibi REST mimarisinde her kaynak ayrı bir uç noktada sunulur. Ancak GraphQL Nedir? REST API Farkları ve WPGraphQL Kurulum Rehberi içeriğimizde incelediğimiz üzere GraphQL tek bir /graphql endpoint'i üzerinden istemcinin dilediği ağaç yapısını sorgulamasına izin verir. Bu durum saldırganlara yeni kapılar açar.
1. Dairesel ve Aşırı Derin Sorgular (Nested Query Attacks)
GraphQL şemanızda çift yönlü ilişkiler tanımladıysanız (örneğin bir User nesnesinin posts dizisine, Post nesnesinin ise tekrar author alanına sahip olması), saldırgan sonsuz döngüye giren bir sorgı yazabilir. Bu durum sunucuda belleğin (RAM) dolmasına ve Servis Dışı Bırakma (DoS) durumuna yol açar.
# Sunucu kaynaklarını eriten dairesel sorgu örneği
query CircularAttack {
user(id: "1") {
posts {
author {
posts {
author {
posts {
title
}
}
}
}
}
}
}
2. Sorgu Karmaşıklığı ve Kaynak Tüketimi (Resource Exhaustion)
Sorgu derinliği az görünse bile, yatayda devasa miktarda veri talep edilebilir. Bir istemcinin aynı istek içinde 100 farklı ilişkili alanı ve bunların alt elemanlarını istemesi, veritabanı seviyesinde onlarca ağır JOIN sorgusunun çalışmasına ve N+1 probleminin tetiklenmesine neden olur.
3. Şema Keşfi ve Introspection Saldırıları
GraphQL'in varsayılan özelliklerinden biri olan Introspection, istemcilerin API şemasındaki tüm türleri, alanları ve mutasyonları sorgulamasına imkan tanır. Geliştirme aşamasında harika bir kolaylık sağlayan bu özellik, canlı (production) ortamda açık bırakıldığında saldırganlara tüm veri yapınızı altın tepside sunar.
4. GraphQL Batching (Toplu İstem) Saldırıları
GraphQL sunucuları genellikle tek bir HTTP isteği içinde birden fazla sorgunun dizi (array) halinde gönderilmesini destekler. Saldırgan, klasik rate limit mekanizmalarını (örneğin IP başına dakikada 60 HTTP isteği) baypas etmek için tek bir HTTP isteğinin içine 500 adet login mutasyonu yerleştirebilir. Bu durum kaba kuvvet (brute-force) saldırılarını son derece etkili ve tespit edilmesi zor hale getirir.
GraphQL API Güvenliğini Sağlamak İçin 5 Temel Katman
GraphQL uygulamanızı korumak için tek bir önlem yeterli değildir. Derinlemesine savunma (Defense in Depth) prensibini uygulayarak aşağıdaki güvenlik katmanlarını devreye almanız gerekir.
1. Sorgu Derinliğini Sınırlama (Query Depth Limiting)
Gelen GraphQL sorgusunun kaç seviye derine inebileceğini kısıtlayarak dairesel DoS saldırılarını engelleyebilirsiniz. Genellikle 5 ila 8 seviye arasındaki derinlik sınırları gerçek dünya uygulamaları için fazlasıyla yeterlidir.
Node.js ve Apollo Server ortamında graphql-depth-limit paketini kullanarak bunu birkaç satırla entegre edebilirsiniz:
const express = require('express');
const { ApolloServer } = require('@apollo/server');
const depthLimit = require('graphql-depth-limit');
const schema = require('./schema');
const server = new ApolloServer({
schema,
validationRules: [depthLimit(6)] // Maksimum 6 seviye derinliğe izin verilir
});
Saldırgan 7. seviyeye inmeye çalıştığında, sorgu resolver katmanına ulaşıp veritabanına yük bindirmeden önce AST (Abstract Syntax Tree) doğrulaması aşamasında reddedilir.
2. Sorgu Karmaşıklık Analizi (Query Complexity Analysis)
Derinlik sınırı yatay genişlemeleri engelleyemez. Örneğin tek derinlikte 50 farklı ilişki çağrılabilir. Bu nedenle sorgunun toplam maliyetini (cost) hesaplayan karmaşıklık analizi uygulanmalıdır. Her alana bir puan atanır ve toplam puan belirlenen eşiği aşarsa istek engellenir.
import createComplexityLimitRule from 'graphql-query-complexity';
import { renderGraphiQL } from 'express-graphql';
const complexityRule = createComplexityLimitRule(1000, {
defaultComplexity: 1,
onCost: (cost) => console.log('Sorgu Maliyeti:', cost),
estimators: [
// Karmaşıklık hesaplama mantığı
]
});
Örneğin basit bir string alan 1 puan iken, sayfalandırma yapılan users(first: 100) alanı 100 puan olarak hesaplanabilir. Toplam maliyet 1000 puanı geçtiğinde sistem işlem yapmayı reddeder.
3. Introspection Özelliğini Üretim Ortamında Kapatmak
Canlıya alınan sistemlerde dışarıdan gelen Introspection sorgularını engellemek şema güvenliği için kritiktir.
const server = new ApolloServer({
schema,
introspection: process.env.NODE_ENV !== 'production',
});
Eğer mobil uygulamanız veya ön yüzünüz için şema dokümantasyonu gerekiyorsa, bunu kamuya açık endpoint üzerinden sunmak yerine build aşamasında statik olarak üretip yetkilendirilmiş geliştirici portalında yayınlayın.
4. Persisted Queries (Otomatik Kaydedilmiş Sorgular) Kullanımı
Güvenliği en üst seviyeye çıkarmanın en etkili yolu istemcilerin serbestçe GraphQL sorgusu göndermesini engellemektir. Automatic Persisted Queries (APQ) veya Strict Persisted Queries yaklaşımında:
{ "extensions": { "persistedQuery": { "hash": "4f..." } } }).Bu yöntem sayesinde dışarıdan gelen tüm bilinmeyen sorgular, DoS denemeleri ve kaba kuvvet saldırıları otomatik olarak geçersiz kılınır.
GraphQL Rate Limiting: Cost-Based (Maliyet Odaklı) Yaklaşım
Geleneksel REST API'lerde rate limiting IP adresinin belirli bir sürede yaptığı HTTP isteği sayısına bakar. WordPress REST API Güvenliği: Endpoint Kısıtlama ve Rate Limiting Rehberi içeriğimizde anlattığımız bu yaklaşım GraphQL dünyasında yetersiz kalır. Çünkü 1 HTTP isteği basit 1 alan dönebileceği gibi, 10.000 veritabanı satırını da getirebilir.
GraphQL için en doğru yaklaşım Cost-Based Rate Limiting (Maliyet Tabanlı İstek Sınırlama) uygulamaktır. İstemciye sabit bir HTTP istek hakkı yerine, örneğin dakikalık 5000 "Kredi/Maliyet Puanı" verilir.
Redis ve Token Bucket Algoritması ile Uygulama
GraphQL maliyet sınırlamasını Redis üzerinde Token Bucket algoritması ile kurgulayabiliriz. Mantık şu şekilde işler:
429 Too Many Requests veya GraphQL hatası dönülür.// GraphQL Rate Limiter Middleware Mantığı
async function graphqlRateLimiter(req, res, next) {
const userId = req.user ? req.user.id : req.ip;
const queryCost = calculateQueryCost(req.body.query);
const currentTokens = await redis.get(`rate_limit:${userId}`) || 2000;
if (currentTokens < queryCost) {
return res.status(429).json({
errors: [{
message: 'Rate limit aşıldı. Lütfen kredisinizin dolmasını bekleyin.',
extensions: { code: 'RATE_LIMITED', retryAfter: 60 }
}]
});
}
await redis.decrby(`rate_limit:${userId}`, queryCost);
next();
}
GitHub GraphQL API v4 gibi devasa sistemler tam olarak bu maliyet bazlı rate limit altyapısını kullanmaktadır.
GraphQL Güvenliğinde Sık Yapılan 5 Hata
Sistem mimarları ve geliştiricilerin GraphQL dağıtımlarında sıkça düştüğü hatalar şunlardır:
- 1. Sadece HTTP IP Limiting'e Güvenmek: Tek bir HTTP isteği içinde yüzlerce sorgu veya ağır veri çekilebileceğini göz ardı etmek.
- 2. Alan Seviyesinde Yetkilendirmeyi (Field-Level Authorization) Unutmak: Yetkilendirmeyi şema girişinde yapıp resolver seviyesinde kontrol etmemek. Kullanıcı A'nın
User.emailalanını okuyabilmesi ancak Kullanıcı B'nin okuyamaması gerekiyorsa bu kontrol doğrudan resolver veya veri erişim katmanında (Data Loader) yapılmalıdır. - 3. Hata Mesajlarında Veritabanı Detaylarını Sızdırmak: Production ortamında veritabanı hatalarını (SQL syntax error vb.) doğrudan GraphQL response içinde istemciye dönmek. Hatalar yakalanmalı ve maskelenmelidir.
- 4. N+1 Problemini Çözmemek: Güvenlik kadar performansı da etkileyen bu durumda,
DataLoaderkütüphanesi kullanılmadığında atılan sorgular veritabanını kilitleyerek kendiliğinden DoS etkisi yaratır. - 5. CORS Politikalarını Gevşetmek: GraphQL endpoint'ini tüm origin'lere (
*) açmak ve CSRF önlemlerini devreden çıkarmak.
REST ve GraphQL Rate Limiting Karşılaştırması
Kullanacağınız mimariye karar verirken iki yaklaşım arasındaki güvenlik farklarını dikkate almalısınız:
REST API Rate Limiting: Endpoint ve IP tabanlıdır. Tahmin edilebilir yük oluşturur. GET /users isteğinin maliyeti sabittir. Yönetimi ve önbelleklemesi (caching) kolaydır.
>
GraphQL Rate Limiting: Sorgu yapısına ve veri hacmine göre dinamik maliyet gerektirir. Önbellekleme karmaşıktır. İstemcinin sorgu gücünü kısıtlamak için yazılım katmanında hesaplama kütüphaneleri şarttır.
Sonuç ve Sonraki Adımlar
GraphQL, modern geliştirme süreçlerinde sunduğu hız ve esneklikle muazzam bir teknoloji olsa da, güvenlik mimarisi "varsayılan olarak açık ve serbest" bir mantıkla gelir. Sisteminizi korumak için Introspection özelliğini canlı ortamda kapatmakla başlayın. Ardından uygulamanıza sorgu derinliği kısıtlaması (depth limit) ve sorgu karmaşıklık analizi (query complexity) kurallarını ekleyin. İleri aşamada ise Persisted Queries mimarisine geçiş yaparak sisteminizi dışarıdan gelebilecek rastgele sorgu saldırılarına tamamen kapatabilirsiniz.
GraphQL mimarinizi güvenceye aldıktan sonra, sunucu altyapınızı korumaya yönelik ek adımlar için WordPress Güvenlik Önlemleri: Sitenizi Hackerlardan Koruma Rehberi başlığımıza göz atabilir ve genel API güvenlik standartlarınızı gözden geçirebilirsiniz.
Yorumlar (0)
Henüz yorum yapılmamış. İlk yorumu siz yapın!
Yorum Yazın