-
Notifications
You must be signed in to change notification settings - Fork 559
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
base: main
Are you sure you want to change the base?
Changes from 9 commits
d46723d
c0cff2b
d894e3d
9a9e2e4
9c0f1dc
506208f
d7cec7f
2762111
ce47411
935d1c9
a6a5af4
b1e4ddb
1cfd691
8dccbab
7caad55
b694c48
ed892cf
50c088d
ed33204
88504b0
6ee8499
5707224
d1775a1
8792448
67d50ea
ab6a397
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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-Mse-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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 文档里不用贴wasmPlugin的CR配置,只需要贴插件示例配置即可,因为有的用户不是直接用k8s yaml操作的 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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-Mse-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.higress" # Redis 服务名称 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这个serviceName的例子给的不对 ,用 redis.dns 吧,下面README_EN也相应调整下 |
||
servicePort: 6379 # Redis 服务端口 | ||
timeout: 1000 # Redis 操作超时时间 | ||
keyPrefix: "replay-protection" # Redis 键前缀 | ||
url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/replay-protection:v1.0.0 | ||
``` | ||
|
||
## 使用说明 | ||
|
||
### 请求头要求 | ||
|
||
| 请求头名称 | 是否必须 | 说明 | | ||
|-----------------|----------------|------------------------------------------| | ||
| `X-Mse-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-Mse-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` | | ||
|
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-Mse-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.higress" | ||
servicePort: 6379 | ||
timeout: 1000 | ||
keyPrefix: "replay-protection" | ||
url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/replay-protection:v1.0.0 | ||
``` | ||
|
||
## Usage | ||
|
||
### Required Headers | ||
|
||
| Header | Required | Description | | ||
|--------|----------|-------------| | ||
| `X-Mse-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-apigw-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` | |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
1.0.0 |
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.21.11 | ||
|
||
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 | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||
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= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mse 建议可以改名为 higress