Closing the loop on API security configuration

API security is top-of-mind for many organisations. We can’t go a week without hearing about an API vulnerability. While API gateways help protect our APIs, if they are misconfigured, or an API is deployed without any authorisation rules assigned to it, the APIs may be easily compromised.

In this article, we will explore some recent API gateway misconfigurations and then look at ways to automate our deployment process to mitigate these issues.

Case studies in API misconfiguration

API security configuration is an essential step in the deployment process. When it is implemented with manual steps, it can lead to disaster. Let’s look at three case studies that illustrate this concern.

T-Mobile

In late 2022, personal data was accessed via a T-Mobile API. The compromised API has been described as lacking proper authorisation settings configured on the API gateway when deployed. An API incorrectly configured resulted in the leaking of the personal data of 37 million customers.

Optus

Around the same time, Optus released details about a data breach that exposed 10 million customer accounts. Like T-Mobile, this was an error related to security configuration. In this case, it was an API that did not require any credentials. The article details some of the problems that led to the breach:

“In the instance where a public API endpoint did not require authentication, anyone on the internet with knowledge of that endpoint URL could use it,” said the senior manager of cyber security consulting for Moss Adams, Corey J Ball. “If that endpoint was used to access customer data, then anyone on the internet could have used that endpoint to gather customer data…The attacker likely scripted the process to repeat requests from the endpoint until they had collected millions of instances of personally identifiable information.”

Yet another example of how inconsistent or missing API security configurations led to malicious use of an API. 

Fintech company

Finally, a few years ago, a fintech company requested a third-party company to audit their systems. It was discovered that dozens of APIs were deployed without authorisation controls. It was later determined that the APIs were not using the API gateway. Thankfully, these issues were resolved, and no malicious activity was discovered due to this lack of security around some of their internal APIs.

In the last case, the root cause was determined to be an exception granted to the team that allowed them to skip their standard API governance processes. Since then, upper management has been educated about proper API security reviews.

How could these situations have been avoided? Automating proper API security configuration throughout all deployment environments. 

Automate your API configuration

Your organisation must ensure that your APIs offer proper security controls to prevent unauthorised access. APIs deployed without an API gateway expose a surface area ready for malicious activity. APIs deployed with an improperly configured API gateway may expose sensitive data.

As we learned from the previous case studies, misconfiguration is often the root cause of unauthorised API access. Automation can prevent this by applying the proper authorisation rules when the API is deployed.

The easiest way to start protecting REST-based APIs is to use the built-in security declarations using the OpenAPI Specification. We can then further customise our automation using OpenAPI extensions. 

Capturing authorisation details in the OpenAPI Specification (OAS)

Let’s take a simple example of an API that uses a JWT-based token format, requiring a request header in the format: `Authorisation: Bearer <jwt token>’.

In this case, we first define an entry in the  `components/securitySchemes` section of our OpenAPI Specification 3.x document:

```

components:

  securitySchemes:

    BearerAuth:

      type: http

      scheme: bearer

      bearerFormat: JWT

```

For each protected operation, we reference it by name in the `security` declaration for that operation. Here is an example derived from the Swagger Petstore:

```

  /pet/{petId}:

    get:

      tags:

        - pet

      summary: Find pet by ID

      description: Returns a single pet

      operationId: getPetById

      produces:

        - application/json

        - application/xml

      parameters:

        - name: petId

          in: path

          description: ID of pet to return

          required: true

          type: integer

          format: int64

      responses:

        '200':

          description: successful operation

          schema:

            $ref: '#/definitions/Pet'

        '400':

          description: Invalid ID supplied

        '404':

          description: Pet not found

      security:

        - BearerAuth: []

```

We can then leverage the API gateway’s OpenAPI support for deployment configuration or create a deployment script to apply the necessary authorisation requirement for the API operation based on the OpenAPI Specification. As long as our operations each reference the `BearerAuth` security declaration, our deployment automation will require a bearer token to be present in the request to access the API operation.

If we need a bit more granular access control, we can instead use OAuth2 scopes. In this case, we need to adjust the `components/securitySchemes` section of our OpenAPI Specification 3.x document:

```

components:

  securitySchemes:

    OAuth2:

      type: oauth2

      flows:

        authorizationCode:

          authorizationUrl: https://example.com/oauth/authorize

          tokenUrl: https://example.com/oauth/token

          scopes:

            pets:read: Grants read access for the pets resource

            pets:write: Grants write access for the pets resource

            pets:admin: Grants access to admin operations for the pets resource

```

Our API operation would instead reference this new `OAuth2` security scheme along with the scope(s) required to be be authorised to call the operation:

```

  /pet/{petId}:

    get:

      tags:

        - pet

      summary: Find pet by ID

      description: Returns a single pet

      operationId: getPetById

      produces:

        - application/json

        - application/xml

      parameters:

        - name: petId

          in: path

          description: ID of pet to return

          required: true

          type: integer

          format: int64

      responses:

        '200':

          description: successful operation

          schema:

            $ref: '#/definitions/Pet'

        '400':

          description: Invalid ID supplied

        '404':

          description: Pet not found

      security:

        - OAuth2: ['pets:read', 'pets:admin']

```

Enforcing API security declarations

Looks good so far. However, what happens if our OpenAPI document doesn’t declare any security rules? Wouldn’t our API gateway let through all traffic?

Not if we use a linter, such as Spectral, to check the OpenAPI specification for a `security` declaration for each operation. We can even craft a rule to verify that the declaration matches an existing `securitySchemes` entry and that it matches one of the accepted authorization types.

Once we have defined the linter rules we desire, we make this part of the deployment process. The linter rules we have defined are executed against the OpenAPI document. If we miss a `security` declaration for one of our operations, our deployment process halts with the error. This requires proper configuration to deploy our API to our gateway, resulting in the unauthorised API usage outlined in our case studies earlier in this article. 

Leveraging OpenAPI extensions for improved configuration

An additional customisation I’ve seen in some organisations is the use of OpenAPI extensions for additional deployment control. Deployment details such as routing rules and policy names can be specified to help drive the automation scripts.

For example:

```

  /pet/{petId}:

    get:

      tags:

        - pet

      summary: Find pet by ID

      description: Returns a single pet

      operationId: getPetById

      produces:

        - application/json

        - application/xml

      parameters:

        - name: petId

          in: path

          description: ID of pet to return

          required: true

          type: integer

          format: int64

      responses:

        '200':

          description: successful operation

          schema:

            $ref: '#/definitions/Pet'

        '400':

          description: Invalid ID supplied

        '404':

          description: Pet not found

      security:

        - OAuth2: ['pets:read', 'pets:admin']

- x-security-policy: 'my-pet-policy'

  x-route-service: petService-1.0.6

“`

Notice the `x-security-policy` extension under security, which may be required for some API gateways to map the API operation to a policy by name or UUID. Likewise, the `x-route-service` extension could configure the DNS name the API gateway will use to route inbound requests for this operation.

Wrap-up

This article presented recent case studies that detail API gateway misconfigurations or missing configurations that allowed APIs to be used for malicious purposes. We then looked at how we could leverage some of the built-in capabilities of the OpenAPI Specification to define our authorisation rules for our APIs. When combined with linters that check for authorisation rules, we can only allow APIs to be deployed with proper restrictions.

We examined how the OpenAPI extensions capability can further define our security policies and routing rules as part of an automated deployment process. Consider using this or a similar technique to automate the deployment of your APIs to your gateway. This will ensure an authorisation policy is implemented in your automated deployment pipeline.