메인 콘텐츠로 건너뛰기
블로그컴퓨팅과도한 리소스 소비로부터 GraphQL 서버 방어하기

과도한 리소스 소비로부터 GraphQL 서버 보호

텍스트와 함께 물결 모양을 만드는 많은 데이터 포인트가 있는 막대 그래프 그림: 과도한 리소스 소비로부터 GraphQL 서버를 보호하세요.

GraphQL은 필요한 리소스와 속성만 정확하게 요청할 수 있는 유연성을 제공합니다. 이는 데이터를 과도하게 가져오거나 적게 가져오는 경우가 많은 REST와는 다릅니다. 이러한 정밀성 덕분에 GraphQL은 매우 효율적입니다. 또한 GraphQL은 페이지 매김을 처리하는 표준 방법을 제공하여 유연성을 더욱 향상시킵니다. 그러나 악의적인 사용자가 이러한 GraphQL 기능을 악용할 수 있으며, 이는 서버의 안정성에 심각한 위험을 초래할 수 있습니다.

이 블로그에서는 GraphQL의 유연성이 어떻게 사용자에게 불리하게 작용할 수 있는지 살펴보겠습니다. 특히 OWASP API 보안 톱 10에서 강조한 취약점인 무제한 리소스 소비에 초점을 맞추고 있습니다. 또한 이러한 종류의 악용으로부터 시스템을 보호하기 위한 실질적인 조치에 대해서도 논의할 것입니다.

GraphQL의 오버-페칭 및 언더-페칭에 대한 해답

GraphQL은 부분적으로 REST에서 일반적으로 발생하는 과도한 가져오기 문제를 해결하기 위해 설계되었습니다. 예를 들어 사용자, 제품, 주문이 있는 표준 전자상거래 데이터베이스를 생각해 봅시다. 주문 ID로 주어진 주문의 총 금액을 가져와야 한다고 가정해 보겠습니다. REST를 사용하면 /orders/17에 대한 GET 요청은 달러 금액뿐만 아니라 다음 사항도 가져옵니다:

  • 주문 데이터
  • 청구 정보
  • 배송 정보
  • 제품 수량
  • 세금
  • 주문 상태
  • ... 그리고 더

과도하게 가져온 것입니다.

REST를 사용하면 여러 리소스에서 관련 데이터를 취합해야 할 때 언더 페칭이 발생할 수도 있습니다. 주문의 날짜와 상태, 주문에 포함된 모든 제품의 이름과 설명, 주문한 사용자의 이름과 이메일이 포함된 요약을 표시하고 싶다고 가정해 보겠습니다. 이렇게 하려면 여러 요청을 보내야 합니다:

  • GET /orders/17
  • GET /products/1662527
  • GET /products/9914188
  • GET /products/3750021
  • GET /products/7557109
  • GET /products/6081142
  • GET /users/3314

GraphQL은 이러한 REST의 단점에 대한 해답이었습니다. 관련 리소스에서 필요한 것을 정확히 쿼리할 수 있습니다. 위의 작업을 수행하기 위해 GraphQL은 다음과 같이 보일 수 있습니다:

query {
  order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
}

매우 간단하고 유연합니다! 하지만 이러한 유연성은 악의적인 사용자가 의도적으로 데이터를 과도하게 가져올 수 있다는 것을 의미하기도 합니다.

쿼리 유연성 악용

GraphQL의 쿼리 구문을 사용하면 동일한 요청 내에서 여러 쿼리를 수행할 수 있습니다. 위의 쿼리를 가지고 다음과 같은 작업을 수행할 수 있습니다:

query {
  Q1: order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
  Q2: order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
}

이번에는 이전 쿼리와 동일한 데이터를 요청했지만 두 번 요청했다는 점을 제외하면 동일한 데이터를 요청했습니다. 당연히 응답은 단일 쿼리 요청의 두 배 크기가 될 것입니다. 하지만 쿼리를 한 번의 요청으로 100번 반복하면 어떨까요?

query {
  Q00: order(id: "17") {    …  }  Q01: order(id: "17") {    …  }  …  Q99: order(id: "17") {    …  }
}

이렇게 해서 원래 쿼리 크기의 100배에 달하는 응답을 생성하는 쿼리를 만들었습니다. 이 공격을 설명하는 좋은 방법은 다음 치즈버거 이미지로 설명할 수 있습니다. 햄버거 빵은 하나의 요청을 구성하지만, 빵 사이에는 수백 개의 소고기 패티가 있을 수 있습니다!

채워진 쿼리

악의적인 사용자가 이러한 쿼리 유연성을 악용할 경우 과도한 리소스 소비로 인해 서버가 마비될 수 있습니다.

페이지 매김 기능 악용

GraphQL에는 페이지 매김을 처리하는 몇 가지 표준 방법도 있습니다. 일반적인 접근 방식은 오프셋 기반 페이지 매김으로, 호출자가 가져올 항목의 수(제한)와 시작할 항목(오프셋)을 제공합니다.

예를 들어 제품 검색에서 정보를 반환하는 쿼리는 다음과 같습니다:

query {
  products(searchString: "shirt", limit: 8, offset: 0) {
    id
    name
    description
    sku
    category
    images {
      path
      alt_text
    }
    variations {
      name
      description
      cost
    }
  }
}

대신 페이지 매김 매개 변수를 조정하여 쿼리를 실행하면 어떨까요?

query {
  products(searchString: "shirt", limit: 800, offset: 0) {    …  }}

전자 상거래 사이트에서 테스트한 유사한 사례에서 제가 받은 응답을 비교했습니다:

$ du response*.json
680496  response_big.json
333649  response_small.json

제한이 8개가 아닌 800개로 설정되었으므로 큰 파일은 작은 파일의 약 100배 크기일 것이라고 생각할 수 있습니다. 검색 결과 전체 800개의 결과가 나오지 않았을 가능성이 높습니다(아마도 16~20개에 불과할 것입니다).

페이지 매김을 악용하는 것은 누군가가 GraphQL 쿼리 매개변수를 조작하여 서버에 부하를 추가하는 또 다른 예입니다. 공격자는 이 기능을 악용하여 서버가 의도한 것보다 훨씬 더 많은 요청을 처리하도록 하여 리소스 고갈 및 서비스 거부(DoS)를 유발할 수 있습니다.

OWASP API4:2023 제한 없는 리소스 소비

저희가 시연하고 있는 것은 OWASP API 보안 톱 10, 특히 API4:2023 무제한 리소스 소비에 해당합니다. 이 취약점은 API가 특정 종류의 상호 작용이나 요청을 제한하지 않을 때 발생하며, 서버가 DoS 공격 및 기타 운영 중단에 취약하게 됩니다.

API가 제한 없이 과도한 쿼리 또는 페이지 매김을 허용하면 리소스 소비가 급증할 수 있습니다. 이는 결국 성능 저하 또는 완전한 서버 장애를 초래할 수 있습니다. 적절한 제한을 두지 않으면 이러한 공격으로 인해 서비스가 중단될 수 있습니다. 높은 운영 비용이 발생하고 고객이 이탈하여 비즈니스 손실이 발생할 수 있습니다.

자신을 보호하는 방법

이러한 위험에 대처하려면 API 요청을 적절히 규제해야 합니다. 요청할 수 있는 데이터의 양을 제한하는 제어 기능을 구현하세요. 여기에는 쿼리의 크기와 횟수에 대한 제한을 설정하고 속도 제한 및 기타 보호 조치를 구현하는 것이 포함됩니다.

다음은 자신을 보호하기 위한 몇 가지 실용적인 제안입니다:

  • 요청 및 응답 페이로드 크기 제한: 요청 및 반환할 수 있는 데이터 크기에 제한을 설정하면 지나치게 큰 쿼리가 서버에 과부하를 주는 것을 방지할 수 있습니다.
  • 페이지 매김 경계: 페이지 매김의 최대 한도를 구현하여 호출자가 적정 수준보다 많은 레코드를 가져오려고 시도하지 않도록 합니다.
  • 웹 애플리케이션 방화벽(WAF): WAF는 악의적인 활동을 탐지하고 차단하여 GraphQL API에 대한 잠재적인 공격을 차단하는 데 도움이 될 수 있습니다. 이 추가 보안 계층을 추가하려면 Linode Marketplace 의 Haltdos와 같은 WAF를 사용하는 것을 고려하세요.
  • API 보안 도구: 악의적인 활동을 탐지하고 완화할 수 있는 도구는 필수입니다. 이러한 도구는 공격을 나타낼 수 있는 비정상적인 패턴을 식별하여 공격이 시스템에 영향을 미치기 전에 조치를 취할 수 있도록 도와줍니다.

이러한 단계를 수행하면 과도한 리소스 소비를 통해 GraphQL 서버가 악용될 위험을 크게 줄일 수 있습니다. API 상호 작용이 적절하게 규제되도록 하면 서버의 안정성과 성능을 유지하는 데 도움이 됩니다.

GraphQL로 구축하는 방법에 대한 자세한 내용은 GraphQL Apollo를 참조하세요: 예제가 포함된 소개 문서를 참조하세요.

내용

댓글 남기기

이메일 주소는 게시되지 않습니다. 필수 필드가 표시됩니다 *