Ana Karargâh Neler Yapıyoruz?
Hikayemizin Perde Arkası Beyin Kıvılcımları Bağlantıya Geçin

GraphQL Güvenliği: Derinlik Limitleme ve Query Whitelisting

Merhaba değerli okuyucular! Bugün, modern web uygulamalarında giderek daha popüler hale gelen GraphQL'in güvenlik yönlerini, özellikle de derinlik limitleme ve query whitelisting tekniklerini inceleyeceğiz. Bu güvenlik önlemlerinin nasıl uygulanacağını ve neden önemli olduklarını detaylıca ele alacağız. Hazırsanız, GraphQL güvenliğinin derinliklerine dalalım!

GraphQL Güvenlik Riskleri

GraphQL'in esnek yapısı, bazı güvenlik risklerini de beraberinde getirir:

  • Karmaşık ve maliyetli sorgular
  • Derinlik saldırıları
  • Hassas veri sızıntıları
  • DoS (Denial of Service) saldırıları

Derinlik Limitleme

Derinlik limitleme, bir GraphQL sorgusunun ne kadar derinleşebileceğini sınırlar. Bu, potansiyel olarak maliyetli ve tehlikeli derinlik saldırılarını önler.

Derinlik Limitleme Örneği (Node.js ve graphql-depth-limit):


const { ApolloServer } = require('apollo-server');
const depthLimit = require('graphql-depth-limit');

const server = new ApolloServer({
  typeDefs,
  resolvers,
  validationRules: [depthLimit(5)] // Maksimum 5 seviye derinlik
});

server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

Özel Derinlik Limitleme Fonksiyonu:


function createDepthLimitRule(maxDepth) {
  return function (validationContext) {
    return {
      Field(node, key, parent, path, ancestors) {
        if (ancestors.length > maxDepth) {
          validationContext.reportError(
            new GraphQLError(
              `Query exceeds maximum depth of ${maxDepth}`,
              [node]
            )
          );
        }
      }
    };
  };
}

// Kullanım
const server = new ApolloServer({
  typeDefs,
  resolvers,
  validationRules: [createDepthLimitRule(5)]
});

Query Whitelisting

Query whitelisting, yalnızca önceden onaylanmış sorguların çalıştırılmasına izin vererek, potansiyel kötü niyetli sorguları engeller.

Query Whitelisting Örneği (Apollo Server ve Persisted Queries):


const { ApolloServer } = require('apollo-server');
const { createHash } = require('crypto');

const allowedQueries = new Map();

// Önceden onaylanmış sorguları ekleyin
allowedQueries.set(
  createHash('sha256').update('query { hello }').digest('hex'),
  'query { hello }'
);

const server = new ApolloServer({
  typeDefs,
  resolvers,
  persistedQueries: {
    cache: allowedQueries
  }
});

server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

Özel Query Whitelisting Implementasyonu:


const allowedQueries = new Set([
  'query { user(id: $id) { name email } }',
  'query { posts { title author { name } } }'
]);

function validateQuery(query) {
  // Sorguyu normalize et (boşlukları ve yeni satırları kaldır)
  const normalizedQuery = query.replace(/s+/g, ' ').trim();
  return allowedQueries.has(normalizedQuery);
}

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req }) => {
    const query = req.body.query;
    if (!validateQuery(query)) {
      throw new Error('Bu sorguya izin verilmiyor');
    }
    return {};
  }
});

Ek Güvenlik Önlemleri

1. Query Complexity Analysis

Sorgu karmaşıklığını analiz ederek, aşırı karmaşık sorguları engelleyin.


const { getComplexity, simpleEstimator } = require('graphql-query-complexity');

const server = new ApolloServer({
  typeDefs,
  resolvers,
  validationRules: [
    (context) => {
      return {
        Field(node) {
          const complexity = getComplexity({
            schema: context.getSchema(),
            query: context.getDocument(),
            variables: context.getVariableValues(),
            estimators: [simpleEstimator({ defaultComplexity: 1 })]
          });

          if (complexity > 100) {
            throw new Error('Sorgu çok karmaşık');
          }
        }
      };
    }
  ]
});

2. Rate Limiting

Belirli bir zaman diliminde yapılabilecek sorgu sayısını sınırlayın.


const { createRateLimitRule } = require('graphql-rate-limit');

const rateLimitRule = createRateLimitRule({
  identifyContext: (context) => context.id,
  max: 100, // maksimum istek sayısı
  window: '10s' // 10 saniyelik pencere
});

const server = new ApolloServer({
  typeDefs,
  resolvers,
  validationRules: [rateLimitRule]
});

3. Input Sanitization

Kullanıcı girdilerini temizleyerek, potansiyel XSS ve injection saldırılarını önleyin.


const sanitizeHtml = require('sanitize-html');

const resolvers = {
  Mutation: {
    createPost: (_, { title, content }) => {
      const sanitizedTitle = sanitizeHtml(title);
      const sanitizedContent = sanitizeHtml(content);
      // Sanitize edilmiş verileri kullanarak post oluştur
    }
  }
};

GraphQL Güvenlik Kontrol Listesi

GraphQL uygulamanızın güvenliğini sağlamak için bu kontrol listesini kullanabilirsiniz:


class GraphQLSecurityChecker {
  constructor() {
    this.checks = {
      depthLimiting: false,
      queryWhitelisting: false,
      complexityAnalysis: false,
      rateLimiting: false,
      inputSanitization: false
    };
  }

  implementDepthLimiting() {
    // Derinlik limitleme implementasyonu
    this.checks.depthLimiting = true;
  }

  implementQueryWhitelisting() {
    // Query whitelisting implementasyonu
    this.checks.queryWhitelisting = true;
  }

  implementComplexityAnalysis() {
    // Karmaşıklık analizi implementasyonu
    this.checks.complexityAnalysis = true;
  }

  implementRateLimiting() {
    // Rate limiting implementasyonu
    this.checks.rateLimiting = true;
  }

  implementInputSanitization() {
    // Girdi temizleme implementasyonu
    this.checks.inputSanitization = true;
  }

  isSecure() {
    return Object.values(this.checks).every(check => check === true);
  }

  printSecurityStatus() {
    console.log("GraphQL Security Status:");
    for (const [check, status] of Object.entries(this.checks)) {
      console.log(`${check}: ${status ? 'Implemented' : 'Not Implemented'}`);
    }
    console.log(`Overall Security: ${this.isSecure() ? 'Secure' : 'Not Secure'}`);
  }
}

// Kullanım örneği
const securityChecker = new GraphQLSecurityChecker();
securityChecker.implementDepthLimiting();
securityChecker.implementQueryWhitelisting();
securityChecker.implementComplexityAnalysis();
securityChecker.implementRateLimiting();
securityChecker.implementInputSanitization();
securityChecker.printSecurityStatus();

GraphQL, güçlü ve esnek bir API teknolojisi olmasına rağmen, bu esneklik beraberinde güvenlik riskleri de getirebilir. Derinlik limitleme ve query whitelisting gibi teknikler, bu riskleri önemli ölçüde azaltır ve uygulamanızın güvenliğini artırır.

Ancak unutmayın ki, güvenlik sürekli bir süreçtir. Bu teknikleri uygulamanın yanı sıra, düzenli güvenlik denetimleri yapmak, güncel kalmak ve yeni ortaya çıkan tehditlere karşı hazırlıklı olmak önemlidir.

Siz GraphQL güvenliği için hangi önlemleri alıyorsunuz? Karşılaştığınız zorluklar veya paylaşmak istediğiniz ek öneriler var mı? Yorumlarınızı bekliyorum!

Güvenli kodlamalar ve güvenli GraphQL sorguları dilerim!