From e08a042bd8ee4224d265788d0168d70f49dc986e Mon Sep 17 00:00:00 2001 From: Thomas Uhlmann Date: Sat, 4 Aug 2018 18:50:37 +0200 Subject: [PATCH 1/2] Add config option to disable introspection query --- DependencyInjection/Configuration.php | 2 + .../OverblogGraphQLExtension.php | 5 +++ Request/Executor.php | 6 +++ .../doc/security/disable_introspection.md | 19 +++++++++ Resources/doc/security/index.md | 1 + .../config/disableIntrospection/config.yml | 17 ++++++++ .../Security/DisableIntrospectionTest.php | 39 +++++++++++++++++++ 7 files changed, 89 insertions(+) create mode 100644 Resources/doc/security/disable_introspection.md create mode 100644 Tests/Functional/App/config/disableIntrospection/config.yml create mode 100644 Tests/Functional/Security/DisableIntrospectionTest.php diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index ef9746cae..78d9cbd94 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -2,6 +2,7 @@ namespace Overblog\GraphQLBundle\DependencyInjection; +use GraphQL\Validator\Rules\DisableIntrospection; use GraphQL\Validator\Rules\QueryComplexity; use GraphQL\Validator\Rules\QueryDepth; use Overblog\GraphQLBundle\Error\ErrorHandler; @@ -166,6 +167,7 @@ private function securitySection() ->children() ->append($this->securityQuerySection('query_max_depth', QueryDepth::DISABLED)) ->append($this->securityQuerySection('query_max_complexity', QueryComplexity::DISABLED)) + ->append($this->securityQuerySection('disable_introspection', DisableIntrospection::DISABLED)) ->booleanNode('handle_cors')->defaultFalse()->end() ->end() ->end(); diff --git a/DependencyInjection/OverblogGraphQLExtension.php b/DependencyInjection/OverblogGraphQLExtension.php index f185e2078..023d02779 100644 --- a/DependencyInjection/OverblogGraphQLExtension.php +++ b/DependencyInjection/OverblogGraphQLExtension.php @@ -162,6 +162,11 @@ private function treatConfigs(array $configs, ContainerBuilder $container, $forc private function setSecurity(array $config, ContainerBuilder $container) { + if (!empty($config['security']['disable_introspection'])) { + $executorDefinition = $container->getDefinition($this->getAlias().'.request_executor'); + $executorDefinition->addMethodCall('disableIntrospectionQuery'); + } + foreach ($config['security'] as $key => $value) { $container->setParameter(sprintf('%s.%s', $this->getAlias(), $key), $value); } diff --git a/Request/Executor.php b/Request/Executor.php index d01501031..9c08717f9 100644 --- a/Request/Executor.php +++ b/Request/Executor.php @@ -7,6 +7,7 @@ use GraphQL\Executor\Promise\PromiseAdapter; use GraphQL\Type\Schema; use GraphQL\Validator\DocumentValidator; +use GraphQL\Validator\Rules\DisableIntrospection; use GraphQL\Validator\Rules\QueryComplexity; use GraphQL\Validator\Rules\QueryDepth; use Overblog\GraphQLBundle\Event\Events; @@ -113,6 +114,11 @@ public function setMaxQueryComplexity($maxQueryComplexity) $queryComplexity->setMaxQueryComplexity($maxQueryComplexity); } + public function disableIntrospectionQuery() + { + DocumentValidator::addRule(new DisableIntrospection()); + } + /** * @param null|string $schemaName * @param array $request diff --git a/Resources/doc/security/disable_introspection.md b/Resources/doc/security/disable_introspection.md new file mode 100644 index 000000000..4dc67f6ab --- /dev/null +++ b/Resources/doc/security/disable_introspection.md @@ -0,0 +1,19 @@ +Disable introspection +===================== + +This bundle supports [webonyx/graphql-php validation rule to disable introspection queries](webonyx/graphql-php). + +Introspection is a mechanism for fetching schema structure. It is used by tools like GraphiQL for auto-completion, query validation, etc. + +It means that anybody can get a full description of your schema by sending a special query containing meta fields __type and __schema. + +If you are not planning to expose your API to the general public, it makes sense to disable this feature in production. By disabling, tools like GraphiQL won't work anymore. + +```yaml +#app/config/config.yml +overblog_graphql: + security: + disable_introspection: '%kernel.debug%' +``` + +Introspection is enabled by default. diff --git a/Resources/doc/security/index.md b/Resources/doc/security/index.md index be362d504..078f93e98 100644 --- a/Resources/doc/security/index.md +++ b/Resources/doc/security/index.md @@ -6,5 +6,6 @@ Security * [Fields public control](fields-public-control.md) * [Limiting query depth](limiting-query-depth.md) * [Query complexity analysis](query-complexity-analysis.md) +* [Disable introspection](disable_introspection.md) Next step [handling errors](../error-handling/index.md) diff --git a/Tests/Functional/App/config/disableIntrospection/config.yml b/Tests/Functional/App/config/disableIntrospection/config.yml new file mode 100644 index 000000000..4107811cc --- /dev/null +++ b/Tests/Functional/App/config/disableIntrospection/config.yml @@ -0,0 +1,17 @@ +imports: + - { resource: ../config.yml } + - { resource: ../connection/services.yml } + +overblog_graphql: + security: + disable_introspection: true + definitions: + class_namespace: "Overblog\\GraphQLBundle\\QueryComplexity\\__DEFINITIONS__" + schema: + query: Query + mutation: ~ + mappings: + types: + - + type: yaml + dir: "%kernel.root_dir%/config/queryComplexity/mapping" diff --git a/Tests/Functional/Security/DisableIntrospectionTest.php b/Tests/Functional/Security/DisableIntrospectionTest.php new file mode 100644 index 000000000..7f1335bf5 --- /dev/null +++ b/Tests/Functional/Security/DisableIntrospectionTest.php @@ -0,0 +1,39 @@ + [ + [ + 'message' => 'GraphQL introspection is not allowed, but the query contained __schema or __type', + 'category' => 'graphql', + 'locations' => [ + [ + 'line' => 2, + 'column' => 3, + ], + ], + ], + ], + ]; + + $this->assertResponse($this->introspectionQuery, $expected, self::ANONYMOUS_USER, 'disableIntrospection'); + } +} From cbe26a1115b89aa6023b4b2248b7fb65de84e39c Mon Sep 17 00:00:00 2001 From: Thomas Uhlmann Date: Mon, 6 Aug 2018 13:04:48 +0200 Subject: [PATCH 2/2] Change config option to enable_introspection --- DependencyInjection/Configuration.php | 3 +-- DependencyInjection/OverblogGraphQLExtension.php | 2 +- README.md | 1 + Resources/doc/security/disable_introspection.md | 4 ++-- Tests/Functional/App/config/disableIntrospection/config.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 78d9cbd94..814628dff 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -2,7 +2,6 @@ namespace Overblog\GraphQLBundle\DependencyInjection; -use GraphQL\Validator\Rules\DisableIntrospection; use GraphQL\Validator\Rules\QueryComplexity; use GraphQL\Validator\Rules\QueryDepth; use Overblog\GraphQLBundle\Error\ErrorHandler; @@ -167,7 +166,7 @@ private function securitySection() ->children() ->append($this->securityQuerySection('query_max_depth', QueryDepth::DISABLED)) ->append($this->securityQuerySection('query_max_complexity', QueryComplexity::DISABLED)) - ->append($this->securityQuerySection('disable_introspection', DisableIntrospection::DISABLED)) + ->booleanNode('enable_introspection')->defaultTrue()->end() ->booleanNode('handle_cors')->defaultFalse()->end() ->end() ->end(); diff --git a/DependencyInjection/OverblogGraphQLExtension.php b/DependencyInjection/OverblogGraphQLExtension.php index 023d02779..535b4629d 100644 --- a/DependencyInjection/OverblogGraphQLExtension.php +++ b/DependencyInjection/OverblogGraphQLExtension.php @@ -162,7 +162,7 @@ private function treatConfigs(array $configs, ContainerBuilder $container, $forc private function setSecurity(array $config, ContainerBuilder $container) { - if (!empty($config['security']['disable_introspection'])) { + if (false === $config['security']['enable_introspection']) { $executorDefinition = $container->getDefinition($this->getAlias().'.request_executor'); $executorDefinition->addMethodCall('disableIntrospectionQuery'); } diff --git a/README.md b/README.md index 518b629a6..f32c0a02a 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ Documentation - [Fields public control](Resources/doc/security/fields-public-control.md) - [Limiting query depth](Resources/doc/security/limiting-query-depth.md) - [Query complexity analysis](Resources/doc/security/query-complexity-analysis.md) + - [Disable introspection](Resources/doc/security/disable_introspection.md) - [Errors handling](Resources/doc/error-handling/index.md) - [Events](Resources/doc/events/index.md) diff --git a/Resources/doc/security/disable_introspection.md b/Resources/doc/security/disable_introspection.md index 4dc67f6ab..33924a6cb 100644 --- a/Resources/doc/security/disable_introspection.md +++ b/Resources/doc/security/disable_introspection.md @@ -1,7 +1,7 @@ Disable introspection ===================== -This bundle supports [webonyx/graphql-php validation rule to disable introspection queries](webonyx/graphql-php). +This bundle supports [webonyx/graphql-php validation rule to disable introspection queries](http://webonyx.github.io/graphql-php/security/#disabling-introspection). Introspection is a mechanism for fetching schema structure. It is used by tools like GraphiQL for auto-completion, query validation, etc. @@ -13,7 +13,7 @@ If you are not planning to expose your API to the general public, it makes sense #app/config/config.yml overblog_graphql: security: - disable_introspection: '%kernel.debug%' + enable_introspection: '%kernel.debug%' ``` Introspection is enabled by default. diff --git a/Tests/Functional/App/config/disableIntrospection/config.yml b/Tests/Functional/App/config/disableIntrospection/config.yml index 4107811cc..1f8a4d63c 100644 --- a/Tests/Functional/App/config/disableIntrospection/config.yml +++ b/Tests/Functional/App/config/disableIntrospection/config.yml @@ -4,7 +4,7 @@ imports: overblog_graphql: security: - disable_introspection: true + enable_introspection: false definitions: class_namespace: "Overblog\\GraphQLBundle\\QueryComplexity\\__DEFINITIONS__" schema: