OpenAPI Configuration

Looking for legacy options? Check the Legacy Configuration section below.

The OpenAPI Specification (AKA Swagger) is an industry-adopted standard for describing RESTful interfaces, which HawkScan can use to deliver a faster, more thorough scan.

HawkScan will use the contents of a provided OpenAPI spec to improve the quality of the scan by:

  • Pre-seeding the sitemap using the routes defined in the OpenAPI spec. This can be used to complement any crawled routes, or can be used instead of app spidering altogether.
  • Using defined inputs to routes in the the spec to inform how to communicate with the web application and gather clues on how to better attack endpoints.

HawkScan can work with OpenAPI definitions as separate files or defined inline via the stackhawk.yaml. Please note that the inline spec cannot exceed 4MB!

Creating an OpenAPI Spec

A project may not have an OpenAPI spec because its API is for internal application use only. We have found that even for internal APIs it is useful to have an OpenAPI spec for integration not only with HawkScan, but a wide variety of tools and technologies. OpenAPI definitions do not have to be publicly published for internal APIs, they can be for limited to internal use only.

If your project doesn’t already have an OpenAPI file for use with HawkScan, there are multiple ways to get started.

The OpenAPI has v2 and v3 versioned implementations. HawkScan supports both versions.

Example OpenAPI Spec File

A typical OpenAPI spec can be defined in either YAML or JSON format (e.g. openapi.yml). A YAML version might look like the following:

swagger: "2.0"
info:
  title: Sample Example Web API
  description: Web API description in _markdown_.
  version: 1.0.0
host: api.example.com
basePath: /v1
schemes:
  - https
paths:
  /users:
    get:
      summary: Returns a list of users.
      description: extended description in Markdown.
      produces:
        - application/json
      responses:
        200:
          description: OK

Using an OpenAPI Spec File in HawkScan

If your project already uses an existing v3 OpenAPI specification, you can integrate it with HawkScan with the app.openApiConf parameter.

For example, if your app serves the OpenAPI spec on the URL path /openapi.yaml, include the following in your stackhawk.yml configuration.

app:
  openApiConf:
    # Specify the URL path relative to the host
    path: "/openapi.yaml"

Or if you have the spec defined in a local file, openapi.json, provide the relative path to that file with the following config.

app:
  openApiConf:
    # Specify the relative path to the file
    filePath: "openapi.json"

Using an Inline OpenAPI Spec in HawkScan

PLEASE NOTE: your inline spec cannot exceed 4MB!

You can define portions of your web app structure within the app.openApiConf.inline configuration of your stackhawk yaml in the OpenAPI format:

# in the "app" config...
app:
  # instead of a string path to a file, provide the openapi spec inline as a multi-line string with the yaml | pipe syntax
  openApiConf:
    inline: |
      basePath: /v1           
      schemes:                
      - https                 
      paths:                  
        /users:               
          get:                
            summary: Returns a list of users.
            description: extended description in Markdown.
            produces:         
              - application/json
            responses:        
              200:            
                description: OK

See legacy inline configuration for old style.

This can be useful for segmenting scan results to portions of your web application. It can also start as the foundation of more thorough API documentation to start your own openapi.yaml specification file.

Reminder that your inline spec cannot exceed 4MB!

Using Custom Variable Injection

You can configure HawkScan to use custom values for any parameters that exist in your OpenAPI definition. Using custom values allows you to scan paths that can potentially access real data and exercise more branches of your application’s code than default static values that may not exist in the context of your application. To provide custom values for your OpenAPI definition’s params, include the app.openApiConf.customVariables parameter in your stackhawk.yml file.

By default, DELETE methods will not use the custom values provided in the stackhawk.yaml file to protect data from being deleted by the scanner. If you want to include custom variables in ALL methods, you can set the app.openApiConf.includeAllMethods parameter to true. If you would rather specify exactly which methods to use custom variables with, you may set them with the app.openApiConf.includedMethods list. This list will be ignored if the includeAllMethods parameter is set to true.

The following is an example configuration using custom values:

# in the "app" config...
app:
  openApiConf:
    filePath: "/openapi.yaml"
    # Whether or not to use custom variables for all HTTP methods. Defaults to false and does not use custom variables for DELETE requests. 
    includeAllMethods: false
    # The methods to include in custom variable injection. If `includeAllMethods` is set to true, this list is ignored. Otherwise, only the methods provided will use custom variables.
    includedMethods:
      - POST
      - PUT
    # List of custom variables and a list of possible values to use for each of them.  
    customVariables:
      - field: user_id
        values:
          - 1
          - 2
          - 3
      - field: asset_id
        values:
          - 4
          - 5
          - 6
      - field: asset_title
        values:
          - "testAssetTitle1"
          - "testAssetTitle2"
      - field: username
        values:
          - "testAccountUsername"

If you provide a list of values for a custom variable, the scanner will select one randomly for each paths that the custom variable belongs to. If you provide a single value in the list for a variable, that value will be used. For any parameters in the OpenAPI definition that you do not provide custom values for in the stackhawk.yml file, HawkScan will fall back on default logic and use static values based on their type.

To achieve greater control over OpenAPI custom variables, you have the option to include a path regex and a list of request methods. These additional filters help in injecting custom variable values more selectively. When a path regex and/or a list of request methods are specified, only requests that match that specific information will utilize the provided list of values for variable injection. This allows you to assign different sets of values for the same schema parameter name. For instance, if you have two separate endpoints that both use the {userId} parameter, you can use the path regex to assign distinct lists of potential values for each endpoint. Here’s an example of how to configure paths and methods:

# in the "app" config...
app:
  openApiConf:
    filePath: "/openapi.yaml"
    # Whether or not to use custom variables for all HTTP methods. Defaults to false and does not use custom variables for DELETE requests. 
    includeAllMethods: true
    # List of custom variables and a list of possible values to use for each of them.  
    customVariables:
      - field: searchText
        values:
          - "customSearchText1"
          - "customSearchText2"
          - "customSearchText3"
        path: "/api/v1/jwt/items/search"
        requestMethods:
          - GET
          - POST
      - field: searchText
        values:
          - "customSearchText4"
          - "customSearchText5"
          - "customSearchText6"
        path: "/api/v2/jwt/items/search"
        requestMethods:
          - GET
          - POST      

In the example above, when substituting the searchText parameter for v1 endpoints, it will utilize the custom values 1, 2, and 3. However, for v2 endpoints, the injection will instead use custom values 4, 5, and 6. Additionally, when considering the requestMethods, the injection of values will only occur if the request is either a GET or a POST.

Generating Smart Values for Parameters

By leveraging the Java Faker library, HawkScan can generate smarter values when the proper information is supplied in the OpenAPI definition. To enable this feature, be sure the openApiConf.fakerEnabled value is set to true. In the various schema sections that exist within your definition, if a format field exists with a known type, a random value will be generated in the specified format. For example:

paths:
  /search:
    get:
      parameters:
        - in: query
          name: user_email
          type: string
          format: email
      responses:
        200:
          description: OK

When a value for the parameter user_email is generated by HawkScan and an explicit custom value is not provided, then a random, valid email address will be generated for each path the parameter appears in. Another way to leverage this functionality, if you don’t have access to or don’t want to change the OpenAPI definition, is to inject a format similar to a custom variable, described in the section above. To configure a custom variable, supply the faker prefix along with the desired format to generate a corresponding value. For example, to generate a phone number for a parameter called customer_phone_number and an email for customer_email use the following configuration:

  openApiConf:
    filePath: "/myopenapi.yaml"
    fakerEnabled: true #default false
    customVariables:
      - field: customer_email
        values:
          - "$faker:email"
      - field: customer_phone_number
        values:
          - "$faker:phone"
          - "123456767"

Faker values can be used together with custom variables. In the example above, customer_phone_number is given 2 potential values, a static value, and a faker format. One of the 2 will be chosen randomly when a value is generated, and if the faker value is chosen, then a properly formatted random value will be generated.

Below is a list of all the formats supported by HawkScan:

- email
- phone
- uuid
- url
- uri
- hostname
- ipv4 
- ipv6
- date-time
- date
- float
- double
- boolean
- word
- sentence
- paragraph
- sha256
- sha512
- md5
- yoda (Yoda quotes)

Along with generating values for these formats, the minimum and maximum constraints will also be respected, if provided, for all numbers/integers in the OpenAPI definition.

Tips for Creating a New OpenAPI Spec for HawkScan

Because OpenAPI is widely adopted, there are a lot of available tools to help a project get started: https://openapi.tools/

SmartBear has free online editor that can be used immediately to start building a OpenAPI file that will work with HawkScan: https://swagger.io/tools/swagger-editor/

For new projects, the industry recommended approach is to create an OpenAPI spec file and employ OpenAPI code-generators to stub out the endpoints for the desired server frameworks. For existing projects, there are various ways to get an OpenAPI specification defined.

Framework specific help:

Spring/Springboot

SpringDoc is a java library that helps to generate OpenAPI v3 spec files from configuration, class structure and annotated controllers in projects using spring boot. It exposes the generated OpenAPI file from a configured rest endpoint.

Add the SpringDoc-OpenAPI dependency to your maven build pom file:

  <dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.6.9</version>
  </dependency>

or add the dependency to your build gradle if using gradle:

  implementation("org.springdoc:springdoc-openapi-ui")

Also add any additional springdoc modules pertinent to your project. Springdoc also defines extensive spring configuration properties for smarter openapi file generation and spec customization.

Springdoc provides additional controller and method annotations such as @Operation @Parameter @Tag that work with typical spring boot @RequestMapping and @RestController annotations:

// example spring controllers annotated with springdoc

@RestController
@RequestMapping("/api/pets")
@Tag(name = "Pet", description = "Everything about your Pets")
public class PetController {

  @Operation(summary = "Find a pet by Status", description = "Longer description, finds the first pet that matches the given status...")
  @RequestMapping(value = "/findByStatus", method = RequestMethod.GET, params = {"status"})
  public Pet findPetsByStatus(
       @Parameter(description = "the status of the pet")
       @RequestParam("status", defaultValue="ok") String status
  ) {
       // ...
  }

  @Operation(summary = "Updates a pet in the store", description = "Longer description, updates the given pet from form data that matches...")
  @RequestMapping(value = "/{petId}", method = RequestMethod.POST)
  public ResponseEntity<String> operation2(
    @Parameter(hidden = true) implicitParam: ImplicitParam,
    @Parameter(description = "ID of pet that needs to be updated") @PathVariable("petId", required = true) petId: String,
  ) {
    // ...
  }
}

The spec can then be downloaded to a local file by reaching the configured endpoint.

  $ curl localhost:8080/v3/api-docs > openapi.json

With the openapi.json spec downloaded and available, the stackhawk.yaml can be updated:

  app:
    # specify the relative path to an OpenAPI v3 .json or .yaml file
    # prefix the path with / to pull from the target host
    openApiConf: 
      filePath: "openapi.json"

This guide previously recommended a different library called SpringFox for generating a v2 OpenAPI spec. If needed, you can follow the SpringFox migration guide to replace the deprecated implementation.

Rails

There isn’t a way to automatically find and define routes for OpenAPI, but a good way to start is to output all the app’s routes and then use something like swagger-docs to document them.

List out the app’s routes with rails routes

Set up swagger-docs and document each route: https://github.com/richhollis/swagger-docs

    swagger_controller :users, "User Management"

    swagger_api :index do
    param :query, :page, :integer, :optional, "Page number"
    response :unauthorized
    response :not_acceptable
    response :requested_range_not_satisfiable
    end

Express

There isn’t a way to automatically find and define routes for OpenAPI, but a good way to start is to output all the app’s routes and then use something like swagger-jsdoc to document them.

Find all your routes with some code like this:

    var route, routes = [];

    app._router.stack.forEach(function(middleware){
      if(middleware.route){ // routes registered directly on the app
          routes.push(middleware.route);
      } else if(middleware.name === 'router'){ // router middleware
          middleware.handle.stack.forEach(function(handler){
              route = handler.route;
              route && routes.push(route);
          });
      }
    });

    routes.forEach(function(temp){
        var methods = "";
        for(var method in temp.methods){
            methods += method + ", ";
        }
        console.log(temp.path + ": " + methods);
    });

Set up swagger-jsdoc and then document each route: https://github.com/Surnet/swagger-jsdoc/#getting-started

  /**
  * @swagger
  *
  * /login:
  *   post:
  *     description: Login to the application
  *     produces:
  *       - application/json
  *     parameters:
  *       - name: username
  *         description: Username to use for login.
  *         in: formData
  *         required: true
  *         type: string
  *       - name: password
  *         description: User's password.
  *         in: formData
  *         required: true
  *         type: string
  *     responses:
  *       200:
  *         description: login
  */
  app.post('/login', (req, res) => {
  // Your implementation comes here ...
  });

Django

Django projects can use the Django REST swagger Python package to generate an OpenAPI v2 spec file with their code.

Run pip install django-rest-swagger and add the following to your Django settings:

  INSTALLED_APPS = [
  ...
  'rest_framework_swagger',
  ...
  ]

PHP

Laravel and other PHP frameworks can utilize zircote/swagger-php to generate OpenAPI spec files by using code annotations. For OpenAPI v2 spec generation you can explicitly require version 2._ with composer require zircote/swagger-php:2._. The SWAGGER_VERSION=2.0 environment variable will need to be set in your .env file or defined with export SWAGGER_VERSION=2.0

Add phpdoc annotations to your code to assist with OpenAPI spec generation. When you build your site a swagger.json file will be written out to the local working directory.

    /**
    * @OA\Info(title="My First API", version="0.1")
    */

    /**
    * @OA\Get(
    *     path="/api/resource.json",
    *     @OA\Response(response="200", description="An example resource")
    * )
    */

    /** Generate documentation with your php site */
    <?php
    require("vendor/autoload.php");
    $openapi = \OpenApi\scan('/path/to/project');
    header('Content-Type: application/x-yaml');
    echo $openapi->toYaml();

ASP.NET

The Swashbuckle package will expose an OpenAPI spec for the app via a URL.

Install the package:

  Install-Package Swashbuckle

Enable Swashbuckle in something like Program.cs

  httpConfiguration
       .EnableSwagger(c => c.SingleApiVersion("v1", "A title for your API"))
       .EnableSwaggerUi();

Then download the spec to a file from the URL: <your-root-url>/swagger/docs/v1

Add that new file to the stackhawk.yaml

  app:
    # specify the filepath to an OpenAPI v2 .json or .yaml file
    openApiConf: 
      filePath: "myproj.json"

See legacy file path configuration for old style.

Note: The above steps are for if your app is hosted in IIS. If it’s not, please look at the the Swashbuckle docs for similar install instructions.

Amazon API Gateway

Amazon’s API Gateway allows you to export a REST API as an OpenAPI spec.

You can export an OpenAPI v2 .json file with the AWS CLI using a command like:

aws apigateway get-export \
  --parameters extensions='apigateway' \
  --rest-api-id <restapi_id> \
  --stage-name <stage_name> \
  --export-type swagger openapi.json

Note: You can get the restapi_id and stage_name using these commands.

aws apigateway get-rest-apis
aws apigateway get-stages --rest-api-id=<restapi_id>

Now add that new openapi.json file to the stackhawk.yaml.

  app:
    # specify the filepath to an OpenAPI v2 .json or .yaml file
    openApiConf: 
      filePath: "myproj.json"

See legacy file path configuration for old style.

Postman Collection

When an application lacks an OpenAPI specification but has a Postman Collection available, that collection can be exported as json and then converted into an OpenAPI spec file using various tools, such as postman-to-openapi (local option; requires node.js)

Validating An OpenAPI Specification

Once an OpenAPI spec has been generated using one of the methods described above, it can be validated using the official Swagger editor:

  1. paste in the contents of the spec file – this page will dynamically generate and resolve errors as the specification is edited on the page
  2. apply edits as necessary
  3. supply the updated spec to the scanner via the app.openApiConf configuration
  4. scan the application
    1. if further issues or errors are encountered, contact StackHawk Support for assistance

Redocly for API Specification Linting

StackHawk recommends using Redocly for linting your API specifications. Redocly offers robust tools for validating and ensuring the quality of your API specs. For more information on Redocly’s linting capabilities, visit Redocly’s CLI commands for linting.

Legacy Configuration

Note: This configuration is deprecated. Use app.openApiConf instead.

The configuration style below will continue to be supported, but not always. Update stackhawk.yaml to use the above.

Host path

# in the "app" config...
app:
  # Specify the relative path to an OpenAPI v2 .json or .yaml file,
  # prefix the path with / to pull from the target host
  api: "/openapi.yaml"

File path

  app:
    # specify the relative path to an OpenAPI v2 .json or .yaml file
    # prefix the path with / to pull from the target host
    api: "openapi.json"

Inline openapi

Please Note: An inline spec cannot exceed 4MB!

app:
  api:                   
    basePath: /v1           
    schemes:                
    - https                 
    paths:                  
      /users:               
        get:                
          summary: Returns a list of users.
          description: extended description in Markdown.
          produces:         
            - application/json
          responses:        
            200:            
              description: OK