mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 14:06:36 +08:00
[优化] POW 系统接口方案
This commit is contained in:
+3
-2
@@ -1,4 +1,4 @@
|
||||
import { defineAdditionalConfig, type DefaultTheme } from 'vitepress'
|
||||
import {type DefaultTheme, defineAdditionalConfig} from 'vitepress'
|
||||
|
||||
export default defineAdditionalConfig({
|
||||
description:
|
||||
@@ -129,7 +129,8 @@ function sidebarDesign(): DefaultTheme.SidebarItem[] {
|
||||
{ text: '内网穿透隧道设计', link: 'tunnel-design' },
|
||||
{ text: 'WAF 设计', link: 'waf-design' },
|
||||
{ text: 'Pages 静态托管设计', link: 'pages-design' },
|
||||
{ text: 'Uptime Kuma 监控同步设计', link: 'kuma-design' }
|
||||
{ text: 'Uptime Kuma 监控同步设计', link: 'kuma-design' },
|
||||
{ text: '登录验证码设计', link: 'login-captcha' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -65,7 +65,7 @@ OpenResty (Agent, TLS/WAF)
|
||||
|
||||
| 组件 | 职责 | 详细设计参考 |
|
||||
| --------------- | ---------------------------------------------------------------------- | ------------ |
|
||||
| **Server** | 管理端 UI/API、控制面状态持久化、配置编译渲染、发布版本控制、Pages 部署包存储与 Uptime Kuma 监控同步 | [Agent 与发布模型](./agent-design.md) / [Uptime Kuma 监控同步设计](./kuma-design.md) |
|
||||
| **Server** | 管理端 UI/API、控制面状态持久化、配置编译渲染、发布版本控制、Pages 部署包存储、Uptime Kuma 监控同步与登录验证码防护 | [Agent 与发布模型](./agent-design.md) / [Uptime Kuma 监控同步设计](./kuma-design.md) / [登录验证码设计](./login-captcha.md) |
|
||||
| **Agent** | 周期心跳与 WS 同步、静态资源包拉取与解压、OpenResty 配置写入/校验/重载与自愈 | [Agent 与发布模型](./agent-design.md) |
|
||||
| **OpenResty** | 接收真实流量,执行 WAF 过滤、PoW 防护、Basic Auth 认证与静态/反代服务 | [WAF 设计](./waf-design.md) / [Pages 设计](./pages-design.md) |
|
||||
| **Relay** | 部署于边缘节点,管理 `frps` 守护进程生命周期,接受心跳派发的穿透中继配置 | [内网穿透设计](./tunnel-design.md) |
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
# 登录验证码设计 (Login CAPTCHA Integration)
|
||||
|
||||
本文档阐述在 OpenFlare 控制面中引入基于 Proof-of-Work (PoW) 与无感浏览器指纹特征的开源 CAPTCHA 方案 —— Cap,以防止对登录 API 进行暴力破解与爬虫撞库攻击的设计。
|
||||
|
||||
---
|
||||
|
||||
## 1. 业务背景与产品范围
|
||||
|
||||
### 背景与痛点
|
||||
根据我们的系统安全分析,OpenFlare 的登录端点 `/api/user/login` 虽然配置了基于 IP 的限流限制,但由于缺少用户维度的防护机制,攻击者可使用代理池绕过 IP 限制对高权限账户(如 `root`)实施撞库和暴力破解。同时,对于系统登录页面,标准的视觉验证码对用户体验和无障碍不够友好。
|
||||
|
||||
### 产品范围与技术选型
|
||||
* **技术选型**:Cap (Proof-of-Work 驱动的无感无图像验证码解决方案)。
|
||||
- **核心原理**:客户端(Widget/网页)从服务器获取工作量证明 (PoW) 的难题,使用浏览器后台计算求解并将答案回传。服务器验证答案的正确性,完成人机识别。
|
||||
- **优势**:无感、无图像验证、不依赖任何外部第三方 API 节点(私密)、包极小。
|
||||
* **接入范围**:控制面 Server 登录 API(`/api/user/login`)以及前端登录页面。
|
||||
* **配置粒度**:支持管理员通过控制台 Option 表随时开启/关闭验证码(`CapLoginEnabled`)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 系统架构与交互时序
|
||||
|
||||
### 2.1 模块分工
|
||||
1. **Frontend (前端)**:
|
||||
* 在登录页面引入 `cap-widget`(React 19 自定义元素)。
|
||||
* 提交表单时,伴随提交由 Widget 求解出并得到的 `cap-token`。
|
||||
2. **Server (控制面后端)**:
|
||||
* 暴露 `POST /api/cap/challenge` 接口,为客户端分发 PoW 难题和签名的 JWT Token。
|
||||
* 暴露 `POST /api/cap/redeem` 接口,校验客户端提交的 PoW 解答并核发带有失效时间的登录凭证(Redeem Token)。
|
||||
* 将 Redeem Token 与对应过期时间保存在内存缓存/Redis 缓存中。
|
||||
* 在 `POST /api/user/login` 接口中,若启用了验证码保护,先校验并消耗(单次失效)对应的 `cap-token`。
|
||||
|
||||
### 2.2 验证流时序图
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor User as 用户
|
||||
participant Browser as 浏览器 (前端 Web)
|
||||
participant Server as OpenFlare Server (后端)
|
||||
participant Cache as 内存/Redis 缓存
|
||||
|
||||
User->>Browser: 打开登录页面
|
||||
Browser->>Server: POST /api/cap/challenge (获取难题)
|
||||
Server->>Browser: 返回 {challenge, token, expires} (JWT 格式)
|
||||
Note over Browser: Widget 在后台(WASM/Worker)执行 PoW 难题计算
|
||||
Browser->>Server: POST /api/cap/redeem (提交 solutions + token)
|
||||
alt 校验 PoW 解答通过
|
||||
Server->>Cache: 存储 Redeem Token (tokenKey:expires)
|
||||
Server->>Browser: 返回 {success: true, token} (即 cap-token)
|
||||
else 校验失败
|
||||
Server->>Browser: 返回 {success: false, reason}
|
||||
end
|
||||
User->>Browser: 输入账号密码,点击登录
|
||||
Browser->>Server: POST /api/user/login (在 HTTP 请求头中携带 X-Cap-Token)
|
||||
alt CapLoginEnabled = true
|
||||
Server->>Server: Middleware (CapAuth) 校验并消费 X-Cap-Token
|
||||
alt token 合法且未过期且未被消费
|
||||
Server->>Server: c.Next() -> 执行常规登录逻辑 (密码 Bcrypt 校验)
|
||||
Server->>Browser: 返回登录成功 (JWT session)
|
||||
else token 无效或已被消费
|
||||
Server->>Browser: 拦截并返回验证码错误 (401 Unauthorized)
|
||||
end
|
||||
else CapLoginEnabled = false
|
||||
Server->>Server: c.Next() -> 执行常规登录逻辑
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心接口与数据模型
|
||||
|
||||
### 3.1 接口定义
|
||||
|
||||
#### 1. 获取难题 (GET/POST /api/cap/challenge)
|
||||
* **请求方式**:`POST`
|
||||
* **接口权限**:公开
|
||||
* **响应负载**:
|
||||
```json
|
||||
{
|
||||
"challenge": {
|
||||
"c": 50,
|
||||
"s": 32,
|
||||
"d": 4
|
||||
},
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjIjo1MCwicyI6MzIsImQiOjQsImV4cCI6MTcxNzY2MDgwMCwiaWF0IjoxNzE3NjYwMjAwLCJuIjoiMGExYjJjM2Q0ZTVmNiJ9.signature",
|
||||
"expires": 1717660800000
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 核销难题 (POST /api/cap/redeem)
|
||||
* **请求方式**:`POST`
|
||||
* **请求负载**:
|
||||
```json
|
||||
{
|
||||
"token": "challenge_jwt_token_here",
|
||||
"solutions": [12345, 67890, 54321]
|
||||
}
|
||||
```
|
||||
* **响应负载 (成功)**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"token": "random_id:ver_token",
|
||||
"expires": 1717661000000
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 登录接口 (POST /api/user/login)
|
||||
* **请求负载保持不变**:
|
||||
```json
|
||||
{
|
||||
"username": "root",
|
||||
"password": "your_password"
|
||||
}
|
||||
```
|
||||
* **验证码载体**:放置于 HTTP Request Header `X-Cap-Token` 中。
|
||||
|
||||
---
|
||||
|
||||
## 4. 重放攻击防护与安全性权衡
|
||||
1. **JWT 临时状态绑定**:难题在生成时就被签入 JWT payload,包含过期时间限制(10 分钟)。
|
||||
2. **Replay 拦截(Nonce 消耗)**:当客户端调用 `/redeem` 提交解答时,后端在缓存中标记该 JWT Signature 已使用。重复提交相同的解密包将返回 `already_redeemed`。
|
||||
3. **Redeem 一次性核销(单次失效)**:当客户端登录并提交 `cap-token` 时,后端在检验到合法性后立即从缓存中删除该 Key,防止黑客提取历史正确的 `cap-token` 进行重放登录。
|
||||
4. **验证机制无感化**:通过调整 `c (难题数)=50`,`d (难度)=4`,普通用户在桌面端和移动端只需 0.5 秒至 1.5 秒即可静默解出,极大地兼顾了用户体验和反爬效果。
|
||||
@@ -0,0 +1,92 @@
|
||||
# 登录集成 Cap 验证码实现计划
|
||||
|
||||
本计划规定了在 OpenFlare 系统的登录流程中集成 Cap(基于 Proof-of-Work 和无感浏览器检测的验证码)的具体开发步骤。
|
||||
|
||||
---
|
||||
|
||||
## 1. 目标与背景 (Goal & Context)
|
||||
|
||||
### 需求背景
|
||||
为解决安全分析中识别到的“登录接口缺少防暴力破解/撞库逻辑”这一安全风险,我们需要在登录接口中集成 Cap 验证码服务。通过让客户端(爬虫/浏览器)在登录前必须求解一个 PoW 工作量难题并核销,显著提高恶意爬虫爆破的计算成本,从根本上防止针对登录接口的恶意爆破。
|
||||
|
||||
### 开发范围
|
||||
1. **后端验证服务**:在 Server 端移植 `capjs-core` 的 PoW 校验算法(包括 FNV-1a、自定义 PRNG、SHA-256 检验、JWT 难题派发与核销缓存组件)。
|
||||
2. **公开路由映射**:
|
||||
* `POST /api/cap/challenge` (分发难题)
|
||||
* `POST /api/cap/redeem` (核销难题并核发 `cap-token`)
|
||||
3. **控制开关**:增加全局选项 `CapLoginEnabled`,管理员可动态启停。
|
||||
4. **前端交互接入**:在登录页面引入 `cap-widget` 自定义组件,并在提交登录请求时附带 `cap_token`。
|
||||
|
||||
---
|
||||
|
||||
## 2. 设计与决策 (Design & Decisions)
|
||||
|
||||
### 核心对象与数据模型
|
||||
本方案不涉及复杂数据库结构重构,但需要:
|
||||
1. 在 `options` 表中保存 `CapLoginEnabled` (true/false) 选项, 默认为 True, 设置路径在 设置->系统设置->登录与注册开关。
|
||||
2. 建立一个全局的、线程安全的内存验证码核销存储/核销缓存,具备过期清理功能,用于存放核销的 `cap-token` 以及消费过的 JWT 难题 Nonce(Signature),支持 Redis 与本地内存模式。
|
||||
|
||||
### API 与鉴权设计
|
||||
1. **`POST /api/cap/challenge`**:公开接口。
|
||||
2. **`POST /api/cap/redeem`**:公开接口。
|
||||
3. **`POST /api/user/login`**:接受可选/必选的 `cap_token` 参数。
|
||||
|
||||
### 算法移植 (Proof-of-Work Go 实现)
|
||||
* FNV-1a 状态机复现。
|
||||
* 伪随机数生成器 (PRNG) 与 `strings.HasPrefix(sha256Hex, target)` 校验。
|
||||
|
||||
---
|
||||
|
||||
## 3. 具体修改文件清单 (Proposed Changes)
|
||||
|
||||
### 后端 Server
|
||||
* #### [MODIFY] [constants.go](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/common/constants.go)
|
||||
* 增加 `CapLoginEnabled` 全局常量/变量,默认 `true`。
|
||||
* #### [MODIFY] [option.go](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/model/option.go)
|
||||
* 在 `InitOptionMap` 和 `updateOptionMap` 中添加 `CapLoginEnabled` 的支持。
|
||||
* #### [NEW] [prng.go (utils/cap)](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/utils/cap/prng.go)
|
||||
* 职责:实现 FNV-1a、FNV-1a resume 及 XORShift-based 自定义 PRNG 伪随机数算法。
|
||||
* #### [NEW] [cap.go (utils/cap)](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/utils/cap/cap.go)
|
||||
* 职责:实现无状态 PoW 难题生成、验证及 JWT 校验。
|
||||
* #### [NEW] [store.go (utils/cap)](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/utils/cap/store.go)
|
||||
* 职责:定义 `Store` 接口并提供默认的高性能、线程安全的内存 TTL 缓存核销存储实现。
|
||||
* #### [NEW] [manager.go (utils/cap)](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/utils/cap/manager.go)
|
||||
* 职责:封装验证码的核心逻辑,暴露出 `Generate`、`Redeem` 与 `VerifyToken` 高阶 API。
|
||||
* #### [NEW] [middleware.go (utils/cap)](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/utils/cap/middleware.go)
|
||||
* 职责:实现通用的 Gin 中间件 `VerifyMiddleware`。其不依赖任何 OpenFlare 业务代码,完全通过构造注入。
|
||||
* #### [NEW] [cap.go (service)](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/service/cap.go)
|
||||
* 职责:适配器服务,将 OpenFlare 的全局参数(如 `JWTSecret`、`CapLoginEnabled`、`RDB`)注入并实例化全局的 `CapManager` 实例。
|
||||
* #### [NEW] [cap.go (middleware)](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/middleware/cap.go)
|
||||
* 职责:极简的适配器中间件,直接调用并返回 `service.CapManager.VerifyMiddleware(scope)`。
|
||||
* #### [NEW] [cap.go (controller)](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/controller/cap.go)
|
||||
* 职责:实现 `GetCapChallenge` 和 `RedeemCapChallenge` 控制器。
|
||||
* #### [MODIFY] [api-router.go](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/router/api-router.go)
|
||||
* 职责:挂载 `/api/cap/challenge` 和 `/api/cap/redeem` 路由,并在 `/api/user/login` 上应用 `middleware.CapAuth("login")`。
|
||||
* #### [MODIFY] [user.go (controller)](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/controller/user.go)
|
||||
* 无需修改:登录控制器和入参结构体保持完全无侵入。
|
||||
* #### [MODIFY] [misc.go](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/controller/misc.go)
|
||||
* 职责:在 `GetStatus` 中返回 `cap_login_enabled` 开关状态。
|
||||
|
||||
### 前端 Web
|
||||
* #### [MODIFY] [public-status.ts](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/web/types/public-status.ts)
|
||||
* 添加 `cap_login_enabled: boolean` 字段。
|
||||
* #### [MODIFY] [auth.ts](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/web/types/auth.ts)
|
||||
* 在 `LoginPayload` 中添加可选的 `cap_token?: string` 属性。
|
||||
* #### [MODIFY] [login-form.tsx](file:///Users/ryan/DEV/Go/OpenFlare/openflare-server/web/features/auth/components/login-form.tsx)
|
||||
* 动态载入 `cap-widget`(脚本 CDN:`https://cdn.jsdelivr.net/npm/cap-widget`)。
|
||||
* 若后台返回 `cap_login_enabled === true`,则渲染 `<cap-widget data-cap-api-endpoint="/api/cap/" />` 组件。
|
||||
* 在表单提交时,将 `cap-token` 塞入 `loginMutation` 的 Payload 中提交。
|
||||
|
||||
---
|
||||
|
||||
## 4. 验证计划 (Verification Plan)
|
||||
|
||||
### 自动化单元测试
|
||||
* 针对 Go 中的 PoW 核心算法,编写单测 `openflare-server/service/cap_test.go`。
|
||||
* 运行单测命令:`go test -v ./openflare-server/service/...`
|
||||
|
||||
### 手动功能与防暴力破解验证
|
||||
1. 打开控制台选项开启 `CapLoginEnabled`。
|
||||
2. 访问登录页面,观察人机验证组件静默加载并完成 PoW 计算,输入正确账户成功登录。
|
||||
3. 使用 `curl` 模拟恶意爬虫不携带或携带错误的 `cap_token` 对登录 API 发起 POST 请求,预期被拦截并返回“验证码错误”。
|
||||
4. 使用已被核销的同一 `cap_token` 二次请求登录,验证防重放失效机制。
|
||||
Reference in New Issue
Block a user