⚠️ 强烈建议所有正在使用初春图床的用户立即升级到 v4.0.0。
本次版本包含两轮完整安全审计修复的 14 项安全问题,其中多项属于可被直接利用的高危漏洞:SSO 信任锚提权(非超管可把自己变成超管)、权限授予越界、横向角色提升、存储连接 SSRF(可探测内网、向内网 FTP/WebDAV 写文件)、水印转码放大 DoS、CDN 缓存投毒(攻击者的水印图可被缓存一年)、账号定向锁死(单 IP 可打满管理员账号的登录预算)。这些漏洞不需要任何特殊条件,普通登录用户甚至未登录访客就能触发,旧版本继续暴露在公网上存在实际风险。
初春图床 v4.0.0 更新来了!这是一个聚焦安全加固的大版本:两轮完整安全审计修复了 14 项问题,新增用户上传配额与转码缓存,并修复了社区反馈的文件命名问题(#45,感谢 @dasima4396)。
升级前请务必备份 ./data 卷。本版本无破坏性变更,可直接覆盖升级;反向代理部署的用户请务必阅读下文 TRUSTED_PROXIES 一节。
🔒 安全:两轮审计修复 14 项(本次升级的核心理由)
本轮按「SSO 信任锚 → 权限模型 → SSRF → DoS → 缓存」逐层排查,重点修复:
| 漏洞 | 风险说明 | 修复方式 |
|---|---|---|
| SSO 信任锚提权 | 非超管可写入 OIDC/CAS 配置,并把外部用户名映射为本地超管,直接拿到最高权限 | OIDC 9 键 + CAS 6 键 + api_token 等 17 个信任锚键改为仅超级管理员可读写,权限校验之前先行拦截 |
| 权限授予越界 | 用户可授予自己并不持有的权限码,逐步提权 | 授予集合必须为自身持有权限的子集 |
| 横向角色提升 | 把第二个账号提成管理员,绕过针对自身的保护检查 | 非超管不得将任何账号 role 设为管理员(含创建与修改两条路径) |
| 存储连接 SSRF | 存储连接测试接口可探测内网、向内网 FTP/WebDAV 写文件 | 三层防护:端点必须是公网地址(拒绝 127.0.0.1/10.x/172.16.x/192.168.x/169.254.169.254 等)、凭据变更时强制重填、连接期防 DNS rebinding |
| 水印转码放大 DoS | ?watermark=true 不受开关约束、免鉴权零限流、转码槽无超时,可打满服务器 | 转码受 watermark_enable 约束;槽位 2 秒超时返回 503 + Retry-After;HEAD 请求不转码;新增 6 次/10 秒/IP 限流 |
| CDN 缓存投毒 | 转码响应 public, max-age=31536000 且无 Vary,攻击者构造的水印图可被 CDN 缓存一年 | 转码响应改 private, max-age=600, no-transform + Vary,普通图片仍保持一年强缓存 |
| 账号定向锁死 | 单 IP 可耗尽任意账号(含管理员)的登录预算,实施定向拒绝服务 | 限流只对密码错误记账、成功登录清零、注册不共享预算 |
| 其他加固 | — | URL 上传独立下载槽位防占满、TG Bot Token 日志脱敏、静态资源跳过会话查询、数据库错误不回显、禁目录列表、移除 X-Storage-Type 信息泄露 |
如果你正在公网运行旧版本(v3.5.x / v4.5.5 及更早),以上漏洞意味着:任何注册用户都可能把自己变成超管,任何访客都可能消耗你的服务器资源、污染你的 CDN 缓存、或者锁死管理员账号。这不是理论风险,是可直接复现的攻击路径。
🐛 修复:保存源文件名仍追加随机后缀(Issue #45)
感谢 @dasima4396 反馈。开启「保存源文件名」后,上传 风景.jpg 会得到 风景_fghx-x45djh-566.jpg —— 文件名末尾被无条件追加了一长串随机字符;关闭开关后的自动命名也带有同样的后缀。
本版本的行为:
- 开启「保存源文件名」后不再追加随机后缀,
风景.jpg上传后就是风景.webp(后缀按实际格式修正); - 可读字符(中文、空格、短横线等)原样保留,不可读字符折叠为单个
-,同时防御路径逃逸与 Windows 保留名; - 重名自动编号:
风景.webp→风景-2.webp→风景-3.webp……探测占用失败时回退随机命名,绝不覆盖已有图片; - 关闭开关时保持原有「模板 + 随机串」命名逻辑不变。
✨ 新增:用户上传配额
每个用户的可上传总量支持三档语义:
| 配置 | 行为 |
|---|---|
| 个体配额设为具体值 | 严格按该值限制(不与默认值取小) |
| 未设置(跟随默认) | 使用站点默认配额(默认 10 GiB,系统设置中可改) |
| 设为 0 | 不限量 |
- 管理员与超级管理员不参与配额;
- 配额判定以落盘后的真实大小为准(PNG 转码为更小的 WebP 后不会被误判超限);
- 用户卡片实时显示进度条(<70% 主色 / 70–90% 琥珀 / ≥90% 红色)。
⚡ 新增:转码结果缓存
同一张图 + 同一组水印参数,输出恒定,不再重复计算。实测一张 4335×2520 的图:冷转码 0.626s,命中缓存 0.0138s(快 45 倍),且命中时跳过远端存储回源。缓存键覆盖全部水印参数,修改任何参数都会生成新键;改动水印设置时主动失效,避免「改了没生效」的调试困惑。
🛡️ 新增:反代信任配置 TRUSTED_PROXIES(反代用户必读)
v4.0.0 起默认不信任任何代理头:X-Forwarded-For 仅当请求来源在 TRUSTED_PROXIES 列表内才被采信。这是「安全默认」的取舍——不配置时,反代部署下所有访客会共用反代 IP 的限流预算(限流会变得不准,但不会危及安全)。
| 部署形态 | 建议值 |
|---|---|
| 无反代,直接暴露 | 留空(默认) |
| Docker 网络内反代 | 172.16.0.0/12 |
| 本机反代 | 127.0.0.1 |
| 前置 Cloudflare | 补充 CF 官方 IP 段 |
⚠️ 配置了非法条目(不是合法 IP/CIDR)时应用会拒绝启动,而非静默忽略——避免限流在毫不知情的情况下失效。
🔧 修复:Turnstile 配置不完整时的降级
「人机验证方式」选了 Turnstile 但密钥没填全时,此前验证逻辑会回退到本地 POW,但 CSP 头仍按 Turnstile 收紧,导致 POW 组件的 WebAssembly 被浏览器拒绝、验证永远无法完成。现在降级决策统一收敛到一处,CSP 与验证行为保持一致;设置页会明确提示「缺少哪些配置」。
🎨 界面与体验
系统设置页
- 布局整页重写:页签栏吸顶(滚动时始终可见)、统计信息并入页签栏右侧、表单/说明栅格再平衡(输入框不再比说明文字还窄)、各面板内部改两列布局(窄屏自动堆叠)
- 页签选中态对比度修正:深色模式 1.41 → 7.27(WCAG AAA),浅色 5.83
- 页签同步到 URL(
?tab=xxx):刷新、前进/后退都能回到原页签,直达链接自动滚动到选中项 - 新增「系统」页签:显示当前版本号、检查更新(服务端缓存 5 分钟查询 GitHub,避免浏览器限流),有新版本时显示更新日志与跳转链接
- 版本信息从账户设置移至系统设置;侧栏与用户菜单顺序统一为「账户设置 → 系统设置」
- 移除初春 POW 在线验证服务(cha.eta.im):验证方式收敛为「无验证 / Turnstile / 本地 POW(cap-pow)」三选一,旧库里的 pow 配置自动回落,相关 CSP 白名单与前端死代码全部清理
- Turnstile 配置不完整自动回退本地 POW,设置页明确提示缺哪些配置,修复 CSP 不放行 wasm 导致验证永远无法通过的 Bug
- 安全开关(人机验证与访问控制)上移为独立面板,Referer 白名单迁入安全页签
账户设置页
- 修复 7 个无定义的「幽灵类名」;登录会话与登录历史 ≥1280px 并排(整页高度 ~1400 → 728)
- 登录会话:新增「剩余 N 天/小时/分钟」(<24h 琥珀提醒)、当前会话高亮、无其他会话时禁用「退出其他会话」
- 登录历史:改为时间线样式(竖线 + 圆点,最新一条高亮 +「最近一次」徽章)
- 修改密码:新密码/确认并排,按钮初始禁用(有改动且填了当前密码才可提交)
登录页(未登录状态)
- 未登录时不渲染侧边栏:未登录状态下没有任何可导航页面,侧边栏整块不再出现(登录后恢复);内容区不再为不存在的侧栏让位
- 登录卡片与顶栏导航的布局、样式微调
其他
- 主题切换圆形揭示动画(View Transitions API),用户菜单缓入缓出
- API Token 按钮分离:生成/重新生成/复制各自独立,修复输入框右侧 112px 死区
- 标签管理页重构:修复添加/修改/删除无响应的问题(引用未定义的组件)+ 按 id 定位防误删
- 图库新增瀑布流视图、筛选与详情弹窗;最近上传卡片重排(文件名在元信息上方)
- 通知 Toast(message.js)布局自适应:PC 75px 边距、移动端 16px 对称边距、自动让出导航栏高度、悬停暂停自动关闭
- 表单校验错误信息中文化(如「密码不能少于 8 位」「用户名 3-20 个字符」)
- 数据统计页重做、全站去除
:focus-visible黑框、搜索框与输入控件样式统一(.input-modern)
🧱 代码重构
controllers按业务域拆分为auth/images/storage/system/users/shared六个子包,循环依赖清零- 水印/验证策略/外部认证配置等纯逻辑下沉到独立工具包
升级指南
本次升级无破坏性变更,可直接覆盖升级。但仍建议按以下顺序操作:
- 备份
./data卷(数据库 +data/.config_secret+data/.session_secret+data/.initial_admin_password都在里面,丢失后已加密的存储凭据无法恢复); - 备份数据库(如使用外部 MySQL / PostgreSQL,单独做一次 dump);
- 覆盖升级二进制或拉取新镜像:
docker pull onexru/oneimg-oneimg:v4.0.0# 或docker pull onexru/oneimg-oneimg:latestdocker compose up -d- 反向代理部署的用户,配置
TRUSTED_PROXIES(Docker 内反代用172.16.0.0/12,本机反代用127.0.0.1),否则所有访客会共用反代 IP 的限流预算; - 确认
APP_URL已设置为实际访问地址(图片外链基址取自该值); - 升级后进「系统设置 → 系统」页签确认版本号为 v4.0.0。
从 v3.5.5 及更早版本升级时,若
.env里还留着DEFAULT_PASS=123456,请删除该行或改成强密码(初始管理员密码从 v3.5.6 起已改为随机生成,写入data/.initial_admin_password)。
下载与部署
| 产物 | 说明 |
|---|---|
oneImg_Win_amd64_v4.0.0.zip | Windows amd64(含 README,UPX -9) |
oneImg_Win_arm64_v4.0.0.zip | Windows arm64(含 README,UPX 暂不支持该平台 PE 格式,未压缩) |
oneImg_Linux_amd64_v4.0.0.tar.gz | Linux amd64 静态二进制(UPX -9) |
oneImg_Linux_arm64_v4.0.0.tar.gz | Linux arm64 静态二进制(UPX -9) |
oneImg_Docker_amd64_v4.0.0.tar | Docker 镜像,docker load 导入后标签 oneimg:v4.0.0-amd64 |
oneImg_Docker_arm64_v4.0.0.tar | Docker 镜像,docker load 导入后标签 oneimg:v4.0.0-arm64 |
- 二进制包为单文件静态链接程序(webp / sqlite3 由 cgo 内嵌编译),无运行时依赖。
- Docker Hub 支持
linux/amd64与linux/arm64双架构。
最后再说一次:为了你的数据安全和服务器安全,请务必尽快升级到 v4.0.0。 如果升级过程中遇到问题,欢迎在 GitHub 提 Issue 反馈。
项目地址
项目地址: