Add property for disabling GraphQL schema introspection

Prior to this commit, the GraphQL schema assembled by the
auto-configuration would provide no option for disabling the field
introspection.

While this feature is essential for many tools (including GraphiQL),
some prefer disabling it because this allows clients to gather
information about types and schema easily. This commit introduces a new
`spring.graphql.schema.introspection.enabled` configuration property.

Because potential attackers can still gather this information and this
feature is a core concern in the GraphQL spec, introspection is enabled
by default for Spring Boot applications.

Closes gh-29248
This commit is contained in:
Brian Clozel 2022-01-03 17:09:40 +01:00
parent 728206dba0
commit c5817f21eb
4 changed files with 51 additions and 0 deletions

View File

@ -24,6 +24,7 @@ import java.util.stream.Collectors;
import graphql.GraphQL;
import graphql.execution.instrumentation.Instrumentation;
import graphql.schema.visibility.NoIntrospectionGraphqlFieldVisibility;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -77,6 +78,10 @@ public class GraphQlAutoConfiguration {
.schemaResources(schemaResources.toArray(new Resource[0]))
.exceptionResolvers(exceptionResolversProvider.orderedStream().collect(Collectors.toList()))
.instrumentation(instrumentationsProvider.orderedStream().collect(Collectors.toList()));
if (!properties.getSchema().getIntrospection().isEnabled()) {
builder.configureRuntimeWiring((wiring) -> wiring
.fieldVisibility(NoIntrospectionGraphqlFieldVisibility.NO_INTROSPECTION_FIELD_VISIBILITY));
}
wiringConfigurers.orderedStream().forEach(builder::configureRuntimeWiring);
sourceCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
try {

View File

@ -73,6 +73,8 @@ public class GraphQlProperties {
*/
private String[] fileExtensions = new String[] { ".graphqls", ".gqls" };
private final Introspection introspection = new Introspection();
private final Printer printer = new Printer();
public String[] getLocations() {
@ -96,10 +98,31 @@ public class GraphQlProperties {
.toArray(String[]::new);
}
public Introspection getIntrospection() {
return this.introspection;
}
public Printer getPrinter() {
return this.printer;
}
public static class Introspection {
/**
* Whether field introspection should be enabled at the schema level.
*/
private boolean enabled = true;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
public static class Printer {
/**

View File

@ -21,6 +21,8 @@ import graphql.execution.instrumentation.ChainedInstrumentation;
import graphql.execution.instrumentation.Instrumentation;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.visibility.DefaultGraphqlFieldVisibility;
import graphql.schema.visibility.NoIntrospectionGraphqlFieldVisibility;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
@ -145,6 +147,25 @@ class GraphQlAutoConfigurationTests {
});
}
@Test
void fieldIntrospectionShouldBeEnabledByDefault() {
this.contextRunner.run((context) -> {
GraphQlSource graphQlSource = context.getBean(GraphQlSource.class);
GraphQLSchema schema = graphQlSource.schema();
assertThat(schema.getCodeRegistry().getFieldVisibility()).isInstanceOf(DefaultGraphqlFieldVisibility.class);
});
}
@Test
void shouldDisableFieldIntrospection() {
this.contextRunner.withPropertyValues("spring.graphql.schema.introspection.enabled:false").run((context) -> {
GraphQlSource graphQlSource = context.getBean(GraphQlSource.class);
GraphQLSchema schema = graphQlSource.schema();
assertThat(schema.getCodeRegistry().getFieldVisibility())
.isInstanceOf(NoIntrospectionGraphqlFieldVisibility.class);
});
}
@Configuration(proxyBeanMethods = false)
static class CustomGraphQlBuilderConfiguration {

View File

@ -40,6 +40,8 @@ In the following sections, we'll consider this sample GraphQL schema, defining t
include::{docs-resources}/graphql/schema.graphqls[]
----
NOTE: By default, https://spec.graphql.org/draft/#sec-Introspection[field introspection] will be allowed on the schema as it is required for tools such as GraphiQL.
If you wish to not expose information about the schema, you can disable introspection by setting configprop:spring.graphql.schema.introspection.enabled[] to `false`.
[[web.graphql.runtimewiring]]
=== GraphQL RuntimeWiring