Skip to content

Latest commit

 

History

History
150 lines (99 loc) · 10.1 KB

section_10_information_assurance.adoc

File metadata and controls

150 lines (99 loc) · 10.1 KB

Information Assurance

OpenAPI

OpenAPI provides two constructs to describe security controls; Security Scheme Objects, and Security Requirements.

Security Schemes

A Security Scheme Object provides a detailed description of a type of security control. They do not identify where in the API the control should be applied. Currently the OpenAPI specification supports the following Security Schemes:

  • HTTP authentication,

  • API key (either as a header or as a query parameter),

  • OAuth2’s common flows (implicit, password, application and access code) as defined in RFC6749, and

  • OpenID Connect Discovery.

Support for client-side PKI certificates is planned for version 3.1.

Security Scheme Objects reside within the Components Object in the OAS document root. Each Security Scheme Object has an associated key. These keys allow a Security Scheme Object to be referenced from elsewhere in the OAS document. The keys also allow for multiple flavors of a scheme type. For example, the keys "Bobs_API" and "Marys_API" could reference two Schemes of type API Key that have different implementations (ex. header vs. query).

Security Requirements

Security Requirements Objects are used to identify where in the API a Security Scheme (or schemes) should be applied. These objects consist of a set of key-value pairs. Each key should correspond to a key for a Security Scheme Object. The Security Requirement is satisfied when all of the Security Schemes (identified by the keys) are satisfied. The associated values provide additional information specific to this Security Requirement. Currently values are only defined for oauth2 and openIDConnect schemes.

Security Requirements can be specified at two levels:

  • Root: These Security Requirements apply to the whole document unless over-ridden.

  • Operations: These Security Requirements apply to a single operation. These requirements override any requirements specified at the root level.

Rules for Applicability:

  1. When more than one Security Requirement is provided, only one has to be satisfied.

  2. A Security Requirement may map to more than one Security Scheme. In that case, all of the Schemes must be satisfied.

  3. An empty Security Requirement object is valid. This indicates that there are no security controls.

OpenAPI Security Issues:

The following issues have been taken to the OpenAPI Technical Steering Committee for resolution.

  1. There is no way to directly associate a Security Requirement with a Server Object. This can lead to problems. Consider the case where an operation contains two Server Objects. These two servers each implement a different form of authentication. There are Security Requirement objects for each form of authentication. How does the client know which control goes with which server? The answer at this time is that they don’t.

  2. The scope of a Security Requirement is ambiguous in regards to resources. If the result of an operation is a document which contains links to other documents, does the Security Requirement apply to the links as well? Under the current version of OpenAPI we cannot tell for sure.

Our recommended way forward is to be aware of security constraints when designing your API.

  1. If two servers have different authentication methods, then put them on different paths.

  2. Organize your resources so that if a user can access one resource, then they can access all linked resources as well.

  3. Use the appropriate HTTP status codes and messages. If the client cannot authenticate, let them know what is missing.

Access Control

The OpenAPI document provides clients with the information they need to identify themselves to the API and to prove (authenticate) that identity. But why would the API need this information? One reason is to make sure that the resources managed by the API are only provided to clients who are authorized to receive them. Access Controls are the Security Controls which assure that only authorized parties can access each API resource.

Access Controls are an implementation detail which is usually not exposed to the user. However, they do have an impact on the behavior of the API. The following sections discuss some of the ways which the choice of access control can affect the client.

Bootstrap

Many users will come to an API with no a-priori knowledge of its' configuration or client requirements. The OpenAPI document provides them with the information they need to use the API. But what if some of the information in the OpenAPI document is restricted? Clients need the information from the OAS document in order to access the OAS document. This is known as a Catch 22.

The OpenAPI specification does not restrict an API to just one OAS document. So one approach open is to construct an open OAS document with only the information necessary to access the restricted OAS document.

An OAS document is required to have the following content:

Table 1. Required OpenAPI Fields
Field Description

openapi

The version of OpenAPI used in this document

info/title

The title of this API

info/version

The version of this OAS document

paths/

An empty paths value is valid

So the following is a valid OAS document:

openapi: 3.0.1
info:
  title: A sample minimal OAS document
  version: 1.0
path:

A bootstrap OAS document would add a bit more such as:

  1. A path to the restricted OAS document

  2. The Security requirements to access the restricted OAS document

  3. The Server where the restricted OAS document resides

The following example "bootstrap" OAS document tells the client that the full OpenAPI document can be retrieved from https://secure.example.org/api and that it is protected by OAuth.

openapi: 3.0.1
servers:
  - url: 'https://secure.example.org/'
    description: Restricted access server
info:
  version: "1.0.0"
  title: A bootstrap OAS document
  description: >-
    This is an example of using OAuth2 Password Flow in a specification to describe security to your API.
security:
  - password:
    - read
paths:
  /api:
    get:
      summary: The protected OAS document
      responses:
        '200':
          description: OK
components:
  schemas: {}
  securitySchemes:
    password:
      type: oauth2
      flows:
        password:
          tokenUrl: 'http://example.com/oauth/token'
          scopes:
            read: allows reading resources

Discrete Resources

The most common means of access control is to restrict access to a discrete resource. The UNIX file system, for example, can restrict a user’s ability to read, write, execute, or delete a file. Similar file system based discretionary access controls are supported by most platforms. It’s a simple matter for an API to control access to its resources through this platform capability. For example, a user issues a PUT request on a resource. If the file system indicates that resource is read-only, then the user will receive a 403 (forbidden) response.

Complications arise when a request involves more than one resource. For example, a GET request against a collection (such as a file system directory) could return all of the resources within that collection. Assuming that the user has read access to all of the resources. If some, but not all, of the resources are not readable, then the API designer must decide to throw a 403 or return just those resources which are readable. Once decided, this behavior should be consistent across the API.

An more challenging case is when a user has access to only a part of a resource. In the bootstrap discussion above, the unauthenticated user only has access to a small portion of the OpenAPI document. Since each resource is discrete, there is no way to return just part of a resource. Therefore, we need two (or more) copies of each resource with protected content.

An API developer has to decide how they are going to handle multiple copies of the same resource. Three approaches that can be used are:

  1. Use different Servers based on security restrictions.

  2. Use different resource names based on the security restrictions on the resource.

  3. Use different paths based on security restrictions.

Different Servers are a simple solution as long as the security restrictions can be expressed as a small number of categories. It is not difficult define three servers hosting secret, sensitive, and open data respectively. On the other hand, this would not work well if each user has user-specific privileges.

Note: that OpenAPI does not associate Security Requirements with Server Objects. So the security restrictions on each server should be included in the description.

Different Resource Names is another simple approach. Like Different Servers, this works best if the security restrictions can be expressed as a small number of categories. Resource names have the advantage that the user can decide if they will be able to access the resource prior to issuing a request. In addition, since Security Requirements can be assigned at the Operation level, users will also know what form of authentication is required to access the resource.

Different Paths is a more generalized version of the Different Resources approach. Its' major advantage is that it supports user-specific access controls. For example, the path /collections/{uid}/buildings/items would return the "buildings" features which user {uid} can access.

Dynamic Resources

Consider a relational database (RDMS) with row-based access control. Now package that database behind an API. The resources exposed through the API are generated at run time. Upon receiving a request, the API will select those rows which the user is authorized to access, build the response, and return it to the user. This approach takes the API design completely out of the picture. Servers, paths, and resource names are the same for the highly privileged and the unprivileged users. All that changes is the content of the resource returned.

There is an important property to this approach which must be considered. Different users, using the same URL, will get different results. So a URL cannot be used as a unique identifier for the resource.