Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable Introspection #1240

Closed
evaldasg opened this issue Jan 24, 2018 · 4 comments
Closed

Disable Introspection #1240

evaldasg opened this issue Jan 24, 2018 · 4 comments

Comments

@evaldasg
Copy link

Is there a way to disable Introspection from the schema?

@willcosgrove
Copy link

I don't have an answer for you, but I'm curious what the reason for that would be. I'm only guessing, but I doubt there is a way to do that, since it's not part of the GraphQL spec to be able to disable introspection.

@rmosolgo
Copy link
Owner

It's not built-in, but you could implement it with a query analyzer. You could check each irep_node.definition.introspection?, and if it returns true, return an AnalysisError in final_value. Good luck, and feel free to follow up here if you have any trouble in the process!

@rickarubio
Copy link

In case anyone else was looking for a simple example, I went ahead and implemented this IntrospectionAnalyzer to block introspection queries in Rails production environments:

class IntrospectionAnalyzer
  def initial_value(query)
    {
      query: query,
      is_introspection: false
    }
  end

  def call(memo, visit_type, irep_node)
    if irep_node.definition && irep_node.definition.introspection?
      memo[:is_introspection] = true
    end

    memo
  end

  def final_value(memo)
    if memo[:is_introspection] && Rails.env.production?
      unauthorized_introspection_query_error
    else
      memo
    end
  end

  private

  def unauthorized_introspection_query_error
    GraphQL::AnalysisError.new(
      'Introspection queries are not allowed in production.'
    )
  end
end

Schema:

class ApiSchema < GraphQL::Schema
  use GraphQL::Tracing::NewRelicTracing
  use GraphQL::Batch
  max_depth 8

  mutation Types::Mutation
  query Types::Query

  query_analyzer IntrospectionAnalyzer.new
end

Hope this helps, any improvements are welcome.

@amkisko
Copy link

amkisko commented Jan 28, 2020

Security tips 👍

query_analyzer.rb

class QueryAnalyzer < GraphQL::Analysis::AST::Analyzer
  QUERY_ALLOWED_DEPTH = 5

  def initialize(query)
    super
    @max_depth = 0
    @current_depth = 0
  end

  def on_enter_field(node, parent, visitor)
    @current_depth += 1
  end

  def on_leave_field(node, parent, visitor)
    # NOTE: https://graphql-ruby.org/schema/introspection
    introspection_field_names = %w[__schema __type]
    field_def = visitor.field_definition
    if field_def.introspection? && introspection_field_names.include?(field_def.graphql_name)
      @introspection_present = true
    end

    # TODO: Check depth per field

    if @max_depth < @current_depth
      @max_depth = @current_depth
    end
    @current_depth -= 1
  end

  def result
    if @introspection_present
      GraphQL::AnalysisError.new("Not authorized to query schema internals") unless authorized?
    elsif depth_exceeded?
      GraphQL::AnalysisError.new("Query depth #{@max_depth} exceeds allowed #{query_allowed_depth}")
    end
  end

  private def authorized?
    Rails.env.development? ||
    ENV["GRAPHQL_SCHEMA_PASSWORD"].present? &&
    ENV["GRAPHQL_SCHEMA_PASSWORD"] == query.context[:request].headers["Schema-Token"]
  end

  private def depth_exceeded?
    @max_depth > query_allowed_depth
  end

  private def query_allowed_depth
    QUERY_ALLOWED_DEPTH
  end
end

api_schema.rb

class ApiSchema < GraphQL::Schema
  # NOTE: Do not enable `max_depth`, use custom analyser
  # max_depth 8

  mutation(Types::MutationType)
  query(Types::QueryType)

  use(GraphQL::Analysis::AST)
  query_analyzer(QueryAnalyzer)
end

Schema dump using apollo service

apollo service:download --endpoint=https://my-api-endpoint/graphql --header="Schema-Token: XXX"

Query sample

query {
  __schema {
    queryType {
      fields {
        name
        type {
          kind
          ofType {
            kind
            name
          }
        }
      }
    }
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants