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.
- OpenAPI Configuration
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:
- paste in the contents of the spec file – this page will dynamically generate and resolve errors as the specification is edited on the page
- apply edits as necessary
- supply the updated spec to the scanner via the app.openApiConf configuration
- scan the application
- 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