Skip to content

Application-specific Property Analyzer

Configuration Name: PolicyEvaluator

Description

The PolicyEvaluator analyzer evaluates user-defined properties for each successful sequence executed by Sift. A finding is reported if a sequence violates the user-specified Rego policy. Severity of a finding is configurable by the user.

Configuration Parameters

The PolicyEvaluator analyzer requires two configuration parameters:

  • policy: A file containing a Rego policy. Policy file must declare "package aptori".
  • rules: An array of rules to be evaluated. Each rule has the following fields:
    • rule: Name of a rule in the policy file. Each rule must evaluate to a string if the rule matches.
    • severity: Severity to be reported in a Finding if the rule matches. One of "high", "medium", or "low".

A policy file must declare "package aptori". A rule must evaluate to a set of strings. This form can be written as:

Rego Policy File

A policy file defines rules using the Rego policy language. When all conditions of a rule are true, then the rule must evaluate to a string that describes the reason a property violation.

package aptori

exampleProperty[msg] {
    condition1
    condition2
    msg := "some reason for failed property"
}

In the above example, if both condition1 and condition2 are true (logical-AND), then msg will be added to the set of reasons for which exampleProperty has failed. To represent a logical-OR, a rule may be repeated with a different set of conditions, and optionally a different reason message. In the next example, exampleProperty will fail if condition1 AND condition2 are true, OR condition3 AND condition4 AND condition5 are true.

package aptori

exampleProperty[msg] {
    condition1
    condition2
    msg := "some reason for failed property"
}
exampleProperty[msg] {
    condition3
    condition4
    condition5
    msg := "some other reason for failed property"
}

If both sets of conditions are true, then both reason messages will be added to the exampleProperty set of failure reasons. The reason messages will be displayed with the finding that is reported to the Aptori Platform.

Additional rules may be defined in the file. Any rule may be referenced by a top-level rule that is specified in the Sift configuration file.

Rule Evaluation

Rules in the policy are evaluated by Sift after every successful request to an application. The sequence of request-response pairs that is being evaluated is passed in the input data. Pre-defined variable input is available to use when defining conditions. Value input.sequence contains the sequence of request-response pairs. A condition may refer to any value in a request or response in a sequence.

Input Data Schema

The schema of the input data is an object:

{
  "sequence": [             // array of steps, in chronological order
    {
      "operationID": string,
      "input": {
        "body": {},         // map of request body fields as defined by API
        "header": {},       // map of request header fields
        "path": {},         // map of path parameters as defined by API
        "query": {},        // map of query parameters as defined by API
      },
      "output": {
        "header": {},       // map of response header fields
        "body": {},         // map of response body fields as defined by API
      },
      "invokedAt": string,  // timestamp in RFC3339 format
      "path": string,       // for OpenAPI operation
      "method": string,     // for OpenAPI operation
      "statusCode": integer // for OpenAPI operation
    }
  ]
}

Example Configuration

The following example configuration specifies a property that password length should be greater than or equal to 12 characters in length. This property is evaluated only for a subset of operations in the API that set a password. Further, the property has a condition that the operation must have succeeded, e.g., the application accepted a password of insufficient length.

package aptori

passwordViolation[msg] {
    passwordLength[_] < 12
    msg := sprintf("Password length is less than 12", [])
}

passwordLength[op] = x {
    step := input.sequence[i]
    op := step.operationID
    passwordModifyOps[op]
    step.output.body.status == "success"
    x := count(step.input.body.password)
}

passwordModifyOps := {"api_views.users.update_password", "api_views.users.register_user"}

Some details to observe in the above example:

  • passwordViolation is the rule specified in the Sift configuration. It evaluates to a set of strings, as required.
  • Multiple helper rules are defined and used by passwordViolation.
  • Conditions check values in the input values of an operation and in the output values of an operation.
  • If a value is not present in the input data, a condition that uses the value is undefined. The condition is not considered true. This can be the case when a property applies only to a subset of operations. For operations that lack the necessary inoput values, the rule will not evaluate to true.

Faults Reported

The name and severity configuration fields of a policy rule are used when reporting a finding for a detected fault. The name parameter will be included in the title of the fault. The severity field will assign the severity the fault.

Fault Identifier Title Summary Solution Severity
SPF-100 Policy - {rule} Operation sequence violates one or more properties in user-specified policy. Modify the application logic to satisfy all expected behaviors. {severity} as configured