本文用于:总结现状问题、明确安全基线与新架构,并作为“重写版本”的实施蓝图与验收标准。
当前实现已具备“短链生成/跳转、PG、Meilisearch、用户系统、多域名、二维码、限流、CI/CD”等功能,但在安全性、可维护性、并发正确性、可观测性、可测试性上存在明显不足,需要进行系统性重写。
- 安全:默认安全(secure by default),杜绝“单个配置 token 绕过全部权限”的设计。
- 正确性:并发下短码生成无竞态、无重复、可回退重试;统计写入稳定。
- 性能:热点跳转读路径可缓存;高并发下 DB/Redis/Meili 均有超时、限流与降级策略。
- 可维护:分层清晰(handler/service/repo),依赖注入、接口隔离,可做单测与集成测。
- 可观测:结构化日志、指标、追踪、审计日志(尤其是管理员操作)。
- 交付:保留现有 API 大体结构,同时提供明确的迁移说明。
- 全局 DB 句柄的误解:Go 的
*sql.DB本身线程安全,内部自带连接池;但当前未配置池参数(MaxOpen/MaxIdle/ConnMaxLifetime),在高并发可能导致连接抖动或资源占用失控。 - 缺少 context 超时:DB/Redis/Meili 请求缺少
context.WithTimeout,慢查询或网络抖动会造成 goroutine 堆积。 - 全局 context:
context.Background()全局复用不便于取消/超时控制;不算“泄漏”,但会导致无法收敛资源。
- 使用
math/rand.Seed(time.Now().UnixNano()):可预测/可重复,且每次调用都 Seed 会降低随机质量与产生碰撞风险(并发时更明显)。 - 短码生成竞态:即使使用更好的随机数,仍需要在 DB 层用唯一约束 + 冲突重试,避免并发插入重复 code。
- “长度耗尽”计算成本:按长度统计、计算 90% 阈值可能导致高频 COUNT 查询;需要更高效策略(例如:只在冲突频率升高时扩容)。
- JWT 密钥硬编码/与 API_TOKEN 耦合:存在默认密钥、或直接复用 API_TOKEN 的风险,导致 token 可伪造。
- API_TOKEN “超级通行证”:若允许某个系统 token 直接获得 admin 权限,会导致:
- 任何泄漏都等价于“全站失守”
- 无审计、无最小权限
- 与用户 token/JWT 体系冲突
- Token 存储明文:用户 API token 直接存数据库明文字段;一旦数据库泄漏,所有 token 可被直接利用。应改为存储 hash(如 SHA-256/argon2)。
- Web 端 token 存储策略不安全:localStorage 容易被 XSS 窃取。更推荐 HttpOnly Cookie + CSRF 防护,或 BFF 模式。
- 缺少 CSRF 防护:若采用 Cookie 鉴权(未来大概率),必须加 CSRF token 或 SameSite 策略。
- 缺少基础安全头:CSP、HSTS、X-Frame-Options、X-Content-Type-Options 等。
- URL 安全校验不足:可能被用于 SSRF、内网探测、跳转到恶意协议(
file://、javascript:等)。
- 当前 Redis 主要用于限流计数,并未用于热点跳转缓存;对“高并发短链跳转”场景帮助有限。
- 限流实现是简单计数器:缺少更精确的滑动窗口/令牌桶策略、缺少代理链路真实 IP 处理策略。
- 创建/删除/更新短链时对 Meili 的写入失败如何处理(重试、补偿、死信、后台任务)不明确。
- 目前日志混用
log.Printf与自定义 logger,缺少 request_id、用户信息、耗时、错误堆栈。 - 敏感信息输出:首次创建 admin 时输出明文密码/Token 存在泄漏风险(日志系统、容器日志平台、CI 采集都会暴露)。
- 缺少单元测试、集成测试(PG/Redis/Meili)、安全测试用例(SSRF/XSS/CSRF/权限绕过)。
- 缺少 lint(
golangci-lint)与安全扫描(gosec)规范化配置。
nsl-go/
cmd/
api/ # HTTP 服务入口
nsl/ # CLI 管理工具(admin/迁移/修复/导出)
internal/
config/ # 配置加载(env + file),强校验
http/ # gin/chi 路由、middleware、handler
service/ # 业务逻辑(短链/用户/域名/统计/搜索)
repo/ # 数据访问层(pgxpool + sqlc / bun)
auth/ # JWT、API key、RBAC、session
cache/ # Redis 缓存(热点跳转、限流、会话)
search/ # Meilisearch 适配层
jobs/ # 后台任务(索引重建、统计聚合、补偿重试)
observability/ # logger/metrics/tracing
web/ # Web UI 静态资源(可改为独立前端项目)
migrations/ # 版本化迁移(golang-migrate)
docs/
security.md
api.md
deployment.md
- Handler:只做参数校验、鉴权上下文读取、调用 service、返回响应。
- Service:业务逻辑(幂等、冲突重试、权限校验、缓存策略、任务派发)。
- Repo:纯数据访问(必须全程使用 context + timeout)。
- Middleware:鉴权、限流、日志、CORS、安全头。
JWT_SECRET必须显式配置(生产环境),不允许硬编码默认值。- API Token 不再作为超级通行证:若保留系统级 token,只能用于少量管理端点,并且必须审计 + RBAC。
- 用户 API token 只存 hash(例如
sha256(token)),只在创建时展示一次。
- Web UI:HttpOnly Cookie + SameSite + CSRF token(双提交或服务端存储)。
- API 调用:
- Header Bearer API Token(用户级、永久),或
- JWT(短期 access + 可选 refresh)。
- RBAC:
- 基础角色:
admin/user - 预留权限点:
link:createlink:deletedomain:managesettings:update等
- 基础角色:
- 仅允许
http/httpsscheme - SSRF 防护:禁止内网 IP / link-local / loopback / metadata endpoint(可配置开关)
- URL 规范化后再做 hash(避免“同一URL不同写法”重复入库)
- 生成:
crypto/rand+ base62(拒绝采样) - 插入:依赖数据库唯一约束(
(domain_id, code))冲突后重试 - 动态长度:
- 默认最小 6 位
- 当冲突率/容量阈值到达时自动扩到 7、8…
- 管理员可设
min_len/max_len
hash = sha256(normalized_url)- 唯一约束建议:
(user_id, hash)或(user_id, domain_id, hash)(按产品选择) - 再提交相同 URL:返回已有短链(包括二维码)
- 跳转路径必须极快:
- 读:Redis 缓存 code -> url + link_id
- 写:异步写入访问日志/点击数(队列/worker/batch)
- 提供聚合统计:日/周/月、TopN、来源、UA 等
- 必须用途:热点跳转缓存、限流、会话/CSRF token(若使用 Cookie)
- 可选用途:短链详情缓存、用户配额计数缓存、Meili 写入失败队列
- 短链生成/跳转正常
- 相同 URL 幂等返回同一短链
- 动态长度扩容可用(可配置 min/max)
- 多域名增删改查可用
- 二维码生成可用
- 统计与访问记录可用
- Web UI:登录页、管理页可用
- CLI:初始化 admin、重置密码、重置 token、导出数据等
- 无硬编码密钥
- 无“系统 token 全权限绕过”
- token 不明文存储
- CSRF(若 cookie)通过
- SSRF 拦截通过
- RBAC 权限点可扩展
- 单元测试覆盖关键 service(短码生成、幂等、权限校验、配额)
- 集成测试:PG/Redis/Meili(建议 testcontainers)
- CI:
go test ./...+golangci-lint+gosec - 结构化日志 + request_id + metrics(Prometheus)
-
先定安全与配置:JWT_SECRET、token hash、移除超级通行证、审计日志
- ✅ JWT_SECRET、token hash、移除超级通行证
- ✅ 审计日志(管理员操作、敏感操作记录)
-
重写数据层:pgxpool + 迁移版本化(migrate)
- ✅ 已完成
-
重写鉴权与RBAC:web cookie + csrf / api token hash
- ✅ web cookie + csrf / api token hash
- ✅ RBAC 权限点(细粒度权限点:link:create, link:delete, link:view, link:list, stats:view 等)
-
重写短码生成与幂等:并发安全 + DB 冲突重试
- ✅ 已完成
-
引入缓存与异步统计:热点缓存 + worker
- ✅ 已完成
-
补齐测试与CI:单测/集成测/安全扫描
- ✅ 集成测试(PG/Redis 使用 testcontainers)
- ✅
golangci-lint/gosec在 CI 中落地 - ✅ Metrics(Prometheus)
- ✅ Tracing(OpenTelemetry + Jaeger)
-
其他优化:
- ✅ 限流策略优化(滑动窗口 + 令牌桶)
- ✅ 代理链路真实 IP 处理
- ✅ 聚合统计扩展(日/周/月、来源、UA 等维度)
- ✅ Meilisearch 写入失败补偿/重试
- ✅ 结构化日志统一
- 幂等的粒度:同一用户同一 URL 是否允许多个 domain 下生成不同短链? 这里允许
- Web UI 鉴权方式:Cookie(更安全)还是 localStorage(更简单但有XSS风险)? 这里使用Cookie(更安全)
- 系统级 API_TOKEN 是否保留:如果保留,允许哪些端点?是否强制IP白名单/二次验证? 不保留