⚙️

graphql-rubyでIntrospection機能(スキーマ)を無効にして悪用されないようにする

2023/10/29に公開

はじめに

先日公開された記事「開発者フレンドリーは“ハッカーにとってもフレンドリー” 「GraphQL」の機能を使った悪用事例と究極の対策」を拝見して、graphql-rubyでIntrospection機能(スキーマ)を無効にできるか確認してみました。

https://logmi.jp/tech/articles/329491

GraphQL Introspectionについて

https://graphql.org/learn/introspection/
https://graphql-ruby.org/schema/introspection

GraphQLでは、Introspection機能としてどのようなQueryやMutationなどが使用できるかスキーマとして確認できます。
graphql-rubyはスキーマファーストではなくコードファーストなので、実装した内容からIntrospection機能でスキーマを取得できます。
このスキーマを共有することで開発が容易になり非常に有用です。

なぜIntrospection機能を無効にするのか

Introspection機能が有効な場合、だれでもスキーマが取得できます。
そのため、どのようなQueryやMutationなど公開するつもりはなくても公開された状態になり、悪用される可能性もあります。
一般公開を目的としたGraphQL APIであれば非常に有用ですが、一般公開してない場合はIntrospection機能を無効にしたほうがよさそうです。

graphql-rubyでIntrospection機能を無効にする

graphql-rubyを実装したら以下のようなGraphQL::Schemaを継承したクラスがあると思います。
そこでdisable_introspection_entry_pointsを指定すると、Introspection機能を無効にできます。

詳しくはこちらの「Disabling Introspection」を参照ください。
https://graphql-ruby.org/schema/introspection#disabling-introspection

コード例(productionでIntrospection機能を無効)

class MySchema < GraphQL::Schema
  disable_introspection_entry_points if Rails.env.production?
end

Introspection機能が有効な状態でスキーマを取得

$ get-graphql-schema http://localhost:3000/graphql
"""
Requires that exactly one field must be supplied and that field must not be `null`.
"""
directive @oneOf on INPUT_OBJECT

"""Exposes a URL that specifies the behavior of this scalar."""
directive @specifiedBy(
  """The URL that specifies the behavior of this scalar."""
  url: String!
) on SCALAR

type Mutation {
  """An example field added by the generator"""
  testField: String!
}

type Query {
  """An example field added by the generator"""
  testField: String!
}

Introspection機能が無効な状態でスキーマを取得

$ get-graphql-schema http://localhost:3000/graphql
Error: [
  {
    "message": "Field '__schema' doesn't exist on type 'Query'",
    "locations": [
      {
        "line": 3,
        "column": 7
      }
    ],
    "path": [
      "query IntrospectionQuery",
      "__schema"
    ],
    "extensions": {
      "code": "undefinedField",
      "typeName": "Query",
      "fieldName": "__schema"
    }
  },
  {
    "message": "Fragment FullType was defined, but not used",
    "locations": [
      {
        "line": 21,
        "column": 5
      }
    ],
    "path": [
      "fragment FullType"
    ],
    "extensions": {
      "code": "useAndDefineFragment",
      "fragmentName": "FullType"
    }
  }
]

まとめ

GraphQL Introspection機能はスキーマを取得できるので開発を容易になり非常に有用です。
ただ一般公開するつもりはなくても公開されている可能性があるので、無効になっているか確認してみてはいかがでしょうか?

Discussion