Xiuno BBS 重构记录贴(16)安全防护、验证码及审核系统
贰先生 1小时前

# 安全防护、验证码及审核系统

## 概述
Xiuno BBS 4.5+ 内置统一安全防护系统,涵盖验证码、敏感词过滤、内容审核、发帖限制、账号安全、搜索限制等功能。所有安全逻辑直接集成在核心路由中,不依赖外部插件。

## 架构

```
lib/security/
├── AuditService.php           # 审核服务(待审列表、通过、驳回)
├── CaptchaService.php         # 验证码服务(生成、验证、配置)
├── ContentModerationService.php # 内容安全审核(pass/review/block)
├── SecurityConfigService.php  # 安全配置读写(kv存储 + conf.php同步)
├── SecurityService.php        # 安全增强(模糊错误、登录提示)
├── SensitiveWordFilter.php    # 敏感词过滤(Trie树)
├── IpBlacklistService.php     # IP黑白名单
├── EmailBlacklistService.php  # 邮箱域名黑名单
├── LoginSecurityService.php   # 登录安全(锁定、计数)
└── PermissionService.php      # 权限检查
```

安全检查代码直接嵌入核心路由文件的 `// hook` 位置,按顺序执行,任何检查失败即 `message(-1, ...)` 中断请求。

## 一、验证码系统

### 服务类
`lib/security/CaptchaService.php`

### 接口
| 方法 | 说明 |
|------|------|
| `CaptchaService::generate($scene)` | 生成验证码图片 |
| `CaptchaService::verify($scene, $input)` | 验证用户输入 |
| `CaptchaService::is_enabled($scene)` | 检查场景是否开启 |
| `CaptchaService::get_config()` | 获取验证码配置 |
| `CaptchaService::save_config($config)` | 保存验证码配置 |

### 支持场景
| 场景 | 标识 | 检查位置 |
|------|------|----------|
| 登录 | `login` | `route/user.php` — `user_login_post_start` |
| 注册 | `register` | `route/user.php` — `user_create_post_start` |
| 发帖/回帖 | `post` | `route/thread.php` — `thread_create_thread_start`<br>`route/post.php` — `post_post_start` |
| 找回密码 | `resetpw` | `route/user.php` — `user_resetpw_post_start` |

### 验证码类型
- **图片验证码**:字母数字混合,GD 库生成
- **算术验证码**:简单加减法

### 前端集成
- Alpine.js `captchaComponent` 组件:管理验证码图片、输入、刷新、错误提示
- 每次表单提交后自动刷新验证码(无论成功或失败)
- 验证码错误时显示行内红色提示 + toast 通知 + 自动刷新图片

### 配置存储
- 键名:`security_captcha_config`(存储在 `bbs_kv` 表)
- 后台管理:`/admin/?security-captcha.htm`

### 扩展点
插件可定义全局函数覆盖默认实现:
- `security_captcha_generate_{scene}` — 覆盖验证码生成
- `security_captcha_verify_{scene}` — 覆盖验证码验证

## 二、敏感词过滤

### 服务类
`lib/security/SensitiveWordFilter.php`

### 接口
| 方法 | 说明 |
|------|------|
| `SensitiveWordFilter::content_filter($text, $scene)` | 过滤文本,返回 `['pass'=>bool, 'matched_keywords'=>array]` |
| `SensitiveWordFilter::add_word($word)` | 添加敏感词 |
| `SensitiveWordFilter::delete_word($word)` | 删除敏感词 |
| `SensitiveWordFilter::batch_import($words_text)` | 批量导入(每行一个词) |
| `SensitiveWordFilter::get_all_words()` | 获取所有敏感词 |
| `SensitiveWordFilter::clear_words()` | 清空词库 |
| `SensitiveWordFilter::test($text)` | 测试过滤效果 |

### 实现
- Trie 树算法,支持 10w+ 词库高效匹配
- 词库文件:`config/sensitive_words.txt`(每行一个词,# 开头为注释)

### 检查位置
| 操作 | 位置 | 行为 |
|------|------|------|
| 发帖 | `route/thread.php` — `thread_create_thread_start` | 命中则直接拒绝 |
| 回帖 | `route/post.php` — `post_post_start` | 命中则直接拒绝 |

### 后台管理
`/admin/?security-words.htm`

## 三、内容安全审核

### 服务类
`lib/security/ContentModerationService.php`

### 接口
| 方法 | 说明 |
|------|------|
| `ContentModerationService::moderate($type, $content, $scene)` | 审核内容,返回 `pass`/`review`/`block` |

### 返回值含义
| 返回值 | 含义 | 系统行为 |
|--------|------|----------|
| `pass` | 内容安全 | 正常发布 |
| `review` | 需人工审核 | 帖子进入待审状态(`audit_status=0`) |
| `block` | 内容违规 | 直接拒绝发布 |

### 检查位置
| 操作 | 位置 | block 行为 | review 行为 |
|------|------|-----------|-------------|
| 发帖 | `route/thread.php` — `thread_create_thread_start` | 直接拒绝 | 设置 `$_SESSION['security_thread_needs_audit']` |
| 回帖 | `route/post.php` — `post_post_start` | 直接拒绝 | 设置 `$_SESSION['security_post_needs_audit']` |

### 扩展点
插件可定义 `security_moderation_check($type, $content, $scene)` 函数覆盖默认实现。

## 四、帖子审核

### 服务类
`lib/security/AuditService.php`

### 接口
| 方法 | 说明 |
|------|------|
| `AuditService::need_audit($fid, $gid, $subject, $message)` | 判断是否需要审核 |
| `AuditService::need_post_audit($fid, $gid, $message)` | 判断回帖是否需要审核 |
| `AuditService::get_pending_list($type, $page, $pagesize)` | 获取待审列表 |
| `AuditService::approve($target_type, $target_id, $uid)` | 审核通过 |
| `AuditService::reject($target_type, $target_id, $uid, $reason)` | 审核驳回 |
| `AuditService::batch_approve($target_type, $ids, $uid)` | 批量通过 |
| `AuditService::batch_reject($target_type, $ids, $uid, $reason)` | 批量驳回 |
| `AuditService::get_audit_logs($page, $pagesize)` | 获取审核日志 |

### 三级审核规则
1. **版块级**:`bbs_forum.audit_thread = 1` → 该版块新主题需审核
2. **用户组级**:`bbs_group.allow_direct_post = 0` → 该用户组帖子需审核
3. **关键词级**:命中敏感词或 ContentModerationService 返回 `review` → 自动进入审核

### 额外审核触发条件(核心路由内置)
- **新用户前N帖需审核**:`security_new_user_audit_count` 配置项,新注册用户发帖数未达阈值时自动进入审核
- **内容审核服务**:`ContentModerationService::moderate()` 返回 `review` 时自动进入审核

### 审核状态字段
| 字段 | 值 | 含义 |
|------|-----|------|
| `audit_status` | 0 | 待审核 |
| `audit_status` | 1 | 已通过 |
| `audit_status` | 2 | 已驳回 |

### 待审内容可见性规则
| 用户类型 | 可见范围 |
|----------|----------|
| 管理员(gid=1,2) | 可见所有待审内容 |
| 普通用户(gid>2) | 仅可见自己发布的待审内容 |
| 游客(gid=0) | 不可见任何待审内容 |

### 过滤函数
- `thread_list_access_filter($threadlist, $gid)` — 帖子列表过滤(`model/thread.func.php`)
- `post_list_access_filter($postlist, $gid)` — 回帖列表过滤(`model/post.func.php`)
- 帖子详情页:`route/thread.php` 中单独检查访问权限

### 审核通知
帖子/回帖进入审核后,通过 `notify_create()` 向作者发送 `audit_pending` 通知。

### 后台管理
`/admin/?security-audit.htm`

## 五、安全防护设置

### 服务类
`lib/security/SecurityConfigService.php`

### 配置项一览

#### 发帖限制
| 配置键 | 默认值 | 说明 |
|--------|--------|------|
| `security_post_thread_interval` | 60 | 发帖最小间隔(秒),0=不限制 |
| `security_post_reply_interval` | 30 | 回帖最小间隔(秒),0=不限制 |
| `security_post_min_length` | 10 | 发帖最低字数,0=不限制 |
| `security_reply_min_length` | 5 | 回帖最低字数,0=不限制 |
| `security_post_max_length` | 50000 | 发帖最高字数,0=不限制 |
| `security_same_thread_reply_interval` | 0 | 同主题连续回复间隔(秒),0=不限制 |
| `security_new_user_audit_count` | 0 | 新用户前N帖需审核,0=关闭 |

#### 账号安全
| 配置键 | 默认值 | 说明 |
|--------|--------|------|
| `security_ip_register_interval` | 24 | 同一IP注册间隔(小时),0=不限制 |
| `security_password_max_retries` | 5 | 密码错误重试次数,0=不限制 |
| `security_lockout_duration` | 15 | 锁定时间(分钟) |
| `security_password_min_length` | 6 | 密码最小长度 |
| `security_password_complexity` | none | 密码复杂度:none/number/mixed/special |
| `security_allowed_email_domains` | (空) | 邮箱域名白名单,逗号分隔,空=不限制 |

> `security_password_max_retries` 和 `security_lockout_duration` 会自动同步到核心配置 `login_max_attempts` 和 `login_ban_duration`(秒)。

#### 内容权限
| 配置键 | 默认值 | 说明 |
|--------|--------|------|
| `security_allow_edit` | 1 | 允许修改帖子,0=禁止 |
| `security_edit_time_limit` | 60 | 修改有效时间(分钟),0=永久 |
| `security_allow_delete` | 0 | 允许删除帖子,0=禁止 |
| `security_delete_time_limit` | 0 | 删除有效时间(分钟),0=不可删除 |
| `security_allow_delete_reply` | 0 | 允许删除回复,0=禁止 |

#### 上传限制
| 配置键 | 默认值 | 说明 |
|--------|--------|------|
| `security_avatar_upload_limit` | 3 | 头像上传次数限制 |
| `security_avatar_max_size` | 512 | 头像文件最大尺寸(KB) |

#### 搜索限制
| 配置键 | 默认值 | 说明 |
|--------|--------|------|
| `security_search_interval` | 10 | 搜索间隔(秒),0=不限制 |
| `security_search_require_login` | 1 | 搜索需要登录,0=不需要 |

### 配置存储
- 安全配置存储在 `bbs_kv` 表,键名以 `security_` 开头
- `SecurityConfigService::get($key, $default)` — 读取配置
- `SecurityConfigService::save_config($config)` — 批量保存配置
- 部分配置(如登录锁定参数)通过 `file_replace_var()` 同步写入 `conf/conf.php`

### 后台管理
`/admin/?security-protection.htm`

## 六、登录安全

### 服务类
`lib/LoginSecurityService.php`

### 功能
- 密码错误计数:记录在 `bbs_user.login_attempts` 字段
- 账号锁定:达到最大重试次数后设置 `bbs_user.banned_until` 字段
- 锁定检查:`LoginSecurityService::checkBan()` — 锁定时返回错误消息
- 前端联动:锁定时禁用登录按钮 + 倒计时

### 核心配置
| 配置 | 来源 | 说明 |
|------|------|------|
| `login_max_attempts` | `conf/conf.php` | 最大重试次数(与 `security_password_max_retries` 同步) |
| `login_ban_duration` | `conf/conf.php` | 锁定时长秒数(与 `security_lockout_duration` 同步,分钟→秒) |

## 七、安全检查执行流程

### 发帖流程
```
route/thread.php — thread_create
  │
  ├─ // hook thread_create_thread_start
  │   ├─ 验证码检查(CaptchaService)
  │   ├─ 敏感词过滤(SensitiveWordFilter)→ 命中则拒绝
  │   ├─ 内容安全审核(ContentModerationService)→ block拒绝 / review标记审核
  │   ├─ 发帖间隔检查(SecurityConfigService)
  │   ├─ 发帖字数检查(SecurityConfigService)
  │   ├─ 新用户审核判断(SecurityConfigService)→ 标记 $_SESSION
  │   └─ 内容审核服务触发(review → 标记 $_SESSION)
  │
  ├─ 核心审核判断(AuditService::need_audit)+ 读取 $_SESSION 标记
  │   └─ 设置 thread.audit_status
  │
  ├─ 保存帖子
  │
  └─ // hook thread_create_thread_end
      └─ 审核通知($_SESSION 标记存在时通知作者)
```

### 回帖流程
```
route/post.php — post_create
  │
  ├─ // hook post_post_start
  │   ├─ 验证码检查(CaptchaService)
  │   ├─ 敏感词过滤(SensitiveWordFilter)→ 命中则拒绝
  │   ├─ 内容安全审核(ContentModerationService)→ block拒绝 / review标记审核
  │   ├─ 回帖间隔检查(SecurityConfigService)
  │   ├─ 同主题连续回复间隔检查(SecurityConfigService)
  │   ├─ 回帖字数检查(SecurityConfigService)
  │   └─ 内容审核服务触发(review → 标记 $_SESSION)
  │
  ├─ 核心审核判断(AuditService::need_post_audit)+ 读取 $_SESSION 标记
  │   └─ 设置 post.audit_status
  │
  ├─ 保存回帖
  │
  └─ // hook post_post_end
      └─ 审核通知($_SESSION 标记存在时通知作者)
```

### 注册流程
```
route/user.php — user_create
  │
  └─ // hook user_create_post_start
      ├─ 验证码检查(CaptchaService)
      ├─ 同一IP注册间隔检查(SecurityConfigService + kv)
      └─ 邮箱域名白名单检查(SecurityConfigService)
```

### 登录流程
```
route/user.php — user_login
  │
  ├─ // hook user_login_post_start
  │   └─ 验证码检查(CaptchaService)
  │
  └─ 核心登录逻辑
      └─ LoginSecurityService::checkBan() → 锁定检查
```

### 搜索流程
```
route/search.php — search
  │
  └─ // hook search_start
      ├─ 搜索需登录检查(SecurityConfigService)
      └─ 搜索频率限制(SecurityConfigService + kv)
```

### 修改/删除流程
```
route/post.php — post_update
  └─ // hook post_update_post_start
      ├─ 修改权限开关检查
      └─ 修改时间限制检查

route/post.php — post_delete
  └─ // hook post_delete_start
      ├─ 删除权限开关检查
      └─ 删除时间限制检查
```

## 八、数据库字段

### bbs_thread
| 字段 | 类型 | 说明 |
|------|------|------|
| `audit_status` | tinyint | 0=待审 / 1=通过 / 2=驳回 |

### bbs_post
| 字段 | 类型 | 说明 |
|------|------|------|
| `audit_status` | tinyint | 0=待审 / 1=通过 / 2=驳回 |

### bbs_user
| 字段 | 类型 | 说明 |
|------|------|------|
| `login_attempts` | int | 登录失败次数 |
| `banned_until` | int | 锁定截止时间戳 |

### bbs_forum
| 字段 | 类型 | 说明 |
|------|------|------|
| `audit_thread` | tinyint | 版块是否审核发帖 |

### bbs_group
| 字段 | 类型 | 说明 |
|------|------|------|
| `allow_direct_post` | tinyint | 用户组是否免审核发帖 |

### bbs_kv
| 键名 | 说明 |
|------|------|
| `security_captcha_config` | 验证码配置 |
| `security_*` | 各安全配置项 |
| `security_ip_register_{ip}` | IP注册时间记录 |
| `security_search_time_{uid/ip}` | 搜索时间记录 |
| `security_avatar_upload_count_{uid}` | 头像上传计数 |

## 九、后台管理页面

| 页面 | URL | 功能 |
|------|-----|------|
| 防护设置 | `/admin/?security-protection.htm` | 发帖限制、账号安全、内容权限、上传限制 |
| 验证码设置 | `/admin/?security-captcha.htm` | 各场景验证码开关和类型 |
| 敏感词库 | `/admin/?security-words.htm` | 添加/删除/导入/测试敏感词 |
| 内容审核 | `/admin/?security-audit.htm` | 待审列表、通过/驳回、审核日志 |
| 黑名单 | `/admin/?security-blacklist.htm` | IP黑白名单、邮箱黑名单 |

## 十、扩展点

所有模块提供函数级 hook 扩展点,插件可定义全局函数覆盖默认实现:

| 函数名 | 用途 |
|--------|------|
| `security_captcha_generate_{scene}` | 覆盖验证码生成 |
| `security_captcha_verify_{scene}` | 覆盖验证码验证 |
| `security_moderation_check($type, $content, $scene)` | 覆盖内容审核 |
| `security_verify_action($uid, $action)` | 覆盖敏感操作验证 |
最新回复 (0)
全部楼主
返回