Khai thác GraphQL API

“Mọi kiến thức trong bài viết chỉ phục vụ mục đích giáo dục và an toàn thông tin.
Không được sử dụng để tấn công hệ thống mà bạn không sở hữu hoặc không được phép kiểm thử.”

GraphQL là gì?

GraphQL là ngôn ngữ truy vấn API được thiết kế để hỗ trợ giao tiếp hiệu quả giữa máy khách và máy chủ. Nó cho phép người dùng chỉ định chính xác dữ liệu họ muốn trong phản hồi, giúp tránh các đối tượng phản hồi lớn và nhiều lệnh gọi đôi khi có thể được nhìn thấy với API REST.

Các dịch vụ GraphQL xác định một liên kết thông qua đó máy khách có thể giao tiếp với máy chủ. Máy client không cần biết data ở đâu. Thay vào đó máy client gửi truy vấn đến máy GraphQL server, máy server này sẽ tìm nạp dữ liệu từ những nơi có liên quan.

=> GraphQL không phục thuộc vào nền tảng nên có thể được triển khai với nhiều loại ngôn ngữ lập trình và có thể giao tiế với mọi kho lưu trữ dữ liệu.

Cách hoạt động của GraphQL?

GraphQL scheme sẽ xác định cấu trúc dữ liệu của dịch vụ, liệt kê các đối tượng có sẵn (được gọi là type), trường (field) và các mối quan hệ (relationship).

Dữ liệu được mô tả bởi lược đồ GraphQL có thể được thao tác bằng ba loại thao tác sau:

  • Truy vấn tìm nạp dữ liệu
  • Mutation: add, change và delete dữ liệu.
  • Subscription tương tự như truy vấn, nhưng thiết lập kết nối vĩnh viến qua đó máy chủ có thể chủ động đẩy dữ liệu tới máy khác ở định dạng được chỉ định.

Tất cả các hoạt động của GraphQL đều sử dụng cùng một endpoint và thường được gửi dưới dạng POST request. Điều này khác so với API REST, sử dụng các endpoint dành riêng cho hoạt động trên một loạt các phương thức HTTP.

Trong GraphQL, type và name của thao tác xác định cách xử lý truy vấn, thay vì dựa vào endpoint mà truy vấn được gửi tới hoặc dựa vào phương thức HTTP được sử dụng.

Các dịch vụ GraphQL thường phản hồi các hoạt động với một đối tượng JSON trong cấu trúc được yêu cầu.

GraphQL scheme là gì?

Trong GraphQL, lược đồ (schema) đại diện cho một giao dịch giữa giao diện người dùng và phần đáp ứng dịch vụ. Nó xác định dữ liệu có sẵn dưới dạng một loạt các type, sử dụng ngôn ngữ định nghĩa lược đồ mà con người có thể đọc được. Các type này có thể được thực hiện bởi một dịch vụ.

Hầu hết các type được định nghĩa là các đối tượng. Trong đó xác định các đối tượng có sẵn và các field và các đối số mà chúng có. Mỗi trường có một type riêng, có thể là một đối tượng khác hoặc một type vố hướngenumunioninterface hoặc custom type.

Ví dụ: một định nghĩa lược đồ đơn giản cho type Product.

GraphQL query là gì?

GraphQL query lấy dữ liệu từ kho lưu trữ dữ liệu. Chúng gần giống các GET requests trong API REST.

Ví dụ: Một truy vấn có tên myGetProductQuery yêu cầu các trường tên và mô tả của sản phẩm có thuộc tính id là 123.

#Example query

query myGetProductQuery {
        getProduct(id: 123) {
            name
            description
        }
    }

Lưu ý, type Product có thể chứa nhiều trường trong lược đồ hơn những trường được yêu cầu ở đây. Khả năng chỉ yêu cầu dữ liệu bạn cần là một phần quan trọng trong tính linh hoạt của GraphQL.

Mutation là gì?

Các mutation thay đổi dữ liệu bằng cách thêm, xóa hoặc chỉnh sửa dữ liệu. Chúng gần giông như các phương thức POST, PUT và DELETE của API REST.

Cũng giống như các query, mutation cũng có loại thao thác truy vấntên và cấu trúc cho dữ liệu trả về. Tuy nhiên, các muation luôn lấy một loại input nào đó. Đây có thể là một giá trị nội tuyến, nhưng trong thực tế thường được cung cấp dưới dạng một biến.

Ví dụ, dưới đây cho thấy một đột biến để tạo ra một sản phẩm mới và phản ứng liên quan của nó.

Trong trường hợp này, dịch vụ được định cấu hình để tự động gán ID cho các sản phẩm mới đã được trả lại theo yêu cầu.

requests:

    #Example mutation request

    mutation {
        createProduct(name: "Flamin' Cocktail Glasses", listed: "yes") {
            id
            name
            listed
        }
    }

response:

    #Example mutation response

    {
        "data": {
            "createProduct": {
                "id": 123,
                "name": "Flamin' Cocktail Glasses",
                "listed": "yes"
            }
        }
    }

Các thành phần chính của query và mutation

Fields

Tất cả các type GraphQL đều chứa các mục dữ liệu có thể truy vấn được gọi là các trường.

Khi gửi query hoặc mutation, ta cần chỉ định trường nào muốn API trả về. Response trả về nội dung được yêu cầu trong requests.

Ví dụ: một truy vấn để nhận thông tin chi tiết về ID và tên của tất cả nhân viên và phản hồi liên quan. Trong trường hợp này idname.firstname và name.lastname là các trường được yêu cầu.

    #Request

    query myGetEmployeeQuery {
        getEmployees {
            id
            name {
                firstname
                lastname
            }
        }
    }
    #Response

    {
        "data": {
            "getEmployees": [
                {
                    "id": 1,
                    "name" {
                        "firstname": "Carlos",
                        "lastname": "Montoya"
                    }
                },
                {
                    "id": 2,
                    "name" {
                        "firstname": "Peter",
                        "lastname": "Wiener"
                    }
                }
            ]
        }
    }

Arguments

Đối số là các giá trị được cung cấp cho các trường cụ thể. Các đối số có thể được chấp nhận cho một type được xác định trong lược đồ.

Khi gửi query hoặc mutation có chứa đối số, máy chủ GraphQL sẽ xác định cách phản hồi dựa trên cấu hình của nó. Ví dụ: nó có thể trả về một đối tượng cụ thể hơn là chi tiết của tất cả các đối tượng. Ví dụ: Nó có thể trả về một đối tượng cụ thể hơn là chi tiết của tất cả các đối tượng.

Ví dụ: yêu cầu getEmployee lấy ID nhân viên làm đối số. Trong trường hợp này, máy chủ chỉ phản hồi với thông tin của nhân viên khớp với ID đó.

    #Example query with arguments

    query myGetEmployeeQuery {
        getEmployees(id:1) {
            name {
                firstname
                lastname
            }
        }
    }
    #Response to query

    {
        "data": {
            "getEmployees": [
            {
                "name" {
                    "firstname": Carlos,
                    "lastname": Montoya
                    }
                }
            ]
        }
    }

Nếu các đối số do người dùng cung cấp được sử dụng để truy cập trực tiếp các đối tượng thì API GraphQL có thể dễ bị tấn công bởi các lỗ hổng Access Control như IDOR.

Variables

Các biến cho phép chuyển các đối số động, thay vì có các đối số trực tiếp trong chính truy vấn đó.

query dựa trên biến cũng giống như query sử dụng đối số inline. Nhưng một số khía cạnh nhất định của truy vấn được lấy từ một từ điển biến dựa trên JSON riêng biệt. Chúng cho phép bạn sử dụng lại một cấu trúc chung giữa nhiều truy vấn, chỉ với giá trị của chính biến sau khi thay đổi.

Ví dụ: hiển thị cùng một truy vấn như ví dụ trước, nhưng với ID được chuyển dưới dạng biến thay vì dưới dạng một phần trực tiếp của chuỗi truy vấn.

#Example query with variable

query getEmployeeWithVariable($id: ID!) {
    getEmployees(id:$id) {
        name {
            firstname
            lastname
        }
        }
}

Variables:
{
    "id": 1
}

Trong ví dụ này, biến được khai báo ở dòng đầu tiên với ($id: ID!) . Dấu ! cho biết đây là một trường bắt buộc đối với query này. Sau đó, nó được sử dụng làm đối số trong dòng thứ 2 với id:$id. Cuối cùng, giá trị của chính biến này được đặt trong từ điển JSON của biến đó.

Aliases

Các đối tượng GraphQL không thể chứa nhiều thuộc tính có cùng tên.

Ví dụ: Truy vấn sau đây sẽ không hợp lệ vì nó trả về type product hai lần.

    #Invalid query

    query getProductDetails {
        getProduct(id: 1) {
            id
            name
        }
        getProduct(id: 2) {
            id
            name
        }
    }

Aliases cho phép bỏ qua hạn chế này bằng cách đặt tên một cách rõ ràng cho các thuộc tính mà bạn muốn API trả về.

Bạn có thể sử dụng aliases để trả về nhiều phiên bản của cùng một đối tượng type trong một yêu cầu. Điều này giúp giảm số lượng lệnh gọi API cần thiết.

Ví dụ: Một query sử dụng aliases để chỉ định name duy nhất cho cả hai sản phẩm. Truy vấn này có thể vượt qua xác thực và trả về chi tiết.

    #Valid query using aliases

    query getProductDetails {
        product1: getProduct(id: "1") {
            id
            name
        }
        product2: getProduct(id: "2") {
            id
            name
        }
    }
    #Response to query

    {
        "data": {
            "product1": {
                "id": 1,
                "name": "Juice Extractor"
             },
            "product2": {
                "id": 2,
                "name": "Fruit Overlays"
            }
        }
    }

Sử dụng aliases với các mutation cho phép bạn gửi nhiều request GraphQL trong một request HTTP một cách hiệu quả.

Tham khảo cách tấn công này: Bỏ qua giới hạn tốc độ

Fragments

Các phân đoạn là các phần có thể tái sử dụng của query và mutaion. Chúng chứa một tập hợp con các trường thuộc type được liên kết.

Sau khi được xác định, chúng có thể được đưa vào query và mutation. Nếu sau đó chúng được thay đổi, thì thay đổi đó được bao gồm trong mọi query và mutation gọi phân đoạn này.

Ví dụ: một query getProduct trong đó các chi tiết của sản phẩm được chứa trong một phân đoạn productInfo

    #Example fragment

    fragment productInfo on Product {
        id
        name
        listed
    }
    #Query calling the fragment

    query {
        getProduct(id: 1) {
            ...productInfo
            stock
        }
    }
    #Response including fragment fields

    {
        "data": {
            "getProduct": {
                "id": 1,
                "name": "Juice Extractor",
                "listed": "no",
                "stock": 5
            }
        }
    }

Subscriptions

Subscription là một loại query đặc biệt. Chúng cho phép máy client thiết lập kết nối lâu dài với máy chủ để sau đó máy chủ có thể đẩy các bản cập nhật theo thời gian thực tới máy khách mà không cần phải liên tục thăm dò dữ liệu. Chúng chủ yếu hữu ích cho những thay đổi nhỏ đối với các đối tượng lớn và cho chức nắng yêu cầu cậ nhật thời gian thực nhỏ như (hệ thống trò chuyện hoặc hệ thống chỉnh sửa onlien).

Cũng giống như các query và mutation thông thường, các request Subscription xác định hình dạng của dữ liệu được trả về

Subscription thường được thực hiện bằng cách sử dụng WebSockets

Introspection

Là một hàm GraphQL tích hợp cho phép bạn truy vấn máy chủ để biết thông tin về schema.

Thường dùng cho các ứng dụng như GraphQL IDE và công cụ tạo tài liệu.

Hàm này có thể gây ra rủi ro Tiết lộ thông tin nhạy cảm. Vì nó có thể được sử dụng để truy cập thông tin nhạy cảm tiềm ẩn như (mô tả trường) , giúp attacker có thể hiểu được cách chúng có thể tương tác với API. Cách tốt nhất là tắt tính năng Introspection trong môi trường sản xuất.

Làm sao để tìm được GraphQL Enpoint?

Trước khi có thể kiểm thử API GraphQL, ta cần tìm ra endpoint của nó.

Vì các API GraphQL sử dụng cùng một endpoint cho tất cả các request nên đây là thông tin quan trọng.

=> Burp Scanner có thể tự động phát hiện ra endpoint GraphQL và phát sinh sự cố GraphQL endpoint found.

Query chung

Nếu gửi truy vấn query{__typename} vào GraphQL endpoint, nó sẽ bao gồm chuỗi {"data": {"__typename": "query"}} trong phản hồi.

Truy vấn này hoạt động vì mọi endpoint GraphQL đều có một trường dành riêng được gọi là __typename . Đây là trường trả về type của đối tượng được truy xuất dưới dạng chuỗi.

Một số endpoint phổ biến

Các dịch vụ GraphQL thường sử dụng các hậu tố endpoint tương ứng. Khi kiểm tra các GraphQL endpoint, nên tìm cách gửi các truy vấn chung đến các vị trí sau:

/graphql
/api
/api/graphql
/graphql/api
/graphql/graphql
/v1
/graphql/v1

Chú ý: Các dịch vụ GraphQL thường sẽ phản hồi mọi yêu cầu không phải GraphQL với lỗi query not present hoặc lỗi tương tự. Nên nhớ kỹ điều này khi thực hiện kiểm thử các endpoint GraphQL.

Phương pháp requests

Bước tiếp theo trong việc cố gắng tìm các endpoint GraphQL là kiểm tra bằng cách phương thức request khác nhau.

Tốt nhất các GraphQL endpoint trong thực tế chỉ chấp nhận các POST requests có kiểu nội dung là application/json, vì điều này giúp bảo vệ chống lại các lỗ hổng CSRF.

Tuy nhiên, một số endpoint có thể chấp nhận các phương thức thay thế, chẳng hạn như GET hoặc POST sử dụng kiểu nội dung x-www-form-urlencoded.

Nếu bạn không tìm thấy điểm cuối GraphQL bằng cách gửi các POST request tới các điểm cuối chung, hãy thử lại truy vấn chung bằng các phương thức HTTP thay thế nói trên.

Khai thác các đối số không được làm sạch

Tại thời điểm này, ta có thể bắt đầu tìm kiếm các lỗ hổng bảo mật.

Nếu API sử dụng các đối số để truy cập các đối tượng trực tiếp, nó có thể chứa các lỗ hổng Access Control . Người dùng có thể khai thác IDOR bằng cách cung cấp một đối số tương ứng với thông tin đó.

Ví dụ: Truy vấn yêu cầu danh sách sản phẩm cho một cửa hàng trực tuyến.

 #Example product query
 query {
     products {
         id
         name
         listed
     }
 }

Danh sách sản phẩm được trả lại chỉ chứa một vài sản phẩm

#Example product response

    {
        "data": {
            "products": [
                {
                    "id": 1,
                    "name": "Product 1",
                    "listed": true
                },
                {
                    "id": 2,
                    "name": "Product 2",
                    "listed": true
                },
                {
                    "id": 4,
                    "name": "Product 4",
                    "listed": true
                }
            ]
        }
    }

Từ thông tin này, chúng ta có thể suy ra:

  • Sản phẩm được gán một ID tuần tự
  • ID sản phẩm số 3 bị thiếu , có thể do nó đã bị xóa

Tiếp tục Thực hiện try vấn ID sản phẩm bị thiếu, chúng ta có thể nhận được thông tin chi tiết về sản phẩm đó.

    #Query to get missing product

    query {
        product(id: 3) {
            id
            name
            listed
        }
    }
    #Missing product response

    {
        "data": {
            "product": {
            "id": 3,
            "name": "Product 3",
            "listed": no
            }
        }
    }

Điều này bác bỏ đi suy luận thứ 2 của tôi.

Khám phá thông tin lược đồ

Bước tiếp theo trong quá trình thử nghiệm API là ghép thông tin về lược đồ cơ bản lại với nhau.

Cách tốt nhất là sử dụng introspection queries . Introspection là một hàm GraphQL tích hợp cho phép truy vấn máy chủ để biết thông tin về lược đồ.

Sử dụng introspection

Để sử dụng introspection để khám phá thông tin lược đồ. Hãy sử dụng truy vấn trường __schema . Trường này có sẵn trên type gốc của tất cả các truy vấn.

Cũng như query thông thường. Ta có thể chỉ định các trường và cấu trúc của phản hồi mà bạn muốn được trả về khi chạy một truy vấn introspection. Ví dụ: in ra các mutation có sẵn trong phản hồi.

Thăm dò introspection

Có thể thăm dò introspection bằng truy vấn đơn giản sau:

    #Introspection probe request

    {
        "query": "{__schema{queryType{name}}}"
    }

Nếu introspection được bật, phản hồi sẽ trả về tên của tất cả các truy vấn có sẵn.

Burp Scanner có thể tự động kiểm tra xem xét introspection trong quá trình scan. Nếu phát hiện tính năng này được bật , sẽ có cảnh báo GraphQL introspection enabled.

Chạy một truy vấn introspection đầy đủ

Bước tiếp theo là chạy một truy vấn đầy đủ tới endpoint để có thể nhận được càng nhiều thông tin trên lược đồ càng tốt.

Truy vấn sau sẽ trả về đầy đủ chi tiết về tất cả querymutationsubscriptionstype và segments.

#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
                }
            }
        }
    }

Chú ý: Nếu inspection được bật nhưng query trên không chạy, hãy thử xóa các lệnh onOperationonFragment và onField khỏi cấu trúc query.

Nhiều endpoint không chấp nhận các chỉ thị này như một phần của query introspection.

Hình dung kết quả của introspection

Các kết quả của truy vấn introspection có thể rất dài và khó xử lý.

Ta có thể xem xét các mối quan hệ giữa các thực thể lược đồ dễ dàng hơn bằng cách sử dụng Trình hiển thị GraphQL

Sử dụng Extension InQL

Đây là một giải pháp thay thế cho việc chạy query introspection thủ công và trực quan hóa kết quả là tiện ích InQL của Burp Suite.

Đây là một tiện ích của burp suite giúp kiểm tra API GraphQL một cách an toàn. Khi chuyển một URL tới nó (cung cấp liên kết chứa endpoint bằng tải tệp JSON lên) , nó sẽ đưa ra một truy vấn introspection yếu cầu tất cả các query và mutation, đồng thời hiển thị dạng xem có cấu trúc để giúp dễ dàng khám phá.

Tham khảo: https://portswigger.net/burp/documentation/desktop/testing-workflow/session-management/working-with-graphql

Suggestions

Ngay cả khi tính năng introspection bị vô hiệu hóa, đôi khi bạn vẫn có thể sử dụng các suggestions để thu thập thông tin về cấu trúc của API.

suggestion là một tính năng của nền tảng Apollo GraphQL, trong đó máy chủ có thể đề xuất sửa đổi truy vấn trong thông báo lỗi. Chúng thường được sử dụng khi một truy vấn hơi sai nhưng vẫn có thể nhận ra.

Ví dụ: There is no entry for 'productInfo'. Did you mean 'productInformation' instead?

Từ thông báo lỗi trên, có thể thu thập thông tin hữu ích khác, vì phản hồi đang hiển thị các giá trị hợp lệ của lược đồ.

Clairvoyance là một công cụ sử dụng các suggestion để tự động khôi phục tất cả hoặc một phần của lược đồ GraphQL, ngay cả khi tính năng xem xét introspection bị tắt. Điều này làm cho việc ghép thông tin từ các phản hồi suggestion tốn ít thời gian hơn

Người lập trình không thể tắt suggestion trong Apollo. Cách giải quyết xem tại đây:

Burp Scanner có thể tự động kiểm tra các suggestion. Nếu tìm thấy các suggestion đang hoạt động, Burp Scanner sẽ thông báo sự cố GraphQL suggestions enabled.

Bypass các biện pháp bảo vệ introspection của GraphQL

Nếu không thể kiểm thử với các truy vấn introspection thông thường, ta có thể chèn một ký tự đặc biệt sau từ khóa __schema.

Khi nhà phát triển tắt tính tăng introspection, họ có thể sử dụng biểu thức chính quy để loại trừ từ khóa __schema trong các truy vấn.

Đối với các ký tự đặc biệt: ta có thể thử với các ký tự như dấu cách, newline, dấu phẩy vì chúng bị GraphQL bỏ qua.

Nếu cách này không hiệu quả, có thể thử với một phương thức request thay thế, vì tính năng introspection chỉ có thể bị vô hiệu qua thông quan POST requests.

Hãy thử một GET request hoặc POST request với một content-type khác như x-www-form-urlencoded.

Ví dụ: thăm dò introspection được gửi qua GET với các tham số được urlencode

Chú ý: Nếu một endpoint chỉ chấp nhận các truy vấn introspection qua GET và bạn muốn phân tích kết quả của truy vấn bằng InQL Scanner, trước tiên ta cần phải lưu truy vấn vào một tệp. Sau đó, tải tệp vào InQL, tệp sẽ được phân tích cú pháp như bình thường.

Bypass giới hạn tỷ lệ sử dụng aliases

Thông thường, các đối tượng GraphQL không thể chứa nhiều thuộc tính có cùng tên. Aliases cho phép bỏ qua hạn chế này bằng cách đặt tên rõ ràng cho các thuộc tính mà ta muốn APi trả về.

Ta có thể sử dụng alias để trả về nhiều phiên bản của cùng một loại đối tượng trong một requests.

Mặc dùng các alias được sử dụng để giới hạn một số lượng lệnh gọi API , nhưng chúng cũng có thể được sử dụng để burp force một endpoint GraphQL.

Các endpoint đôi khi sẽ có sẵn một số loại giới hạn tốc độ để ngăn chặn các cuộc tấn công vét cạn như vậy. Một số khác thì sẽ giới hạn tốc độ hoạt động dựa trên số lượng HTTP requests nhận được thay vì số lượng thao tác được thực hiện trên endpoint.

Ví dụ: truy vấn alias để kiểm tra xem mã giảm giá của cửa hàng có hợp lệ hay không. Thao tác này có khả năng bỏ qua giới hạn tốc độ vì nó là một HTTP request duy nhất, mặc dù nó có thể được sử dụng để kiểm tra một số lượng lớn mã giảm giá cùng lúc.

    #Request with aliased queries

    query isValidDiscount($code: Int) {
        isvalidDiscount(code:$code){
            valid
        }
        isValidDiscount2:isValidDiscount(code:$code){
            valid
        }
        isValidDiscount3:isValidDiscount(code:$code){
            valid
        }
    }

GraphQL CSRF

Các lỗ hổng CSRF cho phép kẻ tấn công khiến người dùng thực hiện các hành động mà họ không có ý định thực hiện. Điều này được thực hiện bằng cách tạo một website độc hại giả mạo tên miền request tới ứng dụng dễ bị tấn công.

GraphQL có thể sử dụng làm vector cho các cuộc tấn công CSRF, kẻ tấn công tạo ra một payload làm cho trình duyệt của nạn nhân gửi truy vấn độc hại.

Cách phát sinh

Lỗ hổng CSRF GrapQL có thể phát sinh khi endpoint GraphQL không xác thực loại nội dung của các requests được gửi tới đó và không có mã thông báo CSRF nào được triển khai.

Các POST requests sử dụng Content-type: application/json được bảo mật chống giả mạo miễn là loại nội dung được xác thực. Trong trường hợp này, kẻ tấn công sẽ không thể khiến trình duyệt của nạn nhân gửi reqeust này ngay cả khi nạn nhân truy cập một trang web độc hại.

Các GET request hoặc bất kỳ request nào có content-type là x-www-form-urlencoded , có thể được gửi bởi trình duyệt vì vậy có thể làm cho người dùng dễ bị tấn công nếu endpoint chấp nhận các request này.

Các ngăn chặn các cuộc tấn công GraphQL

Để ngăn chặn các cuộc tấn công GraphQL phổ biến. Khi phát triển ứng dụng ta cần lưu ý điều gì? :+1:

  • Nếu API không public thì tốt nhất là nên tắt introspection giải lộ thông tin nhạy cảm.
  • Nếu API này là public thì phải bật introspection. Nên xem xét lại scheme để nó không lộ lọt những trường không mong muốn.
  • Nên vô hiệu hóa suggestions ngăn việc sử dụng Clairvoyance để suy luận ra thông tin lược đồ. Chú ý: trong Apollo không thể tắt suggestions.
  • API không nên hiển thị bất kì trường user private nào như email, userid.
  • Ngăn chặn alias brute force
    • Giới hạn độ sâu truy vấn của API. Độ sâu truy vấn chính là số lượng truy vấn lồng nhau trong một query.
    • Định cấu hình số lượng byte tối đa mà một truy vấn có thể chứa
    • Nên phân tích chi phí trên API. Xác định lượng tài nguyên cần để chạy truy vấn , nếu quá phức tạp về tính toán để chạy thì loại bỏ luôn.
  • Ngăn chặn CSRF
    • APi chỉ chấp nhận các query POST
    • API nên xác thực xem input có khớp với Content-type được cung cấp không. nên dùng lại có độ bảo mật cao.

Cảm ơn bạn đã đón đọc, hẹn gặp lại tại các bài viết khác nhé.

Leave a comment