Sift Configuration Schema
Sift configuration has 3 main sections:
- Test Profile specifies what tests will be performed.
- Targets specifies what target API will be tested.
- Run Parameters specifies how Sift will execute.
Configuration parameters that are required are marked as such in the descriptions below. A value for a configuration parameter may contain a template expression - see Configuration Templating for details.
Example Configuration
version: 2
testProfile:
analyzers:
- kind: OpenAPIConformance
- kind: BrokenObjectLevelAuth
- kind: BUA
- kind: EmailExposure
- kind: ServerError
- kind: PolicyEvaluator
policy: filename
rules:
- rule: nameOfRuleInPolicyFile
severity: high
- attacks:
- file: InjectionStringsFile
name: faultName
severity: high
kind: ConfigurableInjection
- attacks:
- file: HeaderInjectionStringsFile
header: User-Agent
name: faultName
severity: high
kind: ConfigurableHeaderInjection
defaultGenerators:
- 11100000-0000-0000-0000-000000000111
- 22200000-0000-0000-0000-000000000222
targets:
- id: 00000000-0000-0000-0000-000000000000
url: http://localhost:8888/
traceHeader: Sift-Request
timeout: 5s
model:
definition:
file: examples/VAmPI/openapi3.yaml
type: API_KIND_OPENAPI
generators:
- context: /createApplication
rules:
- kind: Regex
params:
expr: TL-[0-9]{8}
pattern: loan_id
type: string
- kind: IntRange
params:
max: 850
min: 300
pattern: fico
type: number
- kind: IntRange
params:
max: 130
min: 18
pattern: age
type: number
- context: /createAccessToken/input/body
rules:
- kind: IntConstant
params:
value: 42
pattern: expiresAt
type: number
authorization:
user1:
kind: static
location: header
name: Authorization
value: Bearer eyXXXXXXXXXXXXX
user2:
kind: static
location: header
name: Authorization
value: Basic ZGVtbzpwQDU1dzByZAo=
user3:
kind: basic
password: p@55w0rd
username: demo
user4:
command: bearer_token_gen.py
kind: dynamic
location: header
name: Authorization
timeout: 5m0s
user5:
command: http_header_gen.js
kind: dynamic-http-header
timeout: 5m0s
popToken:
fields:
- http-method
- uri
- body
header: X-Authorization
privateKey: ./path/to/popPrivateKey.pem
operations:
excludeId:
- deleteUser
includeId:
- createApplication
- createAccessToken
# Run Parameters (optional)
environmentId: 00000000-0000-0000-0000-000000000000
fuzzLimit: 5
labels:
env: dev
commitSHA: c5e902b7ddfd48eace196b0c050f52e069529279
platformUrl: http://localhost:8080
sequenceLimit: 3
timeLimit: 10m25s
Test Profile
testProfile
contains configuration parameters that specify what to test in a
run.
The testProfile
property may contain an object with the sub-properties
defined below. Or, it may contain a string that is the filename that contains
the Test Profile object.
Analyzers
testProfile.analyzers
is a list of Analyzers to use during an
analysis run. Each analyzer checks an API for specific kinds of faults. At
least one analyzer is required to be specified.
Each item in the list is a map that contains a required key kind
, which
specifies the kind of analyzer to enable in the analysis. Some analyzers have
additional configuration parameters that must be specified in the map. The
analyzer descriptions in the Analyzers page contain the
configuration name of each kind of analyzer and any additional parameters
required by an analyzer.
Default Generators
testProfile.defaultGenerator
is an optional list of GeneratorSet IDs that are
used as the default generators in a run. Default GeneratorSets define
generators for common, global fields. The order of IDs in the list is from
highest to lowest precedence. All of the GeneratorSets in the list have lower
precedence than generators in the Semantic Model
(targets[].model.generators
).
Targets
A target is an API that is analyzed by Sift. Each target specifies an API ID that has previously been defined in the Aptori Platform. Other parameters of a target configure the URL at which Sift can access the API, the location of the API definition, and authorization settings for requests to the API.
targets
is an array of targets. At least one target is required to be
specified. Each target contains:
id
: Asset ID defined in Aptori Platform. (required)url
: Base URL where an application is serving the API. (required)model
: Semantic Model of the target API.definition
: Location of the API definition. (required)generators
: Specify how to generate values for input fields in the API.resourceProfiles
: Specify hints for the Semantic Model.
authorization
: Parameters to configure authorization token for requests.header
: Optional additional HTTP header fields to include in requests.operations
: Filters for which operations to test.popToken
: Parameters to add Proof-of-Possession (PoP) tokens to requests.rateLimit
: Control the number of requests per second to invoke.timeout
: Request timeout duration.traceHeader
: HTTP header field to populate with a unique request identifier.
Model
A Semantic Model describes what the target API looks like and data relationships among its operations. Aptori automatically constructs a Semantic Model from an API definition, but a user may specify hints to refine the Semantic Model.
The targets[].model
property may contain an object with the sub-properties
defined below. Or, it may contain a string that is a filename that contains
the Semantic Model object.
Definition
targets[].model.definition
configures a location where Sift can find the API
definition. This parameter is required.
Sift can load an API definition from a URL or a file on the local filesystem.
Or, Sift can retrieve a specific revision of the API definition from the
Platform. Only one of path
, file
, or revision
should be specified. If
multiple are specified, then the Sift will choose one according to precedence,
from high to low: path
, file
, revision
.
definition
has the following fields:
type
: Type of API definition. Supported types are "API_KIND_OPENAPI".path
: Absolute or relative URL to the API definition. If the URL is relative (starts with "/"), then it is resolved relative to theURL
of the target API.file
: Filename on the local filesystem that contains API definition.revision
: Revision ID of an API definition that has been uploaded to the Platform.
Generators
targets[].model.generators
is a GeneratorSet that specifies rules for how to
select a Generator to produce a value for an input field of an operation. The
GeneratorSet may specify both field-specific and wildcard-style rules. Refer
to Generators for details.
Specifying a GeneratorSet for an API is optional. When a Generator is not configured for a particular field, Sift intelligently generates values based on its understanding of the API definition.
Resource Profiles
A Resource Profile specifies the kind of resource acted upon and type of action performed by an operation.
targets[].model.resourceProfiles
is a list of Resource Profile objects. Each
Resource Profile object has the following properties.
operation
: Operation ID for this ResourceProfile objectresource
: Name of a kind of resource. Slashes in the string are used to denote hierarchical resources.action
: Specifies the type of action the operation performs. One ofcreate
,read
,update
,delete
,list
.identifier
: For action typescreate
andlist
, this property specifies the field that contains the ID of the resource provided by the operation. The string is formated as a JSON Pointer, such as "/output/body/id" or "/input/path/name".
Authorization
targets[].authorization
configures authorization tokens to use in requests sent to a
target API. authorization
is map of user identity ID to an identity
configuration. The user identity ID is a user-specified name for a user
identity supplied in requests to the target API.
Each identity configuration contains a required kind
property that specifies
the kind of authorization for a user identity as one of:
static
basic
dynamic
dynamic-http-header
Each kind of authorization has additional configuration parameters, as described in the following subsections.
All of the kinds of authorization may contain an optional validation
property. When present, the validation
property instructs Sift to validate
the authorization credential by making a request to the target and comparing
the response status code to an expected value. The validation
property is an
object with the following properties:
method
: HTTP method of the validation requestpath
: Path of the validation request is appended to the target's URL.statusCode
: Expected status code of the response.
If a validation request fails or the status code does not match, then Sift will abort the run with an error.
Static
A static
kind of authorization configures an authorization token value that
is valid for the duration of an analysis run. Each static authorization has
three required fields:
location
: The location where the authorization token is passed in a request. This must be set to "header".name
: Name of the header key in which the authorization token value is passed in a request. Whenlocation
is "header",name
is the HTTP header key (e.g., "Authorization", "Api-Key").value
: The static token value that will be passed in the request.
For example, to set a Bearer JWT in the "Authorization" header, use the following identity configuration, where "{jwt}" is a placeholder for the JWT value.
kind: static
location: header
name: Authorization
value: Bearer {jwt}
This will configure Sift to send the following header in each request:
Authorization: Bearer {jwt}
Basic
A basic
kind of authorization configures Sift to use HTTP Basic
Authentication as authorization for a request. Each basic authorization has
two required fields:
username
: The username for HTTP Basic authorization.password
: The password for HTTP Basic authorization.
For example, the following identity configuration:
kind: basic
username: demo
password: p@55w0rd
will configure Sift to use the following authorization in each request:
Authorization: Basic {base64-encoded("demo:p@55w0rd")}
Dynamic
A dynamic
kind of authorization configures Sift to use an authorization value
that is provided at runtime by execution of a command and refreshed
periodically according to a configured interval. Each dynamic authorization
has the following required fields:
location
: The location where the authorization token is passed in a request. Supported values are: "header".name
: Name of the header key in which the authorization token value is passed in a request. Whenlocation
is "header", the value ofname
is the HTTP header key (e.g., "Authorization", "Api-Key").command
: Command to execute to generate an authorization token.timeout
: Interval in seconds at which the command will be executed.
Execution of command
must produce a token value on its standard output
(stdout). Any leading and trailing whitespace will be trimmed.
Since the command may need to interact with the target application, the URL of the target is set in environment variable "SIFT_TARGET_URL" when the command is executed.
For example, given the following authorization configuration:
kind: dynamic
location: header
name: Authorization
command: echo "Bearer jwt12345"
timeout: 300
Sift will execute command echo "Bearer jwt12345"
at least once every 300
seconds, and use the output as the authorization token. In each request, the
authorization token will be passed in the following HTTP header specified in
the configuration:
Authorization: Bearer jwt12345
Alternately, different kinds of commands may be used and the authorization token may be passed in whichever header is specified in the configuration. For example, a Python script can be used in the command:
kind: dynamic
location: header
name: Api-Key
command: python getApiKey.py
timeout: 300
If the output of python getApiKey.py
is "apiKey6543", then Sift will send
the following HTTP header in each request:
Api-Key: apiKey6543
Dynamic-HTTP-Header
A dynamic-http-header
kind of authorization configures Sift to use a set of
HTTP headers that are provided at runtime by execution of a command, and
refreshed periodically according to a configured interval. Each
dynamic-http-header
authorization has the following required fields:
command
: Command to execute to generate HTTP headers.timeout
: Interval in seconds at which the command will be executed.
Execution of command
must produce on its standard output (stdout) a set of
HTTP headers, one per line, in the form "Key: Value". Any leading and trailing
whitespace will be trimmed.
Since the command may need to interact with the target application, the URL of the target is set in environment variable "SIFT_TARGET_URL" when the command is executed.
As an illustrative example, consider the following authorization configuration:
kind: dynamic-http-header
command: auth.sh
timeout: 120
and the Bash script auth.sh
:
#!/bin/bash
echo "Authorization: Bearer jwt12345"
echo "X-TenantId: abcdef54321"
Sift will execute the auth.sh
command at least once every 120 seconds, and
use the headers read from the output. In each request, the authorization
headers will be added to any other headers configured by the user (see
"Additional Headers") or added by Sift's generated test sequences.
Authorization headers override other user configured headers.
For the example above, the following HTTP headers will be included in a request (along with any other headers, not shown).
Authorization: Bearer jwt12345
X-TenantId: abcdef54321
Any language may be used to implement the command. The following example
illustrates how to use Javascript to obtain a JWT token from a login API, and
output an HTTP Authorization
header with the bearer token.
#!/usr/bin/env node
//
// Example login script for Sift dynamic-http-header authorization plugin.
//
// This script performs a POST request to a login endpoint and obtains a JWT
// token from the response. It outputs the necessary "Authorization" header
// with the bearer token value to stdout. All of the headers output by the
// script to stdout will be used by Sift to authorize requests for the virtual
// user associated with this script.
//
// WARNING: Do NOT store secrets in a script. For illustration only!
const userEmail ='[email protected]';
const userPass = 'MySecret';
// Using environment variable SIFT_TARGET_URL ensures this script will work
// with any target URL in the Sift configuration (or on Sift command-line).
const base_url = process.env.SIFT_TARGET_URL;
const login_url = `${base_url}/api/v1/user/login`;
const payload = { 'email': userEmail, 'password': userPass };
fetch(login_url, {
method: "POST",
headers: { "Content-type": "application/json" },
body: JSON.stringify(payload),
})
.then((response) => {
if (response.status !== 200) {
console.log(`Login failed: status=${response.status}`);
process.exit(1);
}
response.json().
then(resp => {
console.log(`Authorization: Bearer ${resp.data.jwtToken}`);
})
})
.catch(error => {
console.error('Error during login:', error.message);
process.exit(1);
});
Additional Headers
The targets[].header
property of a Target configures additional HTTP headers
to send in each request. The property is a map of key-value pairs. For
example, the following configuration adds a "Referer" header to each request to
a Target.
header:
Referer: https://example.com
The headers are added to every request, and have higher precedence than headers from authorization user identity (if the header fields are identical).
Proof-of-Possession (PoP) Token
The targets[].popToken
property of a Target is an optional property to configure Sift
to add a Proof-of-Possession (PoP) token to each request. A PoP token signs
details of a request with a private key. The popToken
property contains the
following subfields:
privateKey
: A required filename that contains a RSA private key in PEM format.header
: A required parameter that contains the HTTP header key into which a PoP token is added to a request.fields
: An optional array of fields of an HTTP request to sign in a PoP token. The values may be any header key or one of the pre-defined keywords 'http-method, 'uri', 'body'. The field values are extracted and added into the PoP token's 'edts' claim in the order that they appear.
If fields
is empty or not specified, then 'edts and 'ehts' will be set to
all header keys of a request, followed by 'http-method', 'uri', 'body' (in
that order).
A field may not be present in a particular request (e.g., missing body, missing header key). In that case, the field name remains in the 'ehts' claim and the value of the field is treated as an empty string (i.e., no bytes added to 'edts' for that field).
Example:
popToken:
privateKey: ./path/to/popPrivateKey.pem
header: X-Authorization
fields:
- http-method
- uri
- body
Operations Filter
The targets[].operations
property configures a filter that selects which
operations from a target API are invoked during an analysis run. An operation
will be invoked when all include filters match, and no exclude filter matches.
Any filter that is empty or not specified defaults to match. Filters that may
be specified:
includeID
: an array of Operation IDs. Match if operation's ID is present in the array.excludeID
: an array of Operation IDs. Match if operation's ID is present in the array.includePath
: an array of regular expressions that match path of an OpenAPI operation. Match if operation is an OpenAPI operation and the path of the operation matches a regular expression in the array. Ignored for any non-OpenAPI operation.excludePath
: an array of regular expressions that match path of an OpenAPI operation. Match if operation is an OpenAPI operation and the path of the operation matches a regular expression in the array. Ignored for any non-OpenAPI operation.
Rate Limit
targets[].rateLimit
configures the rate at which Sift sends requests to a
target API. The value of rateLimit
is a floating point number of requests
per second.
Examples:
3
: send no more than 3 requests per second.0.5
: send no more than 1 request every 2 seconds.
Timeout
targets[].timeout
configures the maximum duration for each request to a
target. The value of timeout
may be a number (in seconds) or a string that
uses the following suffixes for time units: "h" for hours, "m" for minutes, "s"
for seconds, "ms" for milliseconds. For example, a value of "1m30s" is
equivalent to "90s" - both set the timeout to 90 seconds.
If timeout
is not specified or value is zero, then the default timeout is 3
seconds. If the value is negative, then requests will not have a timeout (NOT
RECOMMENDED).
Trace Header
If targets[].traceHeader
is a non-empty string, then Sift sends a unique
request identifier in this header field in every request. The identifier is
unique among all requests sent to a particular target in a single analysis
run. The request identifier can be used to trace or correlate a request with
application logs.
The value of traceHeader
should not conflict with the name of any header
parameter defined in the API definition because it will override values that
Sift is trying to use to analyze the application.
Run Parameters
The following optional properties may be specified at the top-level of the configuration to control how a run is executed.
Environment
environmentID
specifies the ID of an Environment (defined in Platform) in
which the analysis is being performed. This may also be overridden with CLI
flag --env
.
Fuzz Limit
fuzzLimit
configures that number of attempts that are made to invoke each
operation when constructing sequences of operations.
Labels
labels
are user-defined metadata assigned to an analysis run. labels
is a
map of user-defined key-value pairs of strings.
Additional labels may be added with CLI flag --label
.
Platform URL
platformURL
specifies the location of the Aptori Platform to which results of
the analysis run will be published.
This value is overridden by presence of any of the following, from highest to lowest priority:
- CLI flag
--platform
; - environment variable
SIFT_PLATFORM_URL
.
Sequence Limit
sequenceLimit
configures the maximum length for an operation sequence that is
constructed during an analysis run. If sequenceLimit
is not specified, then
the default behavior is to construct sequences of up to 100 operations in
length.
Time Limit
timeLimit
configures the maximum duration of an analysis run. The duration
is a string that may use the following suffixes for time units: "h" for hours,
"m" for minutes, "s" for seconds. For example, to set a 12.5 minute time
limit, use the string "12m30s".
NOTE: sift
performs initialization and final transmission to the Aptori
Platform outside of the analysis time limit. If there is an external limit on
runtime, then it is recommended to configure timeLimit
to be 30 seconds less
than the external limit.