Policy Analyzer
Configuration Name: PolicyEvaluator
Description
The PolicyEvaluator
analyzer evaluates user-defined policy rules for each
step executed by Sift. A finding is reported if a sequence violates the
user-specified Rego
policy. The
severity of a finding is configurable by the user.
Configuration Parameters
The PolicyEvaluator
analyzer requires a policy. A policy stored in the
Platform may be specified by its ID.
- kind: PolicyEvaluator
policyId: "00000000-0000-0000-0000-000000000000"
A policy stored on the local filesystem must be given a name that will be displayed on findings reported for any policy violation.
- kind: PolicyEvaluator
name: "MySecurityPolicy"
policyFile: "policy.rego"
Rego Policy
A Rego policy used with the PolicyEvaluator must declare the package as "aptori" and define a "violations" rule. The "violations" rule must return an array of violation objects when a request sequence violates a policy rule. Each violation object must include a rule name, severity, and an array of reasons explaining why the rule was violated.
package aptori
violations contains {
"ruleName": "Policy Rule A",
"severity": "medium",
"reasons": ["reason1", "reason2"],
} if {
condition1
condition2
}
In the above example, if both condition1
and condition2
are true
(logical-AND), then a violation is reported for rule "Policy Rule A" with
severity of "medium" and two reason strings.
The schema for a Violation is:
ruleName
: string with display name for policy ruleseverity
: string that is one of "critical", "high", "medium", "low", "info"reasons
: an array of strings that describe reasons for a rule violation
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,
reasonsRuleB
will fail if condition1
AND condition2
are true, OR
condition3
AND condition4
AND condition5
are true. Different reason
messages are reported for the two cases.
package aptori
violations contains {
"ruleName": "Policy Rule B",
"severity": "high",
"reasons": reasonsRuleB,
} if {
len(reasonsRuleB) > 0
}
reasonsRuleB contains "some reason for failed rule" if {
condition1
condition2
}
reasonsRuleB contains "a different reason for failed rule" {
condition3
condition4
condition5
}
If both sets of conditions are true, then both reason messages will be added to the violation. The reason messages are displayed in the finding that is reported to the Aptori Platform.
Any number of rules and expressions that add to the violations
array may be
defined in a policy.
Policy Evaluation
Rules in a policy are evaluated by Sift after every request to the target
application. The sequence of request-response pairs that is being evaluated is
passed in the input data. A pre-defined variable input
is available to use
when defining conditions. The value input.sequence
contains the sequence of
steps, each step represents a request-response pair made to the target
application. 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,
"invokedAt": string, // timestamp in RFC3339 format
"path": string, // path portion of the request URL
"method": string, // HTTP method of request
"status": string, // One of "success" (for 2xx), "client-error" (for 4xx),
// or "server-error" (for 5xx)
"input": {
"body": {}, // JSON object in schema 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": {}, // JSON object in schema defined by API
},
"request": {
"body": string, // base64-encoded raw request body
"header": {}, // map of header to array of string.
"method": string, // HTTP method of request
"url": string // Complete request URL
},
"response": {
"body": string, // base64-encoded raw request body
"header": {}, // map of header key to array of string.
"statusCode": integer // HTTP response status code
}
}
]
}
Example Policy
The following policy verifies password strength using user-specified criteria.
It contains multiple rules, such as length should be greater than or equal to
12 characters, password must contain upper-case, etc. This updatedPassword
rule only returns a password when the method is "POST", "PUT", "PATCH" (e.g.,
an operation that modifies the password) and the request body contains a
"password" field. Further, the rule has a condition that the operation must
have succeeded, e.g., the application accepted the password values. If any of
those conditions are false, then updatedPassword
returns an undefined value
that causes rules that reference it to be false.
package aptori
violations contains {
"ruleName": "Password Strength",
"severity": "high",
"reasons": PasswordViolations,
} if {
count(PasswordViolations) > 0
}
PasswordViolations contains "must have lower-case character" if {
not regex.match(`[a-z]`, updatedPassword)
}
PasswordViolations contains "must have upper-case character" if {
not regex.match(`[A-Z]`, updatedPassword)
}
PasswordViolations contains "must have a numeric digit" if {
not regex.match(`[0-9]`, updatedPassword)
}
PasswordViolations contains "must have symbol character" if {
not regex.match(`[!@#$%^&*;]`, updatedPassword)
}
PasswordViolations contains "must have at least 12 characters" if {
not count(updatedPassword) >= 12
}
# updatedPassword contains the value of a password that was
# accepted by an operation that stores a password.
updatedPassword := x if {
some step in input.sequence
step.status == "success"
step.method in {"POST", "PUT", "PATCH"}
x := step.input.body.password
}
Some details to observe in the above example:
violations
is the rule evaluated by Sift. If it contains a non-empty array of violation objects, then Sift reports a finding to the Aptori Platform.- A violation is only added to
violations
if there are one or more reason strings added toPasswordViolations
. - Multiple rules for
PasswordViolations
are defined. Each rule checks a different condition of the password strength criteria and adds a reason string toPasswordViolations
if true. - Conditions in each
PasswordViolations
rule check the value of a modified password, as determined by the value ofupdatedPassword
. - If a value is not present in the input data, a condition that uses the value
is undefined and the condition is not considered true. Hence, if there is an
operation with method "PUT" but it does not contain a field "password" in the
request body, then
updatedPassword
has the undefined value, and rules that use it will not be true.
Test your policy using Rego Playground
Test your policy using Rego Playground. This is a sample value for the input data that describes a request sequence being evaluated. This sample may be pasted into the input box and altered for testing your policy.
{
"sequence": [
{
"operationID": "registerUser",
"invokedAt": "2025-03-27T18:31:15.836538-07:00",
"method": "POST",
"path": "/users/v1/register",
"status": "success",
"input": {
"body": {
"email": "[email protected]",
"password": "NotSecret",
"username": "robert42"
},
"header": {
"Content-Type": "application/json"
}
},
"output": {
"body": {
"message": "Successfully registered. Login to receive an auth token.",
"status": "success"
},
"header": {
"Content-Length": "92",
"Content-Type": "application/json",
"Date": "Fri, 28 Mar 2025 01:31:15 GMT"
}
},
"request": {
"body": "eyJlbWFpbCI6ICJib2JAZXhhbXBsZS5jb20iLCAicGFzc3dvcmQiOiAiTm90U2VjcmV0IiwgInVzZXJuYW1lIjogInJvYmVydDQyIn0K",
"header": {
"Content-Type": ["application/json"]
},
"method": "POST",
"url": "https://example.com/api/v1/register"
},
"response": {
"body": "eyAibWVzc2FnZSI6ICJTdWNjZXNzZnVsbHkgcmVnaXN0ZXJlZC4gTG9naW4gdG8gcmVjZWl2ZSBhbiBhdXRoIHRva2VuLiIsICJzdGF0dXMiOiAic3VjY2VzcyIgfQo=",
"header": {
"Content-Length": ["95"],
"Content-Type": ["application/json"],
"Date": ["Fri, 28 Mar 2025 01:31:15 GMT"]
},
"statusCode": 201
}
}
]
}
Faults Reported
When a policy reports a violation, the policy name is included in the title of
the finding. The severity
field of a violation determines the severity of
the finding. The ruleName
and reasons
fields of a violation are displayed
in the step comment of the finding.
Fault Identifier | Title | Summary | Solution | Severity |
---|---|---|---|---|
SPF-100 | Policy - {policyName} |
Operation sequence violates one or more rules in user-specified policy. | Modify the application logic to satisfy all expected behaviors. | {severity} as specified in violation |