Files
CHFS-NG/docs/REVIEW_B_AUDIT_20261002.md

7.9 KiB
Raw Permalink Blame History

审核专家 B:CHFS-NG 代码安全审计报告

  • 审核人:审核专家 B
  • 日期:2026-10-02
  • 对象:/root/chfs-ng-research(Go,11 个非测试源文件,约 3900 行)
  • 生产环境:chfs-ng.service(root 用户),bin/chfs-ng -file chfs.ini,监听 *:18999
  • 验证:go vet ./... 干净;go test ./... 全通过
  • 结论:有条件通过 —— 代码层面的路径防御与权限检查扎实,但生产部署配置存在阻断项,另有 2 高/3 中需处理

【阻断】生产配置使用弱密码 admin123,明文存储且文件全局可读

【严重度:阻断】

【位置】 /root/chfs-ng-research/chfs.ini(生产配置文件)

【问题描述】 生产 chfs.ini 中 [admin] 的密码为明文 admin123,文件权限为 -rw-r--r--(全局可读)。 服务监听 *:18999(所有网卡),主机防火墙 INPUT 策略为 ACCEPT 且无规则,等同于直接暴露公网。 远程攻击者无需任何前置条件,直接用 admin/admin123 登录即获得全部文件读写删除权限。

【利用/触发条件】 curl -X POST http://<host>:18999/chfs/session -d "user=admin&pwd=admin123" 即得管理员 JWT。

【修复建议】

  1. 立即更换高强度密码;2. chmod 600 chfs.ini;3. 配置 allow IP 白名单或置于反向代理后;
  2. 考虑主机防火墙限制 18999 入站。

【高】/chfs/exist 未鉴权的文件存在性预言机

【严重度:高】

【位置】 internal/api/server.go:512 func (s *Server) exist

【问题描述】 该端点全程未调用 account(r, s),未做任何权限检查:GET /chfs/exist?file=<path> 返回 201/404 直接泄露任意路径是否存在。所有其他文件端点都有 MaskFor 检查,唯独此处遗漏, 与 README 宣称的"完善的权限体系"不一致。

【利用/触发条件】 当前生产 guest=r,攻击者本就可列目录,实际影响有限;但在 guest 被收紧的部署中, 该端点绕过权限模型造成信息泄漏。

【修复建议】 加上 if !account(r, s).MaskFor(p).HasRead() { 403 },与其他端点保持一致。


【高】缩略图接口无文件大小限制,可被解压炸弹打 OOM

【严重度:高】

【位置】 internal/api/server.go:1164 func (s *Server) thumbnail

【问题描述】 image.Decode(f) 会把整个文件读入内存解码,而此前没有任何文件大小检查。 缓存层虽有 8MB/64 项上限(thumbnail_cache.go),但 decode 本身在缓存之外无限制。 攻击者(生产环境 guest 即有 read 权限)可请求超大文件或特制解压炸弹 (小文件声明超大宽高,如 PNG 头声明 100000x100000 → 数十 GB 内存分配),直接 OOM 杀死服务。

【利用/触发条件】 GET /chfs/thumbnail?file=<大文件或炸弹图片>,无需登录(guest 可读)。

【修复建议】 Stat 后检查 fi.Size(),超过阈值(如 32MB)直接拒绝;或对 decode 加内存上限。


【中】目录 ZIP 下载无总大小/数量限制,CPU 与带宽耗尽

【严重度:中】

【位置】 internal/api/server.go:1290 downloadSelectedZip、1368 downloadDir

【问题描述】 两个接口把目录树流式打包为 zip 直接写回 response,全程无总字节数、无文件数上限 (downloadSelectedZip 仅限制了顶层 path 参数 ≤100 个,但每个可为超大目录;downloadDir 无任何限制)。 zip.Deflate 是 CPU 密集型,多并发请求可打满 CPU 并占满带宽。guest 可读即触发。

【修复建议】 增加可配置的打包上限(总大小、文件数),超限返回 413;或对该接口加并发信号量。


【中】上传无单文件/总量配额,可填满磁盘

【严重度:中】

【位置】 internal/api/server.go:838 upload、937 upload2、savePart

【问题描述】 ParseMultipartForm 仅限制内存部分(64MB/128MB),savePart 的 io.Copy(f, in) 无任何大小上限。 有写权限的用户可上传超大文件填满磁盘。当前生产仅 admin 有写权限,实际影响有限, 但项目主打"动态权限控制"(会给普通用户开写权限),属于设计缺口。

【修复建议】 增加 upload.max-size 配置项,savePart 中用 io.LimitReader 截断并报错。


【中】默认删除进系统回收站且永不清理,磁盘被"已删除"文件占满

【严重度:中】

【位置】 internal/storage/storage.go Trash;internal/config/config.go 默认 FileRemove: 1

【问题描述】 默认 file.remove=1 走 wastebasket.Trash(~/.local/share/Trash),该库无自动清理机制 (只有模式 2 的 MoveToTrash 有 30 天清理)。长期运行的服务删除的文件永久占用磁盘, df 与用户认知不一致,最终表现为神秘的磁盘占满。

【修复建议】 对模式 1 也加定期清理(如 30 天),或在文档中明确说明并给出清理方式。


【中低】search 无结果数量上限

【严重度:中低】

【位置】 internal/api/server.go:1009 func (s *Server) search

【问题描述】 全树递归遍历,结果集无上限一次性 JSON 返回。超大目录树下内存与响应体膨胀, guest 可直接触发。

【修复建议】 加 limit 参数(默认如 500),超限截断并提示。


【低】ipFilter 不识别 X-Forwarded-For,反代后 allow 白名单失效

【严重度:低】

【位置】 internal/api/server.go:2065 ipFilter / clientIP

【问题描述】 clientIP 只读 r.RemoteAddr。README 建议生产用 HTTPS 反向代理, 一旦接入反代,allow 看到的永远是代理 IP,白名单名存实亡(要么全放行要么全拒绝)。

【修复建议】 支持可信代理 + X-Forwarded-For 解析,或在文档中明确说明该限制。


【低】密码哈希为无盐 SHA256

【严重度:低】

【位置】 internal/auth/auth.go func PasswordHash

【问题描述】 users.json 中存储 hex(sha256(password)),无盐。文件泄漏后彩虹表可直接破解弱密码。

【修复建议】 改用 bcrypt(golang.org/x/crypto/bcrypt),并做旧哈希的兼容迁移。


已验证为安全的关键点(正面结论)

  1. JWT 密钥管理正确:main.go 在未配置 jwt.secret 时生成随机 32 字节密钥并以 0600 权限持久化 到 users.json.jwt-secret(生产已生效,文件存在)。auth.go 中的硬编码常量在 server 路径中不可达。
  2. 路径穿越防御扎实:unsafePath(NUL + .. 段)与 storage.real() 双层防御;real() 对最近存在祖先 做 EvalSymlinks,连路径中间的符号链接逃逸都能拦住。多根目录经 Multi 路由后仍走同一检查。
  3. 权限检查完整:除 exist 外所有 mutating 端点都有 MaskFor 检查;rename 为 create-only; remove/transfer 有递归 preflight;WebDAV 有独立 webdavAuthFS 包装,Move/Copy/RemoveAll 均有 checkTree。
  4. 上传 preflight:upload/upload2 全量校验后再落盘,失败回滚已保存分片;createExclusive 防并发覆盖。
  5. Cookie 安全:JWT cookie 为 HttpOnly;生产 guest 为只读。
  6. 生产密钥文件权限正确:users.json.jwt-secret 为 0600。

总体结论

有条件通过。

代码本身质量不错:路径穿越防御、权限模型、并发处理都经过认真设计,测试全过、vet 干净。 真正的风险在生产部署:admin123 弱密码 + 公网直连 + 无防火墙是阻断项,必须立即处理。 代码层面需修:exist 鉴权缺失(高)、缩略图 OOM(高),以及 ZIP/上传/回收站/搜索的资源限制(中)。 修完阻断项和高优先级后可认为达到生产安全标准。