GraphQL

Support HackTricks

Introduction

GraphQL को REST API के लिए एक प्रभावी विकल्प के रूप में उजागर किया गया है, जो बैकएंड से डेटा क्वेरी करने के लिए एक सरल दृष्टिकोण प्रदान करता है। REST के विपरीत, जो अक्सर डेटा एकत्र करने के लिए विभिन्न एंडपॉइंट्स पर कई अनुरोधों की आवश्यकता होती है, GraphQL सभी आवश्यक जानकारी को एकल अनुरोध के माध्यम से लाने की अनुमति देता है। यह सरलीकरण डेवलपर्स के लिए महत्वपूर्ण लाभ प्रदान करता है क्योंकि यह उनके डेटा लाने की प्रक्रियाओं की जटिलता को कम करता है।

GraphQL और सुरक्षा

नई तकनीकों के आगमन के साथ, जिसमें GraphQL भी शामिल है, नई सुरक्षा कमजोरियाँ भी उभरती हैं। एक महत्वपूर्ण बिंदु यह है कि GraphQL डिफ़ॉल्ट रूप से प्रमाणीकरण तंत्र शामिल नहीं करता है। ऐसे सुरक्षा उपायों को लागू करना डेवलपर्स की जिम्मेदारी है। उचित प्रमाणीकरण के बिना, GraphQL एंडपॉइंट्स अनधिकृत उपयोगकर्ताओं के लिए संवेदनशील जानकारी को उजागर कर सकते हैं, जो एक महत्वपूर्ण सुरक्षा जोखिम पैदा करता है।

डायरेक्टरी ब्रूट फोर्स हमले और GraphQL

उजागर GraphQL उदाहरणों की पहचान करने के लिए, डायरेक्टरी ब्रूट फोर्स हमलों में विशिष्ट पथों को शामिल करने की सिफारिश की जाती है। ये पथ हैं:

  • /graphql

  • /graphiql

  • /graphql.php

  • /graphql/console

  • /api

  • /api/graphql

  • /graphql/api

  • /graphql/graphql

खुले GraphQL उदाहरणों की पहचान करने से समर्थित क्वेरीज़ की जांच करने की अनुमति मिलती है। यह एंडपॉइंट के माध्यम से उपलब्ध डेटा को समझने के लिए महत्वपूर्ण है। GraphQL का अंतर्दृष्टि प्रणाली इस प्रक्रिया को सरल बनाती है, जो एक स्कीमा द्वारा समर्थित क्वेरीज़ का विवरण देती है। इस पर अधिक जानकारी के लिए, GraphQL दस्तावेज़ में अंतर्दृष्टि देखें: GraphQL: A query language for APIs.

फिंगरप्रिंट

उपकरण graphw00f यह पहचानने में सक्षम है कि किसी सर्वर में कौन सा GraphQL इंजन उपयोग किया जा रहा है और फिर सुरक्षा ऑडिटर के लिए कुछ सहायक जानकारी प्रिंट करता है।

यूनिवर्सल क्वेरीज़

यह जांचने के लिए कि क्या एक URL एक GraphQL सेवा है, एक यूनिवर्सल क्वेरी, query{__typename}, भेजी जा सकती है। यदि प्रतिक्रिया में {"data": {"__typename": "Query"}} शामिल है, तो यह पुष्टि करता है कि URL एक GraphQL एंडपॉइंट होस्ट करता है। यह विधि GraphQL के __typename फ़ील्ड पर निर्भर करती है, जो क्वेरी की गई वस्तु के प्रकार को प्रकट करती है।

query{__typename}

Basic Enumeration

Graphql आमतौर पर GET, POST (x-www-form-urlencoded) और POST(json) का समर्थन करता है। हालांकि सुरक्षा के लिए केवल json की अनुमति देना अनुशंसित है ताकि CSRF हमलों को रोका जा सके।

Introspection

Schema जानकारी खोजने के लिए introspection का उपयोग करने के लिए, __schema फ़ील्ड को क्वेरी करें। यह फ़ील्ड सभी क्वेरियों के रूट प्रकार पर उपलब्ध है।

query={__schema{types{name,fields{name}}}}

इस क्वेरी के साथ आप सभी प्रकारों के नाम पाएंगे जो उपयोग में हैं:

query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}

इस क्वेरी के साथ आप सभी प्रकार, इसके फ़ील्ड और इसके तर्क (और तर्क का प्रकार) निकाल सकते हैं। यह डेटाबेस को क्वेरी करने के लिए जानने में बहुत उपयोगी होगा।

त्रुटियाँ

यह जानना दिलचस्प है कि क्या त्रुटियाँ दिखाई जाएँगी क्योंकि वे उपयोगी जानकारी में योगदान करेंगी।

?query={__schema}
?query={}
?query={thisdefinitelydoesnotexist}

इंट्रोस्पेक्शन के माध्यम से डेटाबेस स्कीमा की गणना करें

यदि इंट्रोस्पेक्शन सक्षम है लेकिन उपरोक्त क्वेरी नहीं चलती है, तो क्वेरी संरचना से onOperation, onFragment, और onField निर्देशों को हटाने का प्रयास करें।

#Full introspection query

query IntrospectionQuery {
__schema {
queryType {
name
}
mutationType {
name
}
subscriptionType {
name
}
types {
...FullType
}
directives {
name
description
args {
...InputValue
}
onOperation  #Often needs to be deleted to run query
onFragment   #Often needs to be deleted to run query
onField      #Often needs to be deleted to run query
}
}
}

fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}

fragment InputValue on __InputValue {
name
description
type {
...TypeRef
}
defaultValue
}

fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}

इनलाइन इंट्रोस्पेक्शन क्वेरी:

/?query=fragment%20FullType%20on%20Type%20{+%20%20kind+%20%20name+%20%20description+%20%20fields%20{+%20%20%20%20name+%20%20%20%20description+%20%20%20%20args%20{+%20%20%20%20%20%20...InputValue+%20%20%20%20}+%20%20%20%20type%20{+%20%20%20%20%20%20...TypeRef+%20%20%20%20}+%20%20}+%20%20inputFields%20{+%20%20%20%20...InputValue+%20%20}+%20%20interfaces%20{+%20%20%20%20...TypeRef+%20%20}+%20%20enumValues%20{+%20%20%20%20name+%20%20%20%20description+%20%20}+%20%20possibleTypes%20{+%20%20%20%20...TypeRef+%20%20}+}++fragment%20InputValue%20on%20InputValue%20{+%20%20name+%20%20description+%20%20type%20{+%20%20%20%20...TypeRef+%20%20}+%20%20defaultValue+}++fragment%20TypeRef%20on%20Type%20{+%20%20kind+%20%20name+%20%20ofType%20{+%20%20%20%20kind+%20%20%20%20name+%20%20%20%20ofType%20{+%20%20%20%20%20%20kind+%20%20%20%20%20%20name+%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20}+%20%20%20%20}+%20%20}+}++query%20IntrospectionQuery%20{+%20%20schema%20{+%20%20%20%20queryType%20{+%20%20%20%20%20%20name+%20%20%20%20}+%20%20%20%20mutationType%20{+%20%20%20%20%20%20name+%20%20%20%20}+%20%20%20%20types%20{+%20%20%20%20%20%20...FullType+%20%20%20%20}+%20%20%20%20directives%20{+%20%20%20%20%20%20name+%20%20%20%20%20%20description+%20%20%20%20%20%20locations+%20%20%20%20%20%20args%20{+%20%20%20%20%20%20%20%20...InputValue+%20%20%20%20%20%20}+%20%20%20%20}+%20%20}+}

अंतिम कोड पंक्ति एक graphql क्वेरी है जो graphql से सभी मेटा-जानकारी (ऑब्जेक्ट नाम, पैरामीटर, प्रकार...) को डंप करेगी।

यदि अंतर्दृष्टि सक्षम है, तो आप GraphQL Voyager का उपयोग करके GUI में सभी विकल्प देख सकते हैं।

क्वेरी करना

अब जब हम जानते हैं कि डेटाबेस के अंदर किस प्रकार की जानकारी सहेजी गई है, तो चलिए कुछ मान निकालने की कोशिश करते हैं।

अंतर्दृष्टि में आप यह देख सकते हैं कि आप किस ऑब्जेक्ट के लिए सीधे क्वेरी कर सकते हैं (क्योंकि आप केवल इसलिए क्वेरी नहीं कर सकते कि ऑब्जेक्ट मौजूद है)। निम्नलिखित छवि में आप देख सकते हैं कि "queryType" को "Query" कहा जाता है और "Query" ऑब्जेक्ट के फ़ील्ड में से एक "flags" है, जो एक ऑब्जेक्ट का प्रकार भी है। इसलिए आप फ्लैग ऑब्जेक्ट के लिए क्वेरी कर सकते हैं।

ध्यान दें कि क्वेरी का प्रकार "flags" "Flags" है, और यह ऑब्जेक्ट नीचे परिभाषित है:

आप देख सकते हैं कि "Flags" ऑब्जेक्ट name और value से मिलकर बने हैं। फिर आप क्वेरी के साथ फ्लैग के सभी नाम और मान प्राप्त कर सकते हैं:

query={flags{name, value}}

ध्यान दें कि यदि क्वेरी करने के लिए ऑब्जेक्ट एक प्राथमिक प्रकार है जैसे स्ट्रिंग जैसा कि निम्नलिखित उदाहरण में है

आप इसे बस इस तरह क्वेरी कर सकते हैं:

query={hiddenFlags}

In another example where there were 2 objects inside the "Query" type object: "user" and "users". यदि इन वस्तुओं को खोजने के लिए किसी भी तर्क की आवश्यकता नहीं है, तो आप उनसे सभी जानकारी प्राप्त कर सकते हैं बस आपके द्वारा मांगी गई डेटा के लिए। इस इंटरनेट के उदाहरण में आप सहेजे गए उपयोगकर्ता नाम और पासवर्ड निकाल सकते हैं:

हालांकि, इस उदाहरण में यदि आप ऐसा करने की कोशिश करते हैं तो आपको यह त्रुटि मिलती है:

ऐसा लगता है कि यह किसी तरह "uid" तर्क का उपयोग करके खोज करेगा, जो Int प्रकार का है। खैर, हम पहले से ही जानते थे कि, Basic Enumeration अनुभाग में एक क्वेरी प्रस्तावित की गई थी जो हमें सभी आवश्यक जानकारी दिखा रही थी: query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}

यदि आप उस क्वेरी को चलाते समय प्रदान की गई छवि को पढ़ते हैं, तो आप देखेंगे कि "user" के पास Int प्रकार का arg "uid" था।

तो, कुछ हल्की uid ब्रूटफोर्स करते हुए मैंने पाया कि uid=1 पर एक उपयोगकर्ता नाम और एक पासवर्ड प्राप्त हुआ: query={user(uid:1){user,password}}

ध्यान दें कि मैंने खोजा कि मैं पैरामीटर "user" और "password" के लिए पूछ सकता हूं क्योंकि यदि मैं कुछ ऐसा देखने की कोशिश करता हूं जो मौजूद नहीं है (query={user(uid:1){noExists}}) तो मुझे यह त्रुटि मिलती है:

और enumeration phase के दौरान मैंने खोजा कि "dbuser" वस्तु के पास "user" और "password" के रूप में फ़ील्ड थे।

Query string dump trick (thanks to @BinaryShadow_)

यदि आप एक स्ट्रिंग प्रकार द्वारा खोज सकते हैं, जैसे: query={theusers(description: ""){username,password}} और आप खाली स्ट्रिंग के लिए खोजते हैं तो यह सभी डेटा को डंप करेगा। (इस उदाहरण को ट्यूटोरियल के उदाहरण से संबंधित नहीं माना गया है, इस उदाहरण के लिए मान लें कि आप "theusers" को "description" नामक स्ट्रिंग फ़ील्ड का उपयोग करके खोज सकते हैं)।

Searching

इस सेटअप में, एक database में व्यक्तियाँ और फिल्में होती हैं। व्यक्तियाँ को उनके ईमेल और नाम द्वारा पहचाना जाता है; फिल्में उनके नाम और रेटिंग द्वारा। व्यक्तियाँ एक-दूसरे के साथ दोस्त हो सकती हैं और भी फिल्में रख सकती हैं, जो डेटाबेस के भीतर संबंधों को इंगित करती हैं।

आप नाम द्वारा व्यक्तियों की खोज कर सकते हैं और उनके ईमेल प्राप्त कर सकते हैं:

{
searchPerson(name: "John Doe") {
email
}
}

आप व्यक्तियों को नाम से खोज सकते हैं और उनकी सब्सक्राइब की गई फ़िल्में प्राप्त कर सकते हैं:

{
searchPerson(name: "John Doe") {
email
subscribedMovies {
edges {
node {
name
}
}
}
}
}

ध्यान दें कि यह व्यक्ति के subscribedMovies का name प्राप्त करने के लिए कैसे संकेतित किया गया है।

आप एक साथ कई वस्तुओं की खोज भी कर सकते हैं। इस मामले में, 2 फिल्मों की खोज की जाती है:

{
searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) {
name
}
}r

या यहां तक कि विभिन्न वस्तुओं के कई संबंधों का उपयोग करते हुए उपनाम:

{
johnsMovieList: searchPerson(name: "John Doe") {
subscribedMovies {
edges {
node {
name
}
}
}
}
davidsMovieList: searchPerson(name: "David Smith") {
subscribedMovies {
edges {
node {
name
}
}
}
}
}

Mutations

म्यूटेशन का उपयोग सर्वर-साइड में परिवर्तन करने के लिए किया जाता है।

इंट्रोस्पेक्शन में आप घोषित म्यूटेशन पा सकते हैं। निम्नलिखित चित्र में "MutationType" को "Mutation" कहा जाता है और "Mutation" ऑब्जेक्ट में म्यूटेशन के नाम होते हैं (जैसे कि इस मामले में "addPerson"):

इस सेटअप में, एक डेटाबेस में व्यक्तियाँ और फिल्में होती हैं। व्यक्तियों की पहचान उनके ईमेल और नाम से होती है; फिल्मों की पहचान उनके नाम और रेटिंग से होती है। व्यक्तियाँ एक-दूसरे के साथ दोस्त बन सकती हैं और उनके पास फिल्में भी हो सकती हैं, जो डेटाबेस के भीतर संबंधों को दर्शाती हैं।

डेटाबेस के भीतर नई फिल्मों को बनाने के लिए एक म्यूटेशन इस प्रकार हो सकता है (इस उदाहरण में म्यूटेशन को addMovie कहा जाता है):

mutation {
addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) {
movies {
name
rating
}
}
}

नोट करें कि क्वेरी में डेटा के दोनों मान और प्रकार को कैसे इंगित किया गया है।

इसके अतिरिक्त, डेटाबेस एक म्यूटेशन ऑपरेशन का समर्थन करता है, जिसका नाम addPerson है, जो व्यक्तियों के निर्माण की अनुमति देता है, साथ ही उनके मौजूदा दोस्तों और फिल्मों के साथ उनके संबंधों को। यह महत्वपूर्ण है कि दोस्तों और फिल्मों को नए बनाए गए व्यक्ति से लिंक करने से पहले डेटाबेस में पहले से मौजूद होना चाहिए।

mutation {
addPerson(name: "James Yoe", email: "jy@example.com", friends: [{name: "John Doe"}, {email: "jd@example.com"}], subscribedMovies: [{name: "Rocky"}, {name: "Interstellar"}, {name: "Harry Potter and the Sorcerer's Stone"}]) {
person {
name
email
friends {
edges {
node {
name
email
}
}
}
subscribedMovies {
edges {
node {
name
rating
releaseYear
}
}
}
}
}
}

Directive Overloading

जैसा कि इस रिपोर्ट में वर्णित एक कमजोरियों में में समझाया गया है, एक निर्देश ओवरलोडिंग का मतलब है कि एक निर्देश को लाखों बार कॉल करना ताकि सर्वर ऑपरेशन बर्बाद कर सके जब तक कि इसे DoS करना संभव न हो।

Batching brute-force in 1 API request

यह जानकारी https://lab.wallarm.com/graphql-batching-attack/ से ली गई थी। GraphQL API के माध्यम से विभिन्न क्रेडेंशियल्स के साथ कई क्वेरीज़ को एक साथ भेजकर प्रमाणीकरण करना। यह एक क्लासिक ब्रूट फोर्स हमला है, लेकिन अब HTTP अनुरोध प्रति एक से अधिक लॉगिन/पासवर्ड जोड़ी भेजना संभव है क्योंकि GraphQL बैचिंग सुविधा है। यह दृष्टिकोण बाहरी दर निगरानी अनुप्रयोगों को यह सोचने के लिए धोखा देगा कि सब कुछ ठीक है और कोई ब्रूट-फोर्सिंग बॉट पासवर्ड अनुमान लगाने की कोशिश नहीं कर रहा है।

नीचे आप एक एप्लिकेशन प्रमाणीकरण अनुरोध का सबसे सरल प्रदर्शन देख सकते हैं, जिसमें एक समय में 3 विभिन्न ईमेल/पासवर्ड जोड़ी हैं। स्पष्ट रूप से, एक ही अनुरोध में हजारों भेजना संभव है:

जैसा कि हम प्रतिक्रिया स्क्रीनशॉट से देख सकते हैं, पहले और तीसरे अनुरोध ने null लौटाया और error अनुभाग में संबंधित जानकारी को दर्शाया। दूसरी म्यूटेशन में सही प्रमाणीकरण डेटा था और प्रतिक्रिया में सही प्रमाणीकरण सत्र टोकन है।

GraphQL Without Introspection

दिन-ब-दिन graphql एंडपॉइंट्स अंतर्दृष्टि को अक्षम कर रहे हैं। हालाँकि, जब एक अप्रत्याशित अनुरोध प्राप्त होता है तो graphql द्वारा फेंके गए त्रुटियाँ clairvoyance जैसे उपकरणों के लिए अधिकांश स्कीमा को फिर से बनाने के लिए पर्याप्त हैं।

इसके अलावा, Burp Suite एक्सटेंशन GraphQuail Burp के माध्यम से GraphQL API अनुरोधों को देखता है और प्रत्येक नए क्वेरी के साथ एक आंतरिक GraphQL स्कीमा बनाता है। यह GraphiQL और Voyager के लिए स्कीमा को भी उजागर कर सकता है। जब यह एक अंतर्दृष्टि क्वेरी प्राप्त करता है तो एक्सटेंशन एक नकली प्रतिक्रिया लौटाता है। परिणामस्वरूप, GraphQuail सभी क्वेरीज़, तर्कों और फ़ील्ड्स को API के भीतर उपयोग के लिए दिखाता है। अधिक जानकारी के लिए यहाँ देखें.

एक अच्छा शब्दसूची GraphQL संस्थाओं को खोजने के लिए यहाँ मिल सकती है.

Bypassing GraphQL introspection defences

API में अंतर्दृष्टि क्वेरीज़ पर प्रतिबंधों को बायपास करने के लिए, __schema कीवर्ड के बाद विशेष वर्ण डालना प्रभावी साबित होता है। यह विधि उन सामान्य डेवलपर की चूक का लाभ उठाती है जो अंतर्दृष्टि को अवरुद्ध करने के लिए regex पैटर्न पर ध्यान केंद्रित करती हैं। जैसे स्पेस, नई पंक्तियाँ, और अल्पविराम जैसे वर्ण जोड़कर, जिन्हें GraphQL अनदेखा करता है लेकिन शायद regex में नहीं गिना गया है, प्रतिबंधों को बायपास किया जा सकता है। उदाहरण के लिए, __schema के बाद एक नई पंक्ति के साथ एक अंतर्दृष्टि क्वेरी ऐसी रक्षा को बायपास कर सकती है:

# Example with newline to bypass
{
"query": "query{__schema
{queryType{name}}}"
}

यदि असफल हो, तो वैकल्पिक अनुरोध विधियों पर विचार करें, जैसे GET अनुरोध या POST x-www-form-urlencoded के साथ, क्योंकि प्रतिबंध केवल POST अनुरोधों पर लागू हो सकते हैं।

वेबसॉकेट्स का प्रयास करें

जैसा कि इस वार्ता में उल्लेख किया गया है, जांचें कि क्या WebSockets के माध्यम से graphQL से कनेक्ट करना संभव हो सकता है क्योंकि यह आपको संभावित WAF को बायपास करने की अनुमति दे सकता है और वेबसॉकेट संचार को graphQL के स्कीमा को लीक करने दे सकता है:

ws = new WebSocket('wss://target/graphql', 'graphql-ws');
ws.onopen = function start(event) {
var GQL_CALL = {
extensions: {},
query: `
{
__schema {
_types {
name
}
}
}`
}

var graphqlMsg = {
type: 'GQL.START',
id: '1',
payload: GQL_CALL,
};
ws.send(JSON.stringify(graphqlMsg));
}

खुली GraphQL संरचनाओं का पता लगाना

जब अंतर्दृष्टि अक्षम होती है, तो JavaScript पुस्तकालयों में प्रीलोडेड क्वेरीज़ के लिए वेबसाइट के स्रोत कोड की जांच करना एक उपयोगी रणनीति है। ये क्वेरीज़ डेवलपर टूल्स में Sources टैब का उपयोग करके पाई जा सकती हैं, जो API के स्कीमा के बारे में जानकारी प्रदान करती हैं और संभावित रूप से खुली संवेदनशील क्वेरीज़ को प्रकट करती हैं। डेवलपर टूल्स में खोजने के लिए कमांड हैं:

Inspect/Sources/"Search all files"
file:* mutation
file:* query

CSRF in GraphQL

यदि आप नहीं जानते कि CSRF क्या है, तो निम्नलिखित पृष्ठ पढ़ें:

CSRF (Cross Site Request Forgery)

आपको कई GraphQL एंडपॉइंट मिलेंगे जो CSRF टोकन के बिना कॉन्फ़िगर किए गए हैं।

ध्यान दें कि GraphQL अनुरोध आमतौर पर POST अनुरोधों के माध्यम से भेजे जाते हैं, जिसमें Content-Type application/json होता है।

{"operationName":null,"variables":{},"query":"{\n  user {\n    firstName\n    __typename\n  }\n}\n"}

हालांकि, अधिकांश GraphQL एंडपॉइंट form-urlencoded POST अनुरोधों का भी समर्थन करते हैं:

query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A

इसलिए, जैसे कि पिछले CSRF अनुरोध बिना प्रीफ्लाइट अनुरोधों के भेजे जाते हैं, यह संभव है कि CSRF का दुरुपयोग करके GraphQL में परिवर्तन किए जाएं।

हालांकि, ध्यान दें कि Chrome के samesite ध्वज का नया डिफ़ॉल्ट कुकी मान Lax है। इसका मतलब है कि कुकी केवल GET अनुरोधों में एक तीसरे पक्ष की वेबसाइट से भेजी जाएगी।

ध्यान दें कि आमतौर पर क्वेरी अनुरोध को GET अनुरोध के रूप में भेजना भी संभव है और CSRF टोकन को GET अनुरोध में मान्य नहीं किया जा सकता है।

इसके अलावा, XS-Search हमले का दुरुपयोग करके GraphQL एंडपॉइंट से उपयोगकर्ता के क्रेडेंशियल्स का दुरुपयोग करके सामग्री को एक्सफिल्ट्रेट करना संभव हो सकता है।

अधिक जानकारी के लिए यहां मूल पोस्ट देखें

GraphQL में क्रॉस-साइट वेबसॉकेट हाईजैकिंग

GraphQL का दुरुपयोग करते हुए CRSF कमजोरियों के समान, यह भी संभव है कि क्रॉस-साइट वेबसॉकेट हाईजैकिंग का प्रदर्शन किया जाए ताकि GraphQL के साथ असुरक्षित कुकीज़ के साथ प्रमाणीकरण का दुरुपयोग किया जा सके और उपयोगकर्ता को GraphQL में अप्रत्याशित क्रियाएँ करने के लिए मजबूर किया जा सके।

अधिक जानकारी के लिए देखें:

WebSocket Attacks

GraphQL में प्राधिकरण

एंडपॉइंट पर परिभाषित कई GraphQL कार्य केवल अनुरोधकर्ता के प्रमाणीकरण की जांच कर सकते हैं लेकिन प्राधिकरण की नहीं।

क्वेरी इनपुट वेरिएबल को संशोधित करने से संवेदनशील खाता विवरण leaked हो सकते हैं।

म्यूटेशन अन्य खाता डेटा को संशोधित करने का प्रयास करते समय खाता अधिग्रहण का कारण बन सकता है।

{
"operationName":"updateProfile",
"variables":{"username":INJECT,"data":INJECT},
"query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}"
}

GraphQL में प्राधिकरण को बायपास करना

Queries को एक साथ जोड़ना एक कमजोर प्रमाणीकरण प्रणाली को बायपास कर सकता है।

नीचे दिए गए उदाहरण में आप देख सकते हैं कि ऑपरेशन "forgotPassword" है और इसे केवल इसके साथ जुड़े forgotPassword क्वेरी को निष्पादित करना चाहिए। इसे अंत में एक क्वेरी जोड़कर बायपास किया जा सकता है, इस मामले में हम "register" और एक उपयोगकर्ता चर जोड़ते हैं ताकि प्रणाली एक नए उपयोगकर्ता के रूप में पंजीकरण कर सके।

GraphQL में उपनामों का उपयोग करके दर सीमाओं को बायपास करना

GraphQL में, उपनाम एक शक्तिशाली विशेषता हैं जो API अनुरोध करते समय गुणों के नाम को स्पष्ट रूप से निर्दिष्ट करने की अनुमति देती हैं। यह क्षमता एकल अनुरोध के भीतर एक ही प्रकार की वस्तुओं के कई उदाहरणों को पुनः प्राप्त करने के लिए विशेष रूप से उपयोगी है। उपनामों का उपयोग उन सीमाओं को पार करने के लिए किया जा सकता है जो GraphQL वस्तुओं को एक ही नाम के साथ कई गुण रखने से रोकती हैं।

GraphQL उपनामों की विस्तृत समझ के लिए, निम्नलिखित संसाधन की सिफारिश की जाती है: Aliases

हालांकि उपनामों का प्राथमिक उद्देश्य कई API कॉल की आवश्यकता को कम करना है, एक अनपेक्षित उपयोग का मामला पहचाना गया है जहां उपनामों का उपयोग GraphQL एंडपॉइंट पर ब्रूट फोर्स हमलों को निष्पादित करने के लिए किया जा सकता है। यह संभव है क्योंकि कुछ एंडपॉइंट्स को दर सीमित करने वालों द्वारा सुरक्षित किया गया है जो ब्रूट फोर्स हमलों को रोकने के लिए HTTP अनुरोधों की संख्या को सीमित करते हैं। हालाँकि, ये दर सीमित करने वाले प्रत्येक अनुरोध के भीतर संचालन की संख्या को ध्यान में नहीं रख सकते हैं। चूंकि उपनाम एक ही HTTP अनुरोध में कई क्वेरी शामिल करने की अनुमति देते हैं, वे ऐसी दर सीमित करने वाली उपायों को बायपास कर सकते हैं।

नीचे दिए गए उदाहरण पर विचार करें, जो दिखाता है कि कैसे उपनामित क्वेरी का उपयोग स्टोर डिस्काउंट कोड की वैधता की पुष्टि करने के लिए किया जा सकता है। यह विधि दर सीमित करने को बायपास कर सकती है क्योंकि यह कई क्वेरी को एक HTTP अनुरोध में संकलित करती है, संभावित रूप से कई डिस्काउंट कोड की एक साथ पुष्टि करने की अनुमति देती है।

# Example of a request utilizing aliased queries to check for valid discount codes
query isValidDiscount($code: Int) {
isvalidDiscount(code:$code){
valid
}
isValidDiscount2:isValidDiscount(code:$code){
valid
}
isValidDiscount3:isValidDiscount(code:$code){
valid
}
}

Tools

Vulnerability scanners

  • https://github.com/dolevf/graphql-cop: graphql endpoints की सामान्य गलत कॉन्फ़िगरेशन का परीक्षण करें

  • https://github.com/assetnote/batchql: बैच GraphQL क्वेरी और म्यूटेशन करने पर ध्यान केंद्रित करने वाला GraphQL सुरक्षा ऑडिटिंग स्क्रिप्ट।

  • https://github.com/dolevf/graphw00f: उपयोग किए जा रहे graphql की फिंगरप्रिंटिंग करें

  • https://github.com/gsmith257-cyber/GraphCrawler: टूलकिट जिसका उपयोग स्कीमाओं को प्राप्त करने और संवेदनशील डेटा की खोज करने, प्राधिकरण का परीक्षण करने, ब्रूट फोर्स स्कीमाओं का परीक्षण करने और एक दिए गए प्रकार के लिए पथ खोजने के लिए किया जा सकता है।

  • https://blog.doyensec.com/2020/03/26/graphql-scanner.html: इसे स्टैंडअलोन या Burp extension के रूप में उपयोग किया जा सकता है।

  • https://github.com/swisskyrepo/GraphQLmap: इसे CLI क्लाइंट के रूप में भी उपयोग किया जा सकता है ताकि हमलों को स्वचालित किया जा सके

  • https://gitlab.com/dee-see/graphql-path-enum: टूल जो GraphQL स्कीमा में एक दिए गए प्रकार तक पहुँचने के विभिन्न तरीकों की सूची बनाता है

  • https://github.com/doyensec/GQLSpection: InQL के स्टैंडअलोन और CLI मोड का उत्तराधिकारी

  • https://github.com/doyensec/inql: उन्नत GraphQL परीक्षण के लिए Burp extension। Scanner InQL v5.0 का मूल है, जहाँ आप एक GraphQL endpoint या एक स्थानीय introspection schema फ़ाइल का विश्लेषण कर सकते हैं। यह सभी संभावित क्वेरी और म्यूटेशन को स्वचालित रूप से उत्पन्न करता है, उन्हें आपके विश्लेषण के लिए एक संरचित दृश्य में व्यवस्थित करता है। Attacker घटक आपको बैच GraphQL हमले चलाने की अनुमति देता है, जो खराब कार्यान्वित दर सीमाओं को पार करने के लिए उपयोगी हो सकता है।

  • https://github.com/nikitastupin/clairvoyance: कुछ Graphql डेटाबेस की मदद से स्कीमा प्राप्त करने की कोशिश करें जो म्यूटेशन और पैरामीटर के नाम सुझाएंगे, भले ही introspection अक्षम हो।

Clients

Automatic Tests

References

Support HackTricks

Last updated