Understanding API Security with GraphQL
Security is a critical aspect of API development, which requires focused attention from design, to implementation, to testing, to operations. The time, effort, and investment needed to secure APIs is often shortchanged, despite security’s importance and prevalence throughout the API development lifecycle. Unfortunately, shortchanging the focus on security leads to insecure APIs reaching users (and adversaries).
API security is expansive. A number of the OWASP Top 10 are relevant to API security, and we'll cover aspects of API security that relate to these six items:
- Broken Access Control
- Insecure Design
- Security Misconfiguration
- Identification and Authentication Failures
- Software and Data Integrity Failures
API security often touches on a few key areas:
- Authentication – Identifying the client interacting with an API
- Authorization – Permitting an identified client to specific API operations
- Data Access Control – Permitting an identified and authorized client to specific data records or data fields
Without strong authentication, authorization and access control based on a client's identity isn't possible. Without strong authorization, clients may be able to access API operations and data to which they aren't permitted. And without rich data access controls, a client authorized to use an API operation may have overly permissive access to view or modify the data accessible through an API.
Each of these areas of API security is fraught with potential challenges, but high-quality security practices can address most.
Credentials (e.g., passwords) and authentication protocol (e.g., single- vs. multi-factor) are two common sources of the "identification and authentication failures" referenced by OWASP. Some less obvious challenges are managing identity or session tokens appropriately (e.g., reasonable expiration times) and fully validating certificates (e.g., hostname matching).
Incorrectly configuring authorization policies, or omitting authorization policies entirely, are two common mistakes that lead to "broken access control", as referenced by OWASP. Another mistake is creating design or implementation flaws that allow an elevation of privilege to an authenticated, but not necessarily authorized, user. This category of broken access control can be thought of as authorization failures.
Another category of broken access control can be thought of as data access control failures. These failures stem from poor design, poor implementation, or, more basically, incorrect assumptions. For example, assuming that any user authorized with access to a piece of data should also have permission to update or delete that piece of data is likely untrue to start with — or will quickly become untrue as the number of users increases.
These are just a handful of common vulnerabilities related to a subset of API security. Maintaining highly secure APIs can be a daunting task.
GraphQL is a query language for APIs. Like most APIs, a GraphQL endpoint accepts client requests over HTTP and makes use of what the HTTP spec affords for providing security-related information as part of a request. In addition, GraphQL itself provides some additional design and implementation benefits that are helpful when securing APIs.
Authentication is orthogonal to GraphQL. In fact, if you search the GraphQL specification for the word "authentication" you'll find 0 results. But for a GraphQL API to be secure, something must authenticate each client prior to the client making an API request. Most likely, that something is a separate Identity Provider (IdP). Generally, upon verifying client credentials through whatever authentication mechanism is provided, the client will receive some form of proof authentication was successful.
This means that GraphQL APIs can only be as secure as the IdP servicing its GraphQL API clients. This also means that time and energy focused on correctly configuring and managing the IdP will help minimize these OWASP threats:
One popular proof of authentication is a JSON Web Token (JWT). JWTs contain a rich set of information, within the JWT's claim set, as shown in Figure 1.
Figure 1 - A decoded JWT
The encoded JWT on the left is one example of information provided by an IdP upon client authentication that can then be sent in subsequent requests to a GraphQL API.
Authorization is also orthogonal to GraphQL. As with "authentication", if you search the GraphQL specification for the word "authorization" you'll find 0 results. However, GraphQL's frequent reliance on HTTP as its transfer protocol brings authorization to the forefront.
The HTTP specification provides a means — via the "Authorization" header — for a GraphQL client to send its proof of authentication (obtained from an IdP) to a GraphQL API. Whether that proof is a JWT or another agreed upon token type that will allow the GraphQL API to make an authorization decision, the Authorization header is the typical means to send that information from client to server. A "Bearer" prefix is often included in the value to denote the token came from another system, as shown in Figure 2.
Figure 2 - An authorization header populated with a JWT
The Authorization header, the Bearer prefix, and the JWT (in this example) are all part of the request sent from the API client to the GraphQL API server. Devoting cycles to designing and implementing a comprehensive authorization policy, and leveraging the HTTP and the Authorization as inputs to the policy implementation, helps to address these OWASP threats:
GraphQL relies heavily on the notion of a schema. The schema defines the types, directives, and operations it supports. This allows for a very rich set of tooling to be built around the GraphQL ecosystem, heavily based on the existence of a well-defined schema.
One of the benefits of the schema and the types it defines is the ability to build data access controls into the schema itself. By doing so, implementations of the GraphQL API can leverage those definitions to make data access control decisions during operation execution. For example, value resolution can be the point at which an identified, authorized API client is allowed or restricted from a specific field referenced. In other words, the schema can include types required for complex data access control and the GraphQL implementation can use those definitions to mechanize data access control.
Figure 3 shows what data access controls represented in a GraphQL schema might look like.
Figure 3 - A GraphQL mutation with schema-compliant access controls
aclInput and its nested types are part of the GraphQL schema. The mutation shown includes data access controls (represented as an access control list (ACL)) embedded in the
Loan being created. The combinations of
path are being used to define coarse and fine grained access controls for the
Loan entity. For example:
- Coarse Grained Access Controls –** **Used to permit or deny access to the entity itself — in this case a
Loan. The first ACL entry permits the LenderNode read and write access to the Loan, across all fields.
- Fine Grained Access Controls –** **Used to permit or deny access to a subset of fields within the entity. The last ACL entry permits the ServicerNode read and write access, but only to the
delinquencyStatusfield of the Loan. Otherwise, the second ACL entry applies, which permits only read access to the fields of Loan.
By modeling data access controls as part of a GraphQL schema and by implementing data access protections as part of the GraphQL API implementation, a robust set of protections can be applied. This approach addresses:
Maintaining strong authentication, authorization, and data access controls for your GraphQL APIs can be a challenge. Even if done well, a number of the OWASP threats initially mentioned are still not addressed:
One of the benefits of adopting a fully-managed platform like Vendia Share, that offers and secures GraphQL APIs, is that the remaining OWASP threats are addressed for you.
Injection is prevented through server-side validation and reliance on high-quality libraries. Further, because of Vendia's use of serverless technology from leading Cloud Service Providers (CSPs), security issues found in popular third-party libraries are quickly addressed to limit exposure and potential impact.
As OWASP notes, "a secure design can still have implementation defects leading to vulnerabilities that may be exploited. An insecure design cannot be fixed by a perfect implementation." Since Vendia covers the design _and _implementation of authorization and data access controls to GraphQL APIs, covering its control plane and data plane, the risk of security issues from either are diminished.
Vendia heavily leverages automation as part of its business blockchain provisioning process. Through a concerted, repeatable application security configuration process, systems are at lower risk than with DIY or manual approaches. Similarly, as you make GraphQL APIs "data aware", a new set of potential security risks emerge. Fortunately, relying on a data model that is inherently "security aware" addresses those risks in a well-documented and well-tested fashion.
Securing GraphQL APIs across all potential security risk areas requires significant time and effort. It's certainly possible to do so on an individual team level. But, often, scarce development cycles are borrowed (for better or for worse, but usually for worse) to create the next "killer feature" for a product. In addition, because APIs often cross organizational boundaries, following good security practices becomes a responsibility of your organization and your partners' organizations.
When you can rely on a real-time data sharing platform that offers a secure GraphQL interface, many of those potential security risks are addressed. Sign up for a 1-week Proof of Concept (POC) to see how Vendia's approach to secure data sharing using GraphQL APIs can help your organization.