Skip to content

Instantly share code, notes, and snippets.

@benmccallum
Last active May 20, 2021 21:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benmccallum/9329bcc70711f1bc14e74dc82693c607 to your computer and use it in GitHub Desktop.
Save benmccallum/9329bcc70711f1bc14e74dc82693c607 to your computer and use it in GitHub Desktop.
Prevent introspection queries on HotChocolate
/// <summary>
/// Prevents use of certain field names typically used in introspection queries.
/// Useful for production environments where you may want to guard against such queries.
/// </summary>
/// <remarks>
/// Compatible with v10 of HotChocolate.
/// </summary>
public class NoIntrospectionValidationRule : IQueryValidationRule
{
private static readonly HashSet<string> _bannedFieldNames = new HashSet<string>() { "__schema", "__type" };
public QueryValidationResult Validate(ISchema schema, DocumentNode queryDocument)
{
if (queryDocument.Definitions.OfType<OperationDefinitionNode>().Any(n => ContainsBannedFieldName(n.SelectionSet)) ||
queryDocument.Definitions.OfType<FragmentDefinitionNode>().Any(n => ContainsBannedFieldName(n.SelectionSet)) ||
queryDocument.Definitions.OfType<InlineFragmentNode>().Any(n => ContainsBannedFieldName(n.SelectionSet)))
{
queryDocument.WithDefinitions(Array.Empty<IDefinitionNode>());
var error = ErrorBuilder.New().SetMessage("Introspection queries are disabled").Build();
return new QueryValidationResult(error);
}
else
{
return QueryValidationResult.OK;
}
}
private bool ContainsBannedFieldName(SelectionSetNode selectionSetNode)
{
return selectionSetNode.Selections.OfType<FieldNode>().Any(f => _bannedFieldNames.Contains(f.Name.Value));
}
}
@benmccallum
Copy link
Author

Usage example in Startup.cs:

if (_env.IsProd())
{
    queryExecutionBuilder.AddValidationRule<NoIntrospectionValidationRule>();
}

@Zero3
Copy link

Zero3 commented Nov 16, 2020

@benmccallum is the last check in the if correct?

billede

@benmccallum
Copy link
Author

benmccallum commented Nov 23, 2020

Hey @Zero3, which version of HotChocolate are you using? This snippet is for v10, so we may need to adjust it for v11 slightly.

@Zero3
Copy link

Zero3 commented Nov 25, 2020

@benmccallum latest v10

@benmccallum
Copy link
Author

@Zero3, I guess that like your tooling is saying, it's not a possible scenario. I'd added it to cover inline fragments, but it does make sense that they don't have a separate "definition". Might need to handle inline fragments slightly differently...

@huysentruitw
Copy link

huysentruitw commented Feb 20, 2021

Not sure if this is the right way to do it, but I've been searching for a similar solution for v11 and came up with this:

internal class NoIntrospectionDocumentValidatorVisitor : TypeDocumentValidatorVisitor
{
    protected override ISyntaxVisitorAction Enter(FieldNode node, IDocumentValidatorContext context)
    {
        if (node.Name.Value == IntrospectionFields.Schema || node.Name.Value == IntrospectionFields.Type)
        {
            IError error = ErrorBuilder.New().SetMessage("Introspection queries are disabled").Build();
            context.Errors.Add(error);
            return new BreakSyntaxVisitorAction();
        }

        return base.Enter(node, context);
    }
}

Register as:

services.AddValidation()
    .TryAddValidationRule<NoIntrospectionDocumentValidatorVisitor>();

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