Tools

Swagger

Cohesion can help you perform security tests on apps and services defined with Swagger 2.0 OpenAPI specifications. This is a two-step process and requires some preparation to get started.

What is Swagger

Swagger is a structured document, typically formatted as JSON or YAML, which describes a web application or a service. The document itself defines several aspects such as the endpoint hostname, base path, all service paths, and supported HTTP methods. Swagger can also define the required and optional parameters and how they fit in the body, headers, cookie and the URL query.

Swagger can really help during the development process as the client API can be dynamically generated from the spec which is more consistent and a lot less error-prone as supposed to writing it by hand.

Security Testing

Swagger specification documents can be used to automatically create test cases with some caveats. For example, swagger specs can be very broad, it is not always possible to fully automate a service or an app without some manual effort. For example, a service may define a number parameters, and although technically any number will be a valid input, the context of what that number means is completely lost. A number can represent an id, date and pretty much any arbitrary information.

Thus, in order to create some quality security tests with Cohesion, it is important to provide some context. If your Swagger file is very complete, such as that there are default values, Cohesion will be able to do all the work by itself.

Step 1

The first step is to run the Swagger spec through Cohesion and generate all the base requests which will be used for testing:

$ cohesion swagger api-spec.json spec/

The first parameter is the actual swagger file. The second parameter is the folder where the base requests will be generated.

$ ls -la spec/
-rw-r--r--   1 _  staff    91  9 May 20:39 DELETE-boutique-api-store-{id}-00.request
-rw-r--r--   1 _  staff   135  9 May 20:39 GET-boutique-api-store-00.request
-rw-r--r--   1 _  staff   135  9 May 20:39 GET-boutique-api-store-01.request
-rw-r--r--   1 _  staff   128  9 May 20:39 GET-boutique-api-store-total-00.request
-rw-r--r--   1 _  staff    88  9 May 20:39 GET-boutique-api-store-{id}-00.request
-rw-r--r--   1 _  staff   443  9 May 20:39 POST-boutique-api-store-00.request
-rw-r--r--   1 _  staff   448  9 May 20:39 POST-boutique-api-store-01.request

If we open one of these files, we are presented with a full HTTP request, which is almost ready to be used in the next step.

$ cat spec/POST-boutique-api-store-00.request
POST https://target/boutique-api-/store HTTP/1.1
Content-Type: application/json


{
  "name": "string",
  "tags": [],
  "description": "",
  "availableAfter": 1,
  "notAvailableAfter": 1
}

Although this request will be sufficient to pass all requirements, it will probably not work as expected as at the very least we need to provide proper timestamps for both "availableAfter" and "notAvailableAfter" parameters.

Step 2

This step is the easy part. All is left to do is to fuzz either all or some of the generated requests. For example:

$ cohesion fuzzer spec/POST-boutique-api-store-00.request

It is also possible to fuzz all requests. For example:

$ ls spec/ | while read R; do cohesion fuzzer spec/$R; done

Additional options can be provided to make this line more useful as per the Shell Scripting documentation.

Authenticated Testing

When testing APIs there is almost always a need to authenticate. The authentication can be provided statically as part of the request files, or dynamically as a command-line option or a function.

Custom headers can be specified with the "--header" command line flag. You can use that flag to set the Authorization header. For example:

$ cohesion fuzzer --header="Authorization: Bearer jwt" api-request.txt

Consult with the usage documentation or the common options manual for more information.

Additionally, you can use extension functions. Functions can dynamically augment the request using custom logic and thus provides a flexible mechanism that covers all possible use-cases.

Consider the following function which fetching an authentication token and sets the Authorization header before testing.

const url = require('url')
const https = require('https')


module.exports = (request) => {
  return new Promise((resolve, reject) => {
    const options = url.parse('http://auth/token')


    const req = https.request(options, (res) => {
      const chunks = []


      res.on('error', reject)


      res.on('data', (data) => {
        chunks.push(data)
      })


      res.on('end', () => {
        const { token } = JSON.parse(Buffer.concat(chunks).toString())


        if (!request.headers) {
          request.headers = {}
        }


        request.headers['Authorization'] = `Bearer ${token}`


        resolve(request)
      })
    })


    req.on('error', reject)
  })
}

Use the function with the following command:

$ cohesion fuzzer --target-func=auth.func 01.request

Consult with the exetension functions manual for more information.

Previous
Other Commands