ShieldQL is a lightweight, powerful, easy-to-use JavaScript library for GraphQL that adds authentication, authorization, and query sanitization to prevent malicious queries and injection attacks.
- Authentication: ShieldQL helps you implement user authentication in your GraphQL APIs, ensuring that only authenticated users can access certain parts of your API.
- Authorization: With ShieldQL, you can define granular access controls for different types and fields in your GraphQL schema. This way, you can control what data each user can access based on their role and permissions.
- Query Sanitization: ShieldQL gives you the tools to sanitize incoming GraphQL queries to prevent potential malicious operations and protect your backend from excessively deep and excessively long queries used in denial-of-service attacks.
-
shieldqlConfig: A Javascript function that allows you to configure how sanitizeQuery will restrict queries and creates a secret for each role in the shieldql.json file, storing all of this information in the .env file and the process.env object
- Where to use: Recommended use is next to importation of ShieldQL functionality in main server file (similar to dotenv.config())
- shieldqlConfig accepts 3 params: strictShieldQL (a boolean), maxDepthShieldQL (a number), and maxLengthShieldQL (a number), which are used to configure sanitizeQuery (see sanitizeQuery for more details)
- strictShieldQL: (default false) boolean value that determines whether or not sanitizeQuery will be run on strict mode or not (strictmode allows queries to be checked against the blocklist)
- maxDepthShieldQL: (default 10) number that establishes the upper bound for the maximum depth of a graphQL query
- maxLengthShieldQL: (default 2000) number that establishes the upper bound for total characters in a graphQL query
-
loginLink: Express middleware function that authenticates the client, creates a jwt access token, and stores it as a cookie on the client's browser to authorize future graphQL queries and mutations aligned with the user's role-based permissions described in the shieldql.json file
-
Assumes that res.locals.role has already been populated with the user's role (that matches roles defined in the shieldql.json file) by a previous middleware function
-
NOTE: Access token expires after one day
-
-
validateUser: Express middleware function that verifies that the client making a graphQL query or mutation is authorized to do so through jwt verification
-
sanitizeQuery: Express middleware function users will require and invoke in their applications to sanitize graphQL queries
- sanitizeQuery works even if shieldqlConfig is never invoked, although if used without shieldqlConfig, default parameters will be used (strictmode set to false, maxDepth set to 10, maxLength set to 2000)
-
sanitize: Pure function users can require and invoke in their applications to sanitize the passed-in query.
- Accepts 4 params:
- input (required, a graphQL query type string)
- strict (a bool value, default false, that enables additional query sanitization)
- maxDepth (the maximum query nesting depth permitted, type integer)
- maxLength (maximum permitted query length, type integer) that
- Can be used as a standalone function and is also invoked within the body of the sanitizeQuery function
- Accepts 4 params:
- Make sure dotenv has been imported, that it is properly configured, and that a .env file already exists
- Ensure that the .env file is in the root directory
- Create a shieldql.json file in root directory. This file will define the roles and permissions that will be enforced throughout the user's graphQL application.
- E.g.:
{
"admin": {
"query": ["."],
"mutation": ["."]
},
"user": {
"query": ["feed", "news"]
},
"job-applicant": {
"query": ["job-description"]
}
}
-
Ensure that the appropriate graphQL role from the shieldqlConfig.js file is passed into the graphQL route through res.locals.role in order for loginLink to enforce authentication and authorization
-
A common approach to this problem is the following (see below for an example)
- Insert a middleware function preceding loginLink that queries the user database
- Extracts the graphQL role
- Stores it in res.locals.role
-
const express = require('express');
const graphqlHttp = require('express-graphql');
const shieldql = require('shieldql');
const dotenv = require('dotenv');
dotenv.config();
shieldql.shieldqlConfig(true, 15, 5000);
const app = express();
app.post(
'/graphql',
shieldql.sanitizeQuery,
populateResLocalsRole, // populateResLocalsRole is an Express Middleware function that populates res.locals.role with the user's graphql.json role
shieldql.loginLink,
shieldql.validateUser,
graphqlHttp({
schema: graphQlSchema,
rootValue: graphQlResolvers,
graphiql: true,
})
);
- NOTE: ShieldQL will NOT be able to authenticate and authorize graphQL queries unless roles are passed into loginLink through res.locals.role
npm i shieldql
While ShieldQL offers essential security features, it's crucial to keep your application and dependencies up to date to stay protected against emerging security threats. Always follow best practices for securing your GraphQL APIs.
- allowListing configuration and implementation for sanitize.js
- Amount limiting (limiting number of times a query can be called)
- make app compatible with multiple root level queries/mutations in a single request
- implement refresh tokens
- Jest/End-to-end Testing
- Add error handling for GraphQL queries
- Developing a graphical interface for configuring permissions and user roles
- Integrate a database to restrict malicious query runs.
- Typescript
We welcome contributions to ShieldQL!
Following Meta's lead with React, we have adopted the Contributor Covenant as our code of conduct for future contributors. Please read it to ensure that you understand and accept the terms and conditions described therein.
- Please submit any pull requests to the dev branch. All changes will be reviewed before merging by OSLabs and prior contributors.
- For help with existing issues, please read our GitHub issues page
- If you cannot find support in the issues page, please file a report on the same issues page.
- Suggestions and other feedback are more than welcome!
- Rodrigo S. Calderon | LinkedIn | GitHub
- Simran Kaur | LinkedIn | GitHub
- Xin Jin Qiu | LinkedIn | GitHub
- Siful Siddiki | LinkedIn | GitHub
- Joie Zhang | LinkedIn | GitHub
Inspired by graphQLock.
ShieldQL is ISC licensed.
Thank you for using ShieldQL! We hope this library helps you secure your GraphQL APIs effectively. If you encounter any issues or need further assistance, please don't hesitate to reach out to us.
Happy coding!