## 增值防护方案 (`protect-schemes`)

防重放、防泄露、防篡改各一份方案(租户各自一份,管理员编辑平台方案);保存时一并改「按方案」的站点,单独设置的不动;属 WAF 增强。

鉴权: 用户（部分参数仅管理员） · 文档: https://www-demo.kuxitong.com/zh/docs/api/protect-schemes

### GET `/api/v2/protect-schemes/leak`

获取防泄露方案 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/protect-schemes/leak" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/protect-schemes/leak`

保存防泄露方案 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `custom` | SiteLeakGuardCustom[] | 有 | 自定义正则,最多 16 条。 |
| `detect` | SiteLeakGuardDetect | 有 | 内置识别各类的处置;不写 = 不查这一类。 |
| `exclude` | string[] | 有 | 不检测的路径前缀(末尾 * 可省),最多 32 条。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没保存过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `observe_days` | integer | 有 | 站点按方案新开启时观察多少天(只记录不处置);0 = 不观察直接处置。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/protect-schemes/leak" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/protect-schemes/replay`

获取防重放方案 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/protect-schemes/replay" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/protect-schemes/replay`

保存防重放方案 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | ReplayGuardAction |  | 没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。 可选值: ["block","challenge"] |
| `app_salt` | string |  | 签名盐(应用密钥,32 字节 hex);app_sign 开而没有它 = 签名头一律不认。 |
| `app_sign` | boolean |  | App 签名头模式:请求带签名头即按签名校验,不需要令牌。 |
| `bind_ip` | boolean |  | 令牌再绑客户端 IP(换 IP 即失效)。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没保存过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `methods` | ReplayGuardMethod[] |  | 受保护方法;不写 = POST/PUT/PATCH/DELETE。 |
| `paths` | ReplayGuardPath[] |  | 保护接口路径表,最多 64 条;空 = 不保护。 |
| `ttl_s` | integer |  | 令牌有效期(秒),签名头的时间戳也按它判;不写 = 120。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/protect-schemes/replay" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/protect-schemes/tamper`

获取防篡改方案 · 鉴权: 用户（部分参数仅管理员）

```sh
curl "https://panel.example.com/api/v2/protect-schemes/tamper" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/protect-schemes/tamper`

保存防篡改方案 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | ReplayGuardAction | 有 | 没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。 可选值: ["block","challenge"] |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没保存过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `mode` | string | 有 | 检查范围:structure 仅结构变化;full 整页任意变化。 可选值: ["structure","full"] |
| `observe_days` | integer | 有 | 站点按方案新开启时观察多少天(只记录不处置);0 = 不观察直接处置。 |
| `scopes` | SiteTamperScope[] | 有 | 保护范围,最多 50 条。 |

```sh
curl -X PUT "https://panel.example.com/api/v2/protect-schemes/tamper" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/protect-schemes/{kind}/apply`

把方案批量应用到网站 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `auto_join` | object |  | 「以后新加入范围的网站自动加入方案」的规则;没开时不返回。 |
| `dry_run` | boolean |  | 为 true 只返回会发生什么的计数,不写任何东西。 默认: false |
| `override_custom` | boolean |  | 为 true 时单独设置的网站也改成按方案;缺省不覆盖,计入 skipped_custom。 默认: false |
| `selection` | ProtectSchemeSelection | 有 | 要应用的网站范围。 |

```sh
curl -X POST "https://panel.example.com/api/v2/protect-schemes/{kind}/apply" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/protect-schemes/{kind}/sites`

列出已设置这项防护的网站 · 鉴权: 用户（部分参数仅管理员）

查询参数:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `page` | integer |  | 页码,从 1 开始。 默认: 1 |
| `page_size` | integer |  | 每页条数。 默认: 20 |
| `tenant_id` | integer |  | 仅管理员可用:按租户过滤。租户凭据调用时忽略,只返回本租户数据。 |
| `q` | string |  | 按网站域名或站点名模糊搜索(不区分大小写)。 |
| `status` | ProtectSchemeSiteStatus |  | 按状态过滤。 可选值: ["enabled","disabled","pending","capture_failed"] |
| `source` | ProtectSiteSource |  | 按来源过滤:scheme 按方案;custom 单独设置(含单独关闭)。 可选值: ["scheme","custom"] (只读) |

```sh
curl "https://panel.example.com/api/v2/protect-schemes/{kind}/sites" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/protect-schemes/{kind}/sites/bulk`

批量重设或关闭网站的这项防护 · 鉴权: 用户（部分参数仅管理员）

请求体:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | ReplayGuardAction | 有 | 没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。 可选值: ["block","challenge"] |
| `filter` | ProtectSchemeSiteFilter |  | 与列表同样的过滤条件,服务端展开成网站集合。 |
| `ids` | integer[] |  | 网站 id 列表。 |

```sh
curl -X POST "https://panel.example.com/api/v2/protect-schemes/{kind}/sites/bulk" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

增值防护方案对象:

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `action` | ReplayGuardAction |  | 没有令牌或重放时:block 回 403;challenge 出 JS 挑战。不写 = block。 可选值: ["block","challenge"] |
| `app_salt` | string |  | 签名盐(应用密钥,32 字节 hex);app_sign 开而没有它 = 签名头一律不认。 |
| `app_sign` | boolean |  | App 签名头模式:请求带签名头即按签名校验,不需要令牌。 |
| `applied` | integer |  | 写入(dry_run 时为将写入)的网站数。 |
| `auto_join` | object |  | 「以后新加入范围的网站自动加入方案」的规则;没开时不返回。 (只读) |
| `bind_ip` | boolean |  | 令牌再绑客户端 IP(换 IP 即失效)。 |
| `counts` | ProtectSchemeCounts |  | 站点计数:调用方看得到的站点里,开着的、按方案的、单独设置的各几个。 (只读) |
| `custom` | SiteLeakGuardCustom[] |  | 自定义正则,最多 16 条。 |
| `demoted_sites` | integer |  | 本次保存因属主没开通 WAF 增强、改为单独设置并保留原值的站点数(只在保存的回包里有)。 (只读) |
| `detect` | SiteLeakGuardDetect |  | 内置识别各类的处置;不写 = 不查这一类。 |
| `domain` | string |  | 网站主域名(没有域名时为站点名)。 |
| `dry_run` | boolean |  | 为 true 只返回会发生什么的计数,不写任何东西。 默认: false |
| `enabled` | boolean |  | 是否开着。 |
| `exclude` | string[] |  | 不检测的路径前缀(末尾 * 可省),最多 32 条。 |
| `expected_updated_at` | string |  | 乐观锁:调用方读到的 updated_at(读到为空 = 还没保存过,用 1970-01-01T00:00:00Z)。与库里当前值不等则回 409 stale_version、不保存;不带则不检查。 |
| `failed` | ProtectSchemeFailure[] |  | 没能处理的网站及原因,最多 100 条。 |
| `failed_total` | integer |  | 没能处理的网站总数(failed 被截断时大于其长度)。 |
| `filter` | ProtectSchemeSiteFilter |  | 与列表同样的过滤条件,服务端展开成网站集合。 |
| `gate` | ProtectSchemeGate |  | 方案属主(租户本人或平台)的 WAF 增强判定档:full 可改;readonly、basic 只许减不许增。 可选值: ["full","readonly","basic"] (只读) |
| `ids` | integer[] |  | 网站 id 列表。 |
| `matched` | integer |  | 范围内调用方看得到的网站数。 |
| `methods` | ReplayGuardMethod[] |  | 受保护方法;不写 = POST/PUT/PATCH/DELETE。 |
| `mode` | string |  | 检查范围:structure 仅结构变化;full 整页任意变化。 可选值: ["structure","full"] |
| `observe_days` | integer |  | 站点按方案新开启时观察多少天(只记录不处置);0 = 不观察直接处置。 |
| `observe_until` | integer |  | 观察期截止(Unix 毫秒时间戳);只有防泄露开着且仍在观察期内才有值,已过期、没有观察期、关着或其余方案为空。 |
| `override_custom` | boolean |  | 为 true 时单独设置的网站也改成按方案;缺省不覆盖,计入 skipped_custom。 默认: false |
| `owner` | string |  | 属主用户名。 |
| `paths` | ReplayGuardPath[] |  | 保护接口路径表,最多 64 条;空 = 不保护。 |
| `scopes` | SiteTamperScope[] |  | 保护范围,最多 50 条。 |
| `selection` | ProtectSchemeSelection | 有 | 要应用的网站范围。 |
| `site_id` | integer |  | 网站 id。 |
| `skipped_custom` | integer |  | 因单独设置而没覆盖的网站数(override_custom 为 false)。 |
| `skipped_gate` | integer |  | 因属主 WAF 增强不是 full 而没写的网站数。 |
| `source` | ProtectSiteSource |  | 站点这一项的来源:scheme 按方案(保存方案时跟着变);custom 单独设置(含关闭、存量迁移来的行)。 可选值: ["scheme","custom"] (只读) |
| `status` | ProtectSchemeSiteStatus |  | 站点这一项的状态:enabled 开着;disabled 关着;pending 开着但防篡改基准还在排队采集;capture_failed 开着但基准采集多次失败、已停止重试(只有防篡改有后两种)。 可选值: ["enabled","disabled","pending","capture_failed"] |
| `tenant_id` | integer |  | 属主用户 id。 |
| `today_blocked` | integer |  | 今日(UTC)拦截与换错误页次数,不含观察期内的命中(只有防泄露有,与方案回包 counts.today_blocked 同口径);其余方案、没接 ClickHouse 或查询失败为空。 |
| `today_hits` | integer |  | 今日命中数(防泄露为今日 UTC 非观察期的打码与拦截次数之和,即 today_masked + today_blocked,防篡改为今日检出篡改的页数);防重放为空。 |
| `today_masked` | integer |  | 今日(UTC)打码次数,不含观察期内的命中(只有防泄露有,与方案回包 counts.today_masked 同口径);其余方案、没接 ClickHouse 或查询失败为空。 |
| `ttl_s` | integer |  | 令牌有效期(秒),签名头的时间戳也按它判;不写 = 120。 |
| `updated_at` | string |  | 版本(没保存过为空);修改时用 expected_updated_at。 (只读) |
| `updated_sites` | integer |  | 本次保存一并改到的按方案站点数(只在保存的回包里有)。 (只读) |
