Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
254 changes: 225 additions & 29 deletions pages/fraud-prevention/custom-rules/custom-rules-cookbook.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Keyri Rules-Engine Cookbook
# Keyri Custom Rules - Examples

Here you'll find example solutions to common problems as copy-and-paste code
snippets with explanations. These can be used both with our no-code rule builder
and
[low-code rule builder](/fraud-prevention/custom-rules/low-code-rule-builder).

## Recipes
## General Rules

### Reduce False Positives

Expand Down Expand Up @@ -33,7 +33,10 @@ other rules that might have been triggered.
"deviceModel.lieProbability": { "$lte": 0.2 }
},
"outcome": "allow",
"signal": "established_user_device_allow"
"signal": "established_user_device_allow",
"strength": 2,
"enabled": true,
"notes": "Allow if device age is at least 7 days, the user has been seen on the device at least 2 times, and the lie probability is less than or equal to 0.2; strength: 2"
}
```

Expand Down Expand Up @@ -70,16 +73,19 @@ verification.

```json
{
"rule": "too_many_user_denials",
"conditions": {
"rule": "too_many_user_denials",
"conditions": {
"$or": [
{"historicalData.user._denials_10_min_": { "$gte": 3 }},
{"historicalData.user._denials_hour_": { "$gte": 5 }},
],
},
"outcome": "deny",
"signal": "deny_user_id_list",
},
{ "historicalData.user._denials_10_min_": { "$gte": 3 } },
{ "historicalData.user._denials_hour_": { "$gte": 5 } }
]
},
"outcome": "deny",
"signal": "deny_user_id_list",
"enabled": true,
"strength": 2,
"notes": "Deny if user has previously been denied at least 3 times in the past 10 minutes or at least 5 times in the past hour; strength: 2"
}
```

#### Explanation:
Expand All @@ -88,13 +94,13 @@ verification.
whatever you want).
- `outcome`: Set to "deny", so if the rule evaluates to true, the event is
denied.
- `strength`: Doesn't have to be set. We're letting it default to 1.
- `strength`: A value of 2 means it will override other rules with a lower strength.
- `conditions`: Defines the criteria for the rule. In this case they're nested
in an "or" array so if any are true - the whole rule returns as true
in an "or" array so if any are true - the whole rule returns as true.
- `historicalData.user._denials_10_min_`: If there are more than 2 denials in
10 minutes on this IP - block it for 10 minutes
10 minutes on this IP - block it for 10 minutes.
- `historicalData.user._denials_hour_`: If there are more than 4 denials in 1
hour on this IP - block it for an hour
hour on this IP - block it for an hour.

---

Expand All @@ -107,22 +113,24 @@ If the IP Address you're evaluating is associated with 326 login denials in last

You're blocking IP Addresses with more than `count` denials in a given period.
After too many denials occur on the IP Address - nobody can use it for 10
minutes, an hour, whatever
minutes, an hour, etc.

#### Code:

```json
{
"rule": "too_many_ip_denials",
"eventType": "all",
"conditions": {
"$or": [
{ "historicalData.ip._denials_10_min_": { "$gte": 3 } },
{ "historicalData.ip._denials_hour_": { "$gte": 10 } }
]
},
"outcome": "deny",
"signal": "deny_ip_list"
"signal": "deny_ip_list",
"enabled": true,
"strength": 2,
"notes": "Deny if IP has previously been denied at least 3 times in the past 10 minutes or at least 10 times in the past hour; strength: 2"
}
```

Expand All @@ -132,13 +140,13 @@ minutes, an hour, whatever
whatever you want).
- `outcome`: Set to "deny", so if the rule evaluates to true, the event is
denied.
- `strength`: Doesn't have to be set. We're letting it default to 1.
- `strength`: A value of 2 means it will override other rules with a lower strength.
- `conditions`: Defines the criteria for the rule. In this case they're nested
in an "or" array so if any are true - the whole rule returns as true
in an "or" array so if any are true - the whole rule returns as true.
- `historicalData.ip._denials_10_min_`: If there are more than 2 denials in 10
minutes on this IP - block it
minutes on this IP - block it.
- `historicalData.ip._denials_hour_`: If there are more than 9 denials in 1
hour on this IP - block it
hour on this IP - block it.

---

Expand All @@ -158,15 +166,17 @@ we'll want to deny.
```json
{
"rule": "too_many_ip_addresses",
"eventType": "all",
"conditions": {
"$or": [
{ "historicalData.user.uniqueIp._totals_day_": { "$gte": 4 } },
{ "historicalData.device.uniqueIp._totals_day_": { "$gte": 4 } }
]
},
"outcome": "deny",
"signal": "deny_ip_list"
"signal": "deny_ip_list",
"enabled": true,
"strength": 2,
"notes": "Deny if device or user has been seen on at least 4 unique IP addresses in the past 24 hours; strength: 2"
}
```

Expand All @@ -176,10 +186,196 @@ we'll want to deny.
whatever you want).
- `outcome`: Set to "deny", so if the rule evaluates to true, the event is
denied.
- `strength`: Doesn't have to be set. We're letting it default to 1.
- `strength`: A value of 2 means it will override other rules with a lower strength.
- `conditions`: Defines the criteria for the rule. In this case they're nested
in an "or" array so if any are true - the whole rule returns as true
in an "or" array so if any are true - the whole rule returns as true.
- `historicalData.user.uniqueIp._totals_day_`: If there are more than 3 IP
Addresses for this user in 24 hours - block it
Addresses for this user in 24 hours - block it.
- `historicalData.device.uniqueIp._totals_day_`: If there are more than 3 IP
Addresses for this device in 24 hours - block it
Addresses for this device in 24 hours - block it.

---

### Block Users on New Device and VPN

Leverage the `threat` object to determine whether the user is using a VPN
and the `changed` boolean value under `deviceUsers` to determine whether
that user-device combination is new.

#### Code:

```json
{
"rule": "New Device and VPN - deny",
"conditions": {
"$and": [
{
"instanceDeltas.deviceUsers.changed": {
"$eq": "true"
}
},
{
"threat.is_vpn": {
"$eq": "true"
}
}
]
},
"outcome": "deny",
"signal": "new_device_and_vpn",
"enabled": true,
"strength": 2,
"notes": "Deny if the device is new to the account and is on VPN; strength: 2"
}
```

### Only Allow Users from a Certain Country

The following rule will only allow users from the US to access your site.
The user's country is denoted in the `ipGeoData.country_code` property.

#### Code:

```json
{
"rule": "Only allow users from the US",
"conditions": {
"ipGeoData.country_code": {
"$ne": "US"
}
},
"outcome": "block",
"signal": "only_allow_users_from_us",
"enabled": true,
"strength": 2,
"notes": "Deny users from any country except for the U.S.; strength: 2"
}
```

### Override Keyri's Risk Determination with your Own Risk Model

If you already have a risk model, you can use it in conjunction with Keyri
rulesets or use its determination to simply override Keyri's determination.
Pass in your risk score as metadata and use it in your ruleset. In this
example, we're overriding Keyri if the risk score from your model is very
low. It has a `strength` value of 10 to override rules with the default strength
value of 9 or below.

#### Code:

```json
{
"rule": "Override Keyri with own risk model",
"conditions": {
"$and": [
{
"metadata.riskScore": {
"$lte": 5
}
}
]
},
"outcome": "allow",
"signal": "override_keyri_with_own_risk_model",
"enabled": true,
"strength": 10,
"notes": "Allow if internal risk score is less than or equal to 5 even if Keyri's system has a different determination; strength: 10"
}
```

## Financial Rules

### Limit Transactions to a Certain Amount

If If you want to limit the amount of money that can be transferred in a single
event, you can add metadata when triggering the event to indicate the amount.
Be sure to name the metadata field the same as the one in the rule. Here's it's
named `amount`.

#### Code:

```json
{
"rule": "Transaction threshold - 1000",
"conditions": {
"$and": [
{
"eventMetadata.amount": {
"$gt": 1000
}
}
]
},
"outcome": "deny",
"signal": "Transaction_threshold_exceeded",
"enabled": true,
"strength": 2,
"notes": "Deny if money being transferred in 1 event is greater than 1,000; strength: 2"
}
```

### Limit Transaction Totals over a Period of Time

You can use built-in math functionality to query and sum the total value of
the amounts a given user has transacted over a period of time.

#### Code:

```json
{
"rule": "24-hour spend threshold - 2500",
"conditions": {
"$and": [
{
"2500": {
"$lte": {
"$sum": [
"userModel.metadata.amount._sum_24_h_",
"eventMetadata.amount"
]
}
}
},
{
"eventMetadata.amount": {
"$gt": 0
}
}
]
},
"outcome": "deny",
"signal": "24-hour_spend_threshold_exceeded",
"enabled": true,
"strength": 2,
"notes": "Deny if money being transferred in the past 24 hours is greater than 2,500; strength: 2"
}
```

### Block High-Value Transactions from a New Country

Use this rule to block a high-value transaction from a country that the
user has never been in before.

#### Code:

```json
{
"rule": "new_country_high_value_txn",
"conditions": {
"$and": [
{
"userModel.country_code.${ipGeoData.country_code}._count_": { "$eq": 1 }
},
{
"eventMetadata.amount": {
"$gte": 10000 }
}
]
},
"outcome": "deny",
"signal": "high_value_new_country",
"enabled": true,
"strength": 2,
"notes": "Deny if user is transferring greater than 10,000 from a new country; strength: 2"
}
```