Files
lisglosips/docs/S29_PERFORMANCE_FAULT_SECURITY_REPORT.md

59 lines
6.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# S29 性能、故障与安全测试报告
## 测试范围
- 环境:本地 KVM 开发环境,A/B/T 通过 Tailscale 联调。
- 范围:小规模 CPS、并发、录音搬运、CDR/Recording Worker 恢复、Redis/MySQL 短故障、API 越权、重放与 SIP 非法来源/超 CPS 探针。
- 约束:不做长时间满载压测,不删除 S28 验收数据,不禁用 SSH 密钥登录,不提前执行 S30。
## 执行记录
### 1. 基线健康检查
- B`lisglosips@api``lisglosips@cdr-worker``lisglosips@recording-worker``mysql``redis-server``heplify-server``grafana-server``lisglosips-prometheus.service` 均 activeAPI `/api/v2/health/ready` 返回 `ok`Prometheus 实际项目服务 `lisglosips-prometheus.service` 返回 ready。
- A`opensips``rtpengine-daemon``rtpengine-recording-daemon``lisglosips-redis-auth-proxy``lisglosips-recording-finalize.timer` 均 active。
- T`lisglosips-s28-uas``opensips` 均 active。
### 2. CPS/并发/录音
- 5 路并发呼叫:T 同时发起 5 路 S28 呼叫,均收到 `100 Giving it a try``200 OK`、BYE `200 OK`,用时约 11.92 秒;B 端生成 5 条 raw CDR、5 条 rated CDR、5 条 READY 录音,录音大小均为 55758 bytes。
- 12 路短突发:T 同时发起 12 路短持话呼叫,均收到 `100 Giving it a try``200 OK`、BYE `200 OK`,用时约 2.13 秒;B 端核对 `raws=12``rated=12``recordingsReady=12``totalDuration=72`、录音大小 `55758-56078` bytes。
- 修复项:T 呼叫脚本原默认固定 `--local-port 50621`,并发时出现 `OSError: [Errno 98] Address already in use`;已改为默认 `--local-port 0` 并在 socket bind 后用实际端口生成 Via/Contact。复测 5 路和 12 路并发均通过。
### 3. Worker 与数据服务故障
- Recording Worker 故障:停止 B `lisglosips@recording-worker` 后发起呼叫,通话成功;恢复 worker 后自动搬运并入库录音,`recordings.status=READY`,大小 55758 bytes。
- CDR Worker 故障:停止 B `lisglosips@cdr-worker` 后发起呼叫,Redis consumer group 出现 `lag=1`MySQL 无 raw CDR;恢复 worker 后 `pending=0``lag=0`raw/rated CDR 正常落库。
- Redis 故障:停止 B `redis-server` 后,A 返回 `503 Redis Unavailable`,符合保护预期;恢复 Redis 后 A 热路径仍持续返回 503,重启 A `lisglosips-redis-auth-proxy` 无效,重启 A `opensips` 后恢复,复测呼叫成功。
- MySQL 故障:停止 B `mysql` 后发起呼叫,SIP 通话成功但 CDR 入库失败。修复后复测:MySQL 恢复并等待 pending idle 窗口后,CDR Worker 自动处理 pending Redis IDraw/rated CDR 正常入库,无新增 deadletter。
### 4. Web/API 安全
- 未认证访问 `/api/v2/users` 返回 `401 AUTH_REQUIRED`
- 质检角色测试用户 `usr_s29_quality_only` 访问 `/api/v2/users` 返回 `403 RBAC_FORBIDDEN`
- 未认证访问录音播放 `/api/v2/recordings/:id/play` 返回 `401 AUTH_REQUIRED`
- 伪造录音 ID `..etcpasswd` 通过认证访问播放接口返回 `404 RECORDING_NOT_READY`,未泄露文件内容。
- 充值重放:对 `cus_s28_t` 使用同一 `idempotencyKey=s29-replay-cus-s28-000001` 连续 POST 两次 `0.000001` 充值,两次返回同一充值 ID `rch_da0bba1c7b1d44428ab92d77a55e503d`;数据库核对 `customer_recharges.rows=1``idempotency_keys.rows=1`、余额只从 `99.748000` 增加到 `99.748001`
### 5. SIP 安全探针
- 从 B `100.90.90.91` 向 A `100.90.90.90:15060/udp` 发送非法来源 INVITECall-ID `s29-illegal-1782094573-3991@lisglosips-b`,客户端等待 3 秒无 SIP 响应;A OpenSIPS 最近日志未出现该 Call-ID。该结果说明非允许来源未进入当前业务路由;因无 OpenSIPS 层日志,保守记录为网络/主机边界静默丢弃证据。
## 缺陷与处理
| 编号 | 现象 | 处理 | 复测 |
| --- | --- | --- | --- |
| S29-D1 | T 呼叫脚本固定本地 UDP 端口,导致并发发起时端口冲突。 | 修改 `infra/server-t/s28/lisglosips-s28-sip.py`,默认 `--local-port 0`,bind 后写入实际端口到 Via/Contact,并部署到 T。 | 5 路并发和 12 路短突发均成功。 |
| S29-D2 | MySQL 短故障时 CDR Worker 将可恢复数据库连接错误 deadletter 并 ACK 原 Redis 消息,导致 CDR 不自动重试。 | `packages/redis` 增加 `CdrRetryableError`retryable 错误不 ACK、不 deadletter,并释放幂等锁;`worker-cdr` 将数据库连接类错误标记为 retryable。 | 停 MySQL 后发起呼叫,恢复 MySQL 并等待 pending idle 窗口后 raw/rated CDR 自动入库,无新增 deadletter。 |
| S29-D3 | 失败 CDR 的长 `event_id` 超过 `raw_cdrs.event_id varchar(64)`,触发 Prisma 长度错误并 deadletter。 | `worker-cdr` 入库前对超过 64 字符的 `event_id` 做稳定 SHA-256 后缀压缩,原始事件仍保留在 payload 中。 | 本地 Vitest 与 build 通过;B 部署后 MySQL 故障复测无新增长度类 deadletter。 |
| S29-D4 | Redis 恢复后 A 热路径仍返回 `503 Redis Unavailable`,仅重启 Redis proxy 无法恢复。 | 本次执行运行时恢复:重启 A `opensips`,恢复呼叫。根因需在后续 OpenSIPS Redis 连接池/故障重连策略中继续排查。 | 重启 A `opensips` 后 T->A 呼叫恢复成功。 |
| S29-D5 | S29 期间本地/T 到 B 的 Tailscale 管理链路出现短时高延迟/丢包,SSH 偶发超时。 | 未改网络配置;采用短命令、分步执行、服务健康复核。 | 后续 SSH 与 API 健康检查恢复;记录为开发环境网络风险。 |
## 结论
S29 在本地 KVM 开发环境完成。单 A/S28 最小闭环在 5 路并发和 12 路短突发下能完成 SIP、CDR、计费、录音入库;Recording Worker、CDR Worker、MySQL 短故障的可恢复路径已验证,其中 MySQL 可恢复缺陷已完成代码修复并部署到 B 当前 release。
API 鉴权、RBAC、录音播放未认证保护和充值幂等重放均通过。SIP 非法来源探针未进入业务路由,但缺少 OpenSIPS 层拒绝日志,建议后续补充明确的非法来源日志/指标。
遗留风险:Redis 恢复后 OpenSIPS 热路径仍需重启 `opensips` 才恢复,当前只有运行时恢复与复测记录,尚未完成根因级修复;多 A、完整生产路由、多 B 高可用不属于 S29 本次范围。