From 6d6d1ac01b15b320163bb39e12f4fa546130185f Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Sat, 17 Jun 2017 14:49:07 +0200 Subject: [PATCH 1/4] Adds tests for DisableIntrospection Validation rule --- tests/Validator/DisableIntrospectionTest.php | 128 +++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 tests/Validator/DisableIntrospectionTest.php diff --git a/tests/Validator/DisableIntrospectionTest.php b/tests/Validator/DisableIntrospectionTest.php new file mode 100644 index 0000000..88d771c --- /dev/null +++ b/tests/Validator/DisableIntrospectionTest.php @@ -0,0 +1,128 @@ +expectFailsRule(new DisableIntrospection(DisableIntrospection::ENABLED), ' + query { + __schema { + queryType { + name + } + } + } + ', + [$this->error(3, 9)] + ); + } + + /** + * @it fails if the query contains __type + */ + public function testQueryContainsType() + { + $this->expectFailsRule(new DisableIntrospection(DisableIntrospection::ENABLED), ' + query { + __type( + name: "Query" + ){ + name + } + } + ', + [$this->error(3, 9)] + ); + } + + /** + * @it does not fail on a query that does not contain __type + */ + public function testValidQuery() + { + $this->expectPassesRule(new DisableIntrospection(DisableIntrospection::ENABLED), ' + query { + user { + name + email + friends { + name + } + } + } + '); + } + + /** + * @it does not fail when not enabled + */ + public function testQueryWhenDisabled() + { + $this->expectPassesRule(new DisableIntrospection(DisableIntrospection::DISABLED), ' + query { + __type( + name: "Query" + ){ + name + } + } + '); + } + + /** + * @it has a public interface for enabeling the rule + */ + public function testPublicEnableInterface() + { + $disableIntrospection = new DisableIntrospection(DisableIntrospection::DISABLED); + $disableIntrospection->setEnabled(DisableIntrospection::ENABLED); + $this->expectFailsRule($disableIntrospection, ' + query { + __type( + name: "Query" + ){ + name + } + } + ', + [$this->error(3, 9)] + ); + } + + /** + * @it has a public interface for disableing the rule + */ + public function testPublicDisableInterface() + { + $disableIntrospection = new DisableIntrospection(DisableIntrospection::ENABLED); + $disableIntrospection->setEnabled(DisableIntrospection::DISABLED); + $this->expectPassesRule($disableIntrospection, ' + query { + __type( + name: "Query" + ){ + name + } + } + '); + } + + + private function error($line, $column) + { + return FormattedError::create( + DisableIntrospection::introspectionDisabledMessage(), + [ new SourceLocation($line, $column) ] + ); + } +} From 1c62f554ae3064003fbd654b5282a808d5a504ff Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Sat, 17 Jun 2017 14:50:24 +0200 Subject: [PATCH 2/4] Implements DisableIntrospection validation rule --- src/Validator/Rules/DisableIntrospection.php | 50 ++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/Validator/Rules/DisableIntrospection.php diff --git a/src/Validator/Rules/DisableIntrospection.php b/src/Validator/Rules/DisableIntrospection.php new file mode 100644 index 0000000..f820375 --- /dev/null +++ b/src/Validator/Rules/DisableIntrospection.php @@ -0,0 +1,50 @@ +setEnabled($enabled); + } + + public function setEnabled($enabled) + { + $this->isEnabled = $enabled; + } + + static function introspectionDisabledMessage() + { + return 'GraphQL introspection is not allowed, but the query contained __schema or __type'; + } + + protected function isEnabled() + { + return $this->isEnabled !== static::DISABLED; + } + + public function __invoke(ValidationContext $context) + { + return $this->invokeIfNeeded( + $context, + [ + NodeKind::FIELD => function (FieldNode $node) use ($context) { + if ($node->name->value === '__type' || $node->name->value === '__schema') { + $context->reportError(new Error( + static::introspectionDisabledMessage(), + [$node] + )); + } + } + ] + ); + } +} From 719a438628dfc6af7c7b19ffad9b0f1737e4b27b Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Sat, 17 Jun 2017 14:51:38 +0200 Subject: [PATCH 3/4] Adds DisableIntrospection validation rule to the DocumentValidator (default: disabled) --- src/Validator/DocumentValidator.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Validator/DocumentValidator.php b/src/Validator/DocumentValidator.php index 540765d..837080a 100644 --- a/src/Validator/DocumentValidator.php +++ b/src/Validator/DocumentValidator.php @@ -25,6 +25,7 @@ use GraphQL\Utils; use GraphQL\Utils\TypeInfo; use GraphQL\Validator\Rules\ArgumentsOfCorrectType; use GraphQL\Validator\Rules\DefaultValuesOfCorrectType; +use GraphQL\Validator\Rules\DisableIntrospection; use GraphQL\Validator\Rules\FieldsOnCorrectType; use GraphQL\Validator\Rules\FragmentsOnCompositeTypes; use GraphQL\Validator\Rules\KnownArgumentNames; @@ -100,6 +101,7 @@ class DocumentValidator 'UniqueInputFieldNames' => new UniqueInputFieldNames(), // Query Security + 'DisableIntrospection' => new DisableIntrospection(DisableIntrospection::DISABLED), // DEFAULT DISABLED 'QueryDepth' => new QueryDepth(QueryDepth::DISABLED), // default disabled 'QueryComplexity' => new QueryComplexity(QueryComplexity::DISABLED), // default disabled ]; From beaf91d08089f457c1dac289297f68d03e492a94 Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Sat, 17 Jun 2017 15:01:37 +0200 Subject: [PATCH 4/4] Adds example for enabling the DisableIntrospection rule. --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 9036037..a1cc75e 100644 --- a/README.md +++ b/README.md @@ -559,6 +559,24 @@ $queryDepth->setMaxQueryDepth($maxQueryDepth = 10); GraphQL::execute(/*...*/); ``` +#### Disabling Introspection + +This is a PHP port of [graphql-disable-introspection](https://github.com/helfer/graphql-disable-introspection). +The rule prohibits queries that contain `__type` or `__schema` fields. + +This document validator rule is disabled by default. Here an example to enable it: + +```php +use GraphQL\GraphQL; +use GraphQL\Validator\Rules\DisableIntrospection; + +/** @var \GraphQL\Validator\Rules\DisableIntrospection $disableIntrospection */ +$disableIntrospection = DocumentValidator::getRule('DisableIntrospection'); +$disableIntrospection->setEnabled(DisableIntrospection::ENABLED); + +GraphQL::execute(/*...*/); +``` + ### More Examples Make sure to check [tests](https://github.com/webonyx/graphql-php/tree/master/tests) for more usage examples.