Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add replay protection plugin #1672

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d46723d
"feat: add replay protection plugin
yunmaoQu Jan 14, 2025
c0cff2b
Merge branch 'main' into feature/request-replay-protection
yunmaoQu Jan 14, 2025
d894e3d
update
yunmaoQu Jan 15, 2025
9a9e2e4
Merge branch 'alibaba:main' into feature/request-replay-protection
yunmaoQu Jan 15, 2025
9c0f1dc
Merge remote-tracking branch 'origin' into feature/request-replay-pro…
yunmaoQu Jan 15, 2025
506208f
Merge branch 'feature/request-replay-protection' of https://github.co…
yunmaoQu Jan 15, 2025
d7cec7f
update
yunmaoQu Jan 16, 2025
2762111
update
yunmaoQu Jan 16, 2025
ce47411
Merge branch 'main' into feature/request-replay-protection
yunmaoQu Jan 17, 2025
935d1c9
update
yunmaoQu Jan 20, 2025
a6a5af4
Merge branch 'feature/request-replay-protection' of https://github.co…
yunmaoQu Jan 20, 2025
b1e4ddb
Merge branch 'main' into feature/request-replay-protection
yunmaoQu Jan 20, 2025
1cfd691
update
yunmaoQu Jan 21, 2025
8dccbab
Merge branch 'feature/request-replay-protection' of https://github.co…
yunmaoQu Jan 21, 2025
7caad55
Merge branch 'main' into feature/request-replay-protection
yunmaoQu Jan 21, 2025
b694c48
update
yunmaoQu Jan 21, 2025
ed892cf
Merge branch 'feature/request-replay-protection' of https://github.co…
yunmaoQu Jan 21, 2025
50c088d
fix
yunmaoQu Jan 24, 2025
ed33204
fix
yunmaoQu Jan 24, 2025
88504b0
fix
yunmaoQu Jan 30, 2025
6ee8499
fix
yunmaoQu Jan 31, 2025
5707224
fix e2e test
hanxiantao Feb 9, 2025
d1775a1
fix e2e test
hanxiantao Feb 9, 2025
8792448
add TestCaseName
hanxiantao Feb 9, 2025
67d50ea
add TestCaseName
hanxiantao Feb 9, 2025
ab6a397
fix e2e test
yunmaoQu Feb 9, 2025
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
105 changes: 105 additions & 0 deletions plugins/wasm-go/extensions/replay-protection/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
title: 防重放攻击
keywords: [higress,replay-protection]
description: 防重放攻击插件配置参考
---

## 简介

Nonce (Number used ONCE) 防重放插件通过验证请求中的一次性随机数来防止请求重放攻击。每个请求都需要携带一个唯一的 nonce 值,服务器会记录并校验这个值的唯一性,从而防止请求被恶意重放。

## 功能说明

- **强制或可选的 nonce 校验**:可根据配置决定是否强制要求请求携带 nonce 值。
- **基于 Redis 的 nonce 唯一性验证**:通过 Redis 存储和校验 nonce 值,确保其唯一性。
- **可配置的 nonce 有效期**:支持设置 nonce 的有效期,过期后自动失效。
- **nonce 格式和长度校验**:支持对 nonce 值的格式(Base64)和长度进行验证。
- **自定义错误响应**:支持配置拒绝请求时的状态码和错误信息。
- **可自定义 nonce 请求头**:可以自定义携带 nonce 的请求头名称。

## 配置说明

| 配置项 | 类型 | 必填 | 默认值 | 说明 |
|-------------------|--------|------|-----------------|---------------------------------|
| `force_nonce` | bool | 否 | `true` | 是否强制要求请求携带 nonce 值。 |
| `nonce_header` | string | 否 | `X-Higress-Nonce` | 指定携带 nonce 值的请求头名称。 |
| `nonce_ttl` | int | 否 | `900` | nonce 的有效期(单位:秒)。 |
| `nonce_min_length`| int | 否 | `8` | nonce 值的最小长度。 |
| `nonce_max_length`| int | 否 | `128` | nonce 值的最大长度。 |
| `reject_code` | int | 否 | `429` | 拒绝请求时返回的状态码。 |
| `reject_msg` | string | 否 | `"Duplicate nonce"` | 拒绝请求时返回的错误信息。 |
| `validate_base64` | bool | 否 | `false` | 是否校验 nonce 的 base64 编码格式 |
| `redis.serviceName` | string | 是 | 无 | Redis 服务名称,用于存储 nonce 值。 |
| `redis.servicePort` | int | 否 | `6379` | Redis 服务端口。 |
| `redis.timeout` | int | 否 | `1000` | Redis 操作超时时间(单位:毫秒)。 |
| `redis.keyPrefix` | string | 否 | `"replay-protection"` | Redis 键前缀,用于区分不同的 nonce 键。|

## 配置示例

以下是一个防重放攻击插件的完整配置示例:

```yaml
apiVersion: extensions.higress.io/v1alpha1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

文档里不用贴wasmPlugin的CR配置,只需要贴插件示例配置即可,因为有的用户不是直接用k8s yaml操作的

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

kind: WasmPlugin
metadata:
name: replay-protection
namespace: higress-system
spec:
defaultConfig:
force_nonce: true
nonce_header: "X-Higress-Nonce" # 指定 nonce 请求头名称
nonce_ttl: 900 # nonce 有效期设置为 900 秒
nonce_min_length: 8 # nonce 最小长度
nonce_max_length: 128 # nonce 最大长度
validate_base64: true # 是否开启base64格式校验
reject_code: 429 # 拒绝请求时返回的状态码
reject_msg: "Duplicate nonce" # 拒绝请求时返回的错误信息
redis:
serviceName: "redis.dns" # Redis 服务名称
servicePort: 6379 # Redis 服务端口
timeout: 1000 # Redis 操作超时时间
keyPrefix: "replay-protection" # Redis 键前缀
url: file:///opt/plugins/wasm-go/extensions/replay-protection/plugin.wasm
```

## 使用说明

### 请求头要求

| 请求头名称 | 是否必须 | 说明 |
|-----------------|----------------|------------------------------------------|
| `X-Higress-Nonce` | 根据 `force_nonce` 配置决定 | 请求中携带的随机生成的 nonce 值,需符合 Base64 格式。 |

> **注意**:可以通过 `nonce_header` 配置自定义请求头名称,默认值为 `X-Mse-Nonce`。

### 使用示例

```bash
# Generate nonce
nonce=$(openssl rand -base64 32)

# Send request
curl -X POST 'https://api.example.com/path' \
-H "X-Higress-Nonce: $nonce" \
-d '{"key": "value"}'
```

## 返回结果

```json
{
"code": 429,
"message": "Duplicate nonce detected"
}
```


## 错误响应示例

| 错误场景 | 状态码 | 错误信息 |
|------------------------|-------|--------------------|
| 缺少 nonce 请求头 | `400` | `Missing nonce header` |
| nonce 长度不符合要求 | `400` | `Invalid nonce length` |
| nonce 格式不符合 Base64 | `400` | `Invalid nonce format` |
| nonce 已被使用(重放攻击) | `429` | `Duplicate nonce` |

101 changes: 101 additions & 0 deletions plugins/wasm-go/extensions/replay-protection/README_EN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
title: Nonce Replay Protection
keywords: [higress, replay-protection]
description: replay-protection config example
---


## Introduction

The Nonce (Number used ONCE) replay protection plugin prevents request replay attacks by validating a one-time random number in requests. Each request must carry a unique nonce value, which the server records and validates to prevent malicious request replay.

## Features

- Mandatory or optional nonce validation
- Redis-based nonce uniqueness verification
- Configurable nonce TTL
- Custom error responses
- Nonce format and length validation

## Configuration

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| force_nonce | bool | No | true | Whether to enforce nonce requirement |
| nonce_ttl | int | No | 900 | Nonce validity period (seconds) |
| nonce_header | string | No | X-Higress-Nonce | Request header name for the nonce |
| nonce_ttl | int | No | 900 | Nonce validity period (seconds) |
| nonce_min_length | int | No | 8 | Minimum nonce length |
| nonce_max_length | int | No | 128 | Maximum nonce length |
| reject_code | int | No | 429 | error code when request rejected |
| reject_msg | string | No | "Duplicate nonce" | error massage when request rejected |
| validate_base64 | bool | No | false | Whether to validate the base64 encoding format of the nonce. |
| redis.serviceName | string | Yes | - | Redis service name |
| redis.servicePort | int | No | 6379 | Redis service port |
| redis.timeout | int | No | 1000 | Redis operation timeout (ms) |
| redis.keyPrefix | string | No | "replay-protection" | Redis key prefix |

## Configuration Example

```yaml
apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
name: replay-protection
namespace: higress-system
spec:
defaultConfig:
force_nonce: true
nonce_ttl: 900
nonce_header:""
nonce_min_length: 8
nonce_max_length: 128
validate_base64: true
reject_code: 429
reject_msg: "Duplicate nonce"
redis:
serviceName: "redis.dns"
servicePort: 6379
timeout: 1000
keyPrefix: "replay-protection"
url: file:///opt/plugins/wasm-go/extensions/replay-protection/plugin.wasm
```

## Usage

### Required Headers

| Header | Required | Description |
|--------|----------|-------------|
| `X-Higress-Nonce` | Depends on force_nonce | Random generated nonce value in base64 format |

>Note: The default nonce header is X-Mse-Nonce. You can customize it using the nonce_header configuration.

### Usage Example

```bash
# Generate nonce
nonce=$(openssl rand -base64 32)

# Send request
curl -X POST 'https://api.example.com/path' \
-H "x-Higress-nonce: $nonce" \
-d '{"key": "value"}'
```

## Error Response

```json
{
"code": 429,
"message": "Duplicate nonce detected"
}
```
## Error Response Examples

| Error Scenario | Status Code | Error Message |
|-----------------------------|-------------|-----------------------------|
| Missing nonce header | `400` | `Missing nonce header` |
| Nonce length not valid | `400` | `Invalid nonce length` |
| Nonce not Base64-encoded | `400` | `Invalid nonce format` |
| Duplicate nonce (replay attack) | `429` | `Duplicate nonce` |
1 change: 1 addition & 0 deletions plugins/wasm-go/extensions/replay-protection/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.0.0-alpha
20 changes: 20 additions & 0 deletions plugins/wasm-go/extensions/replay-protection/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module github.com/alibaba/higress/plugins/wasm-go/extensions/replay-protection

go 1.19

replace github.com/alibaba/higress/plugins/wasm-go => ../..

require (
github.com/alibaba/higress/plugins/wasm-go v1.4.2
github.com/higress-group/proxy-wasm-go-sdk v1.0.0
github.com/tidwall/gjson v1.18.0
github.com/tidwall/resp v0.1.1
)

require (
github.com/google/uuid v1.3.0 // indirect
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 // indirect
github.com/magefile/mage v1.14.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
)
20 changes: 20 additions & 0 deletions plugins/wasm-go/extensions/replay-protection/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbGQ2DTIXHBHxWfqCYQW1fKjyJ/I7W1pMyUDeEA=
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
github.com/higress-group/proxy-wasm-go-sdk v1.0.0 h1:BZRNf4R7jr9hwRivg/E29nkVaKEak5MWjBDhWjuHijU=
github.com/higress-group/proxy-wasm-go-sdk v1.0.0/go.mod h1:iiSyFbo+rAtbtGt/bsefv8GU57h9CCLYGJA74/tF5/0=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/resp v0.1.1 h1:Ly20wkhqKTmDUPlyM1S7pWo5kk0tDu8OoC/vFArXmwE=
github.com/tidwall/resp v0.1.1/go.mod h1:3/FrruOBAxPTPtundW0VXgmsQ4ZBA0Aw714lVYgwFa0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Loading
Loading