The Cequence Unified API Protection (UAP) platform uses built-in algorithms to generate attack fingerprints. You can also define a dynamic fingerprint by specifying a custom set of algorithms. When a dynamic fingerprint is active, the Cequence UAP platform applies those algorithms to your traffic as part of a mitigation policy.
Architecture
A dynamic fingerprint comprises up to five algorithms selected from a pool of predefined and custom algorithms.
The Cequence UAP platform ships with seven predefined algorithms, including a null algorithm. You can clone any predefined algorithm into a custom slot and modify it. You can also write custom algorithms in Lua.
The platform supports a maximum of 31 algorithms total: the seven predefined algorithms plus up to 24 custom algorithms. Custom algorithms are numbered from 31 down to 8. You can have one active dynamic fingerprint at a time.
Create a dynamic fingerprint
From the Cequence UAP platform interface, navigate to Threat Protection Dynamic Fingerprinting.
In the Algorithms list, enable toggles for up to five algorithms you want to include in your fingerprint. The Fingerprint Preview pane updates as you make selections. Unspecified algorithm slots display undefined or 000000 in the preview.
Click Save.
Create a custom algorithm
To create a custom algorithm, follow these steps.
- From the Cequence UAP platform interface, navigate to Threat Protection Dynamic Fingerprinting.
- Click Add Custom Algorithm.
- The Add Custom Algorithm dialog displays. Enter a name for the algorithm.
- Enter a description.
- Enter a valid Lua script that defines the algorithm logic.
- Click Validate Expression below the Lua field to check the script syntax.
- Click Create.
Write a custom algorithm
Custom algorithms are Lua scripts that examine request data and return a fingerprint value. The Cequence UAP platform hashes this value and incorporates it into the overall dynamic fingerprint.
Required function
Your script must include a RunFPAlgorithm function with the following signature.
function RunFPAlgorithm(txn)
This function receives the transaction object txn and must return two string values. The first string is your computed fingerprint value, which the platform converts to a hash. The second string is a log message for debugging purposes.
If your script fails to define RunFPAlgorithm, the algorithm returns a null hash value (00000000).
Optional initialization
To improve performance, define an Init function that executes once when the algorithm loads. Use Init to precompute static data that the RunFPAlgorithm function can reuse during request processing.
function Init() -- precompute static values here end
Access request data
Within RunFPAlgorithm, call Cequence functions through the cequence namespace to access request data.
| Name | Data type | Description |
|---|---|---|
cequence.getHostName(txn) | string | Transaction host header value. |
cequence.getPath(txn) | string | Normalized transaction path. |
cequence.getPathRaw(txn) | string | Transaction path without normalization. |
cequence.getClientIP(txn) | string | Computed client IP. |
cequence.getHeaderValue(txn, header_name) | vector of strings | Header values. |
cequence.headerExists(txn, header_name) | boolean | True if the header exists. |
cequence.getHeaderKeys(txn) | vector of strings | All header names. |
cequence.getHeaders(txn) | map | All headers as name-value pairs. Header names are case-insensitive. |
cequence.getQueryParamValue(txn, param_name) | vector of strings | Query parameter values. |
cequence.queryParamExists(txn, param_name) | boolean | True if the query parameter exists. |
cequence.getQueryParamKeys(txn) | vector of strings | All query parameter names. |
cequence.getQueryParams(txn) | map | All query parameters as name-value pairs. Parameter names are case-sensitive. |
cequence.getCookieValue(txn, cookie_name) | vector of strings | Cookie values. |
cequence.cookieExists(txn, cookie_name) | boolean | True if the cookie exists. |
cequence.getCookieKeys(txn) | vector of strings | All cookie names. |
cequence.getCookies(txn) | map | All cookies as name-value pairs. Cookie names are case-sensitive. |
cequence.getBody(txn) | string | Request body. |
cequence.getBodySize(txn) | number | Size of the request body. |
JSON parsing
You can use the cjson module to parse JSON data within your algorithm.
local cjson = require("cjson")Example algorithm
The following algorithm computes a fingerprint based on request headers.
function RunFPAlgorithm(txn)
local headers = cequence.getHeaders(txn)
local fingerprint_value = ""
local log_message = ""
for key, value in pairs(headers) do
fingerprint_value = fingerprint_value .. key .. "=" .. value
log_message = log_message .. key .. ", "
end
return fingerprint_value, "Headers: " .. log_message
endUse a dynamic fingerprint in a mitigation policy
To specify a dynamic fingerprint as part of a mitigation policy, follow these steps.
- From the Cequence UAP platform interface, navigate to Threat Protection Mitigation Policies.
- Click Add New Policy.
- The Add New Policy dialog displays. Enter a policy name.
- Enter a policy description.
- Select a policy type.
- Click + next to Mitigator Criteria.
- The Mitigator Criteria pane displays. From the Field dropdown, select Dynamic Fingerprint.
- From the Operator dropdown, select Equals.
- Enter the fingerprint ID.
- Click Add.
The new mitigation policy now uses the dynamic fingerprint.