GraphQL ve Güvenlik Zafiyetleri #ArkaKapı9

Huriye Özdemir
6 min readJan 19, 2021

Bu yazı Arka Kapı dergisi 9. Sayıda yayımlanmıştır.

GraphQL, 2012 yılında Facebook tarafından geliştirilen ve 2015 yılında açık kaynaklı olarak yayınlanan bir veri sorgulama dilidir. GraphQL ile istemci bir API kaynağından istediği ve ihtiyacı olan verileri çekmek için gerekli olan sorguları uygulama seviyesinde yaparak kolay bir şekilde elde edebilir. Yazılım geliştiricilerin üretkenliğini artırmak ve veri transferlerinde karşılaşılan zorlukları azaltmak amacıyla Restful mimarisine alternatif olarak geliştirilen bu dili Facebook başta olmak üzere Github, Pinterest ve Coursera gibi popüler platformlar kullanıyor.

GraphQL vs. REST API

GraphQL ve REST API’yi karşılaştırırsak hem ona neden ihtiyaç duyulduğunu daha iyi kavramış hem de avantajlarını görmüş oluruz. Kısaca bahsedelim, örneğin spor verilerini düşünün. Oyuncular, takımlar, maçlar ve bunun gibi birçok alt veri sıralayabiliriz. REST API’de bu verilere ulaşabilmek için her biri için ayrı ayrı endpoint’lere ihtiyaç duyulur ve ayrı ayrı sorgular hazırlamak gerekir. Fakat GraphQL ile, oyuncular, takımlar ve maçlar arasındaki ilişkilerin hepsi aynı veri grafiğinin bir parçası olduğu için verilere ulaşabilmek için tek bir istek yeterlidir.

Resim 1.1

Resim1.2’de örnek bir sorgu, yanıt ve şema üçlüsünün nasıl olduğunu, Resim 1.3’de ise REST API ve GraphQL API arasındaki uygulama farkını açık bir şekilde görüyorsunuz.

Resim 1.2
Resim 1.3

Atak Senaryoları

GraphQL kullanan web uygulamaları ve erişilen endpointler SQL injection, NoSQL injection, erişim kontrollerini atlatma, hassas veri sızıntısı gibi birçok zafiyet barındırabilir. Bu yazıda gerçek senaryolar üzerinden bu atakların nasıl gerçekleştiğine göz atacağız.

SQL Injection

Mathias Choren, blog yazısında SQL injection zafiyetine maruz kalan bir endpoint bulmak için GraphQL ile denemeler yapılıyor. Aşağıdaki örnekteki gibi “type” argümanına tek tırnak (‘) atıldığında MySQL syntax hatası alındığını görüyoruz. Syntax hatası almasak bile bu endpoint’te Blind, Time-based ve Out-of-Band SQL injection zafiyetlerinin hala bulunabileceğini de unutmamak gerekir.

Burada bulunan SQL injection, Burp Suite ile manuel olarak exploit edilmeye çalışılıyor ve tek tırnaktan sonra eklenen SQL sorgusu ile veri tabanındaki diğer veriler çekilmiş oluyor.

GraphQL sorgusu her ne kadar güçlü bir şekilde yazılsa bile, SQL yada No SQL Injection zafiyeti bulundurması mümkündür çünkü GraphQL istemci uygulamaları ve veri tabanı arasında bir katmandır. Muhtemel zafiyet, veri tabanını sorgulamak ve GraphQL sorgularından değişkenleri almak için geliştirilen katmanda bulunabilir.

NoSQL Injection

Pete Corey 2016 yılında yayınladığı bir blog yazısı ile JSON tipleri yolu ile nasıl NoSQL injection zafiyetini bulduğunu açıklıyor (kaynakçadaki link ile daha ayrıntılı inceleyebilirsiniz). Öncelikle NoSQL Injection zafiyetinin oluşturabileceği tehlikeye hızlıca bir göz atalım.

ID numarasına göre Foo koleksiyonundan tek bir öğe yayınlayan, Meteor ile oluşturulmuş bir yayın uygulaması olduğunu düşünelim. İstenilen Foo belgesinin ID bilgisi, yayına abone olduklarında kullanıcı tarafından sağlansın.

Meteor uygulamasına göre , _id argümanı string olarak kabul edilir ama kötü niyetli bir kullanıcı “foo” yayınının _id argümanına string dışında bir şey gönderirse bir MongoDB sorgu operatörünü barındıran bir nesneyi bypass ederek sorgunun davranışını değiştirebilir. Tüm ID’ler boş bir string’ ten daha büyük olduğundan, foo koleksiyonundaki tüm belgeler listelenmiş olur.

Meteor uygulamalarında bu tip zafiyetlerden kurtulmanın en iyi yolu ise argümanları kontrol etmek amacıyla “check” fonksiyonunu kullanmaktır.

Her argümanı bu şekilde kontrol etmek yerine GraphQL’in “strongly-typed” özelliği ile, yani sorguları çalıştırmadan önce syntax olarak doğru sorgular tanımlanmasını sağlama özelliği sayesinde sorunlar çözülmüş oluyor. Çünkü tüm sorgular için tanımlanmış ve ilişkilendirilmiş bir şema oluşturuluyor.

Bir önceki örnek revize edilirse:

Şimdi FooQuery fonksiyonunu GraphQL şemasına bağladıktan sonra aşağıdaki sorgu ile veri elde edilebilir:

Artık “Foo” sorgusuna string dışında herhangi bir veri tipi iletmeye çalışırsak, hata alırız ve sorgumuz çalışmaz.

Graphql/type modülü ile sorgular için veri tipleri ve şemalar tanımlayabilirsiniz. Ancak, input nesnesi içinde tanımlanan alanların iyi ayrıntılandırılması gerekir. Her alan bir skaler veya daha karmaşık bir tür olmalıdır. GraphQL’de varsayılan olarak tanımlı skaler türleri: Int, Float, String, Boolean and ID’dir. Bu tanımlar şema içerisinde yapıldıktan sonra input objelerinin exploit edilmesinin önüne geçilmiş olur.

Information Disclosure

GraphQL ile açığa çıkabilecek bir diğer zafiyet de bilgi ifşasıdır. Aşağıdaki örnekte görüldüğü üzere error uyarısı ile birlikte bir bilginin ifşası gerçekleşiyor.

Erişim Kontrollerini Atlatma

Bir de Jon Bottarini tarafından keşfedilen bu yolu inceleyelim. Jon Bottarini, yalnızca admin seviyesindeki kullanıcıların erişmesi için konfigüre edilmiş verilere kullanıcı seviyesinde ulaşmayı başarmış ve bunu kaçakçılık (smuggling) sorguları olarak isimlendirmiş.

Senaryoda kullanıcılar için kısıtlanmış bir lisans anahtarı bilgisi mevcut. Bu lisans anahtarını kullanıcı seviyesinde elde etmek için Jon Bottarini’nin izlediği yollara bakalım.

Aşağıda kullanıcı seviyesinde oluşturulmuş bir sorgu ve buna dönen yanıt bulunuyor.

Yanıt:

Bu yanıt bilgisinden anlaşılan, currentUser ile email adresi, currentAccount ile de hesap ismi, yetenekler, deneme uygunluğu ve deneme durumu isteniyor.

Buradaki asıl problem, uygulamanın yukarıdaki sorguyu gerçekleştiren kullanıcının yönetici olup olmadığını tespit edememesi. Sorgudaki currentAccount kısmına lisans anahtarı bilgisini ekleyip yanıtı tekrar inceliyoruz.

Yanıt:

Gördüğünüz gibi kullanıcı seviyesinde iken lisans anahtarı bilgisi ile beraber tüm hesap bilgisi elde edilmiş.

GraphQL API Güvenliğini Nasıl Sağlarız?

Ortaya çıkabilecek tehlikeler konusunda farkındalık kazandıktan sonra dikkat edilmesi gereken GraphQL API güvenliğinin nasıl sağlanması gerektiği konusu. Bunun için aşağıda sıralanmış bir best-practices listesi bulunuyor. Bu listeyi inceleyip gerekli kontrolleri sağlayabilirsiniz.

  1. Sorgular için zaman aşımı süresi belirlemek:

Her sorgu için maksimum zaman sınırı belirlemek saldırganın kullanacağı büyük sorgularda işe yarayacaktır.

2. Sorgu derinliğini sınırlandırmak

Devasa büyüklükte gönderilen iç içe sorgular ile muhtemel bir DoS saldırısından korunmak için sorgunun derinliğinin belirlenmesi gerekir. Bunu uygulamak için graphql-depth-limit modülü kullanılabilir.

3. Sorgu karmaşıklığını sınırlandırmak

Karmaşık sorgular GraphQL sunucusuna ek olarak yük eklediğinden yine DoS ataklarına maruz kalınabilir. Bunu uygulamak için graphql-validation-complexity modülü kullanılabilir.

4. Sorgular için bir whitelist oluşturmak

Kötü amaçlı veya istenmeyen sorgulardan kaçınmak için alınabilecek önlemlerden biri de whitelist oluşturarak kabul edilecek sorguları listelemektir.

5. Kalıcı sorgular oluşturmak

GraphQL sorgularını statik string’ler olarak yazmak en iyi yöntemlerden biridir. Bu yöntem ile whitelist kadar kısıtlayıcı olmadan ve bant genişliğini koruyarak kötü sorgulardan korunmuş olursunuz. Bunun için persistgraphql aracı kullanılabilir.

6. Kullanıcılar için hız sınırlamak

Gönderilen sorgular karmaşık olmasa bile belli bir süre içerisinde gönderilen sorgu sayısı fazla olduğunda yine problemler ortaya çıkar. Hız sınırlayıcı ile bir istemcinin belirli bir zaman penceresinde kaç istek gönderebileceğini belirlemek gerekir.

7. GraphQL endpoint’i korumak

GraphQL’de kimlik doğrulaması ve yetkilendirme için güvenliği sağlamak çok önemlidir.

Kimlik doğrulaması için:

● Her yerde SSL sertifikasının zorlanması gerekir.

● Erişim ve hata loglarının tutulması gerekir.

Yetkilendirme için:

● Her bir node için yetki düzeyinin kontrol edilmesi gerekir.

● Verileri ayrı katmanlara çekerek yetkilendirme kontrolünü yapılması gerekir.

Kaynakça

https://devopedia.org/graphql

https://leapgraph.com/graphql-api-security

https://blog.doyensec.com/2018/05/17/graphql-security-overview.html

https://labs.detectify.com/2018/03/14/graphql-abuse/

http://www.petecorey.com/blog/2016/06/13/nosql-injection-and-graphql/

https://medium.com/@localh0t/discovering-graphql-endpoints-and-sqli-vulnerabilities-5d39f26cea2e

--

--

Huriye Özdemir

Senior Cybersecurity Consultant | Artist — Instagram: @art.lady.bug