diff --git a/docs/security/index.rst b/docs/security/index.rst index 6d2e1e38..cb7029b4 100644 --- a/docs/security/index.rst +++ b/docs/security/index.rst @@ -2,14 +2,23 @@ Security consideration ====================== +In this section, we will discuss the most common security risks and how to mitigate them. + As GraphQL is a query language, it allows users to use a wider pannel of inputs than traditional REST APIs. Due to this feature, GraphQL APIs are inherently prone to various security risks, but they can be reduced by taking appropriate precautions. Neglecting them can expose the API to vulnerabilities like credential leakage or denial of service attacks. -In this section, we will discuss the most common security risks and how to mitigate them. +As Graphene is only an engine to run GraphQL queries, it is not responsible for the HTTP layer and this security must be +handled by the web framework you are using. For example, if you are using Django-GraphQL, you may also want to check out +the `Django documentation`_ on how to secure your API. .. toctree:: - :maxdepth: 2 + :maxdepth: 1 + maxdepth queryvalidation + +We have seen the most efficient way to secure your GraphQL API. + +.. _Django documentation: https://docs.djangoproject.com/en/4.1/topics/security/ diff --git a/docs/security/maxdepth.rst b/docs/security/maxdepth.rst new file mode 100644 index 00000000..b3b053cf --- /dev/null +++ b/docs/security/maxdepth.rst @@ -0,0 +1,75 @@ +Depth limit Validator +===================== + +By default, GraphQL queries can be arbitrarily deep. This can lead to a denial of service attack where a client can send +a deeply nested query that will take a long time to execute. For that, you must find a cycle in the graph and iterate +over. + +Example +------- + +For example a simple app that allows you to find your friends and their friends can lead to this query : + +.. code:: graphql + + query { + me { + friends { + friends { + friends { + friends { + ... + # dumping the whole database + } + } + } + } + } + } + +This is not a common use case, your dev team will not do that in the first place. But as your endpoint is publicly +available, you can't be sure that someone will not try to do so. + +Remediation +----------- + +Graphene provides a depth limit validator that can be used to prevent this kind of attack. It can be configured to limit +the depth of all the queries or only some specific ones. The only required argument is ``max_depth`` which is the +maximum allowed depth for any operation in a GraphQL document. The other optional parameters are the following ones : + +- ``ignore``: A list of patterns that, if matched stops recursive depth checking. It can be one of the following : + - ``Callable : (dict[str, int]) -> bool``: A function that receives the current operation and returns a boolean. + - ``Pattern``: A compiled regex pattern that is matched against the operation name. + - ``str``: An operation name. +- ``callback: (dict[str, int]) -> None`` Called each time validation runs. Receives an Object which is a map of the depths for each operation. + +Usage +----- + +Here is an example of how you would implement depth-limiting on your schema. + +.. code:: python + + from graphql import validate, parse + from graphene import ObjectType, Schema, String + from graphene.validation import depth_limit_validator + + + class MyQuery(ObjectType): + name = String(required=True) + + + schema = Schema(query=MyQuery) + + # queries which have a depth more than 20 + # will not be executed. + + validation_errors = validate( + schema=schema.graphql_schema, + document_ast=parse('THE QUERY'), + rules=( + depth_limit_validator( + max_depth=20 + ), + ) + ) diff --git a/docs/security/queryvalidation.rst b/docs/security/queryvalidation.rst index 02e29a35..d0d174c9 100644 --- a/docs/security/queryvalidation.rst +++ b/docs/security/queryvalidation.rst @@ -7,47 +7,6 @@ makes query fail with "Cannot query field on type" error if it doesn't. To help with common use cases, graphene provides a few validation rules out of the box. -Depth limit Validator ---------------------- -The depth limit validator helps to prevent execution of malicious -queries. It takes in the following arguments. - -- ``max_depth`` is the maximum allowed depth for any operation in a GraphQL document. -- ``ignore`` Stops recursive depth checking based on a field name. Either a string or regexp to match the name, or a function that returns a boolean -- ``callback`` Called each time validation runs. Receives an Object which is a map of the depths for each operation. - -Usage ------ - -Here is how you would implement depth-limiting on your schema. - -.. code:: python - - from graphql import validate, parse - from graphene import ObjectType, Schema, String - from graphene.validation import depth_limit_validator - - - class MyQuery(ObjectType): - name = String(required=True) - - - schema = Schema(query=MyQuery) - - # queries which have a depth more than 20 - # will not be executed. - - validation_errors = validate( - schema=schema.graphql_schema, - document_ast=parse('THE QUERY'), - rules=( - depth_limit_validator( - max_depth=20 - ), - ) - ) - - Disable Introspection --------------------- the disable introspection validation rule ensures that your schema cannot be introspected.