安全(P0) - 发布包签名:新增 scripts/package_keygen.php、scripts/package_verify.php、 ywxapp\service\PackageVerifier;FrameworkService::apply() 解压前强制验签 (ywxapp.framework_package_verify,默认开启) - JWT 收紧:config/jwt.php 移除公开默认密钥,JwtService::assertStrongSecret() 校验非空 / 长度≥32 / 已知弱值;.env.production.example 键名由 JWT_SECRET_KEY 修正为 JWT_SECRET - /api/v1/Article:免登录白名单收窄为只读接口,写操作字段白名单 + assertOwner() 越权校验 - 开发者令牌:查找接口不再回显明文、统一失败文案 + 限流 - TemplateInstaller:文件名白名单 + realpath 归一化 + 目录内断言,修复 Zip Slip;补 use ZipArchive - 后台登录:接入验证码、失败锁定与登录限流(config/ratelimit.php) - 缓存 / Session 驱动可由 .env 覆盖(CACHE_DRIVER / SESSION_TYPE),集群部署改 redis - paycenter 支付日志开关改为 PAY_LOG,不再跟随 APP_DEBUG 工程化 / 交付 - 新增 CHANGELOG.md 与 .env.production.example;composer.lock 入库锁定依赖版本 - 插件离线安装 CLI 增加 --uid,后台上传安装透传 uid,付费插件授权校验可通过 - 授权拒绝文案区分「未携带 uid」与「未找到有效授权」,便于排障 - .gitignore 放行 .env.production.example / .env.addon.example / .gitattributes / public/.htaccess 结构 - appmall 由 addon/appmall 迁移为独立应用 app/appmall(市场 / 开发者中心 / 审核 / 分润)
65 lines
5.2 KiB
Markdown
65 lines
5.2 KiB
Markdown
# 更新日志(CHANGELOG)
|
||
|
||
本项目版本号采用语义化版本(主版本.次版本.修订),唯一事实源是 `config/ywxapp.php` 的 `version`,
|
||
由 `scripts/package_framework.php` 递增并写回。发布流程见 `docs/打包与发布指南.md` 的「发版 Checklist」。
|
||
|
||
## [1.1.2] — 待发布(Unreleased)
|
||
|
||
一次以「可对外发布」为目标的安全与工程化收敛,未引入新业务功能。
|
||
|
||
### 安全修复(Security)
|
||
|
||
- **SEC-1 主框架升级包无来源认证**:官网 / CDN / DNS 被攻破即可向全部客户机推送任意代码。
|
||
新增发布包签名体系 `ywxapp\service\PackageVerifier`(RSA-SHA256 签名 + 内容清单哈希 + 防降级),
|
||
`FrameworkService::apply()` 解压前强制验签,未部署公钥时 fail-closed;
|
||
打包脚本自动签名,配套 `scripts/package_keygen.php` 与 `scripts/package_verify.php`。
|
||
- **SEC-2 JWT 默认密钥可用**:`.env.production.example` 键名误写作 `JWT_SECRET_KEY`(代码读 `JWT_SECRET`),
|
||
照模板部署等于用公开密钥签发 token。模板键名已修正,`config/jwt.php` 默认密钥改为空,
|
||
`JwtService` 签发前强制校验强度(不少于 32 字节且不得命中弱值黑名单)。
|
||
- **SEC-3 `/api/*` 文章写接口未授权**:`$noNeedLogin=['*']`,且 `$needRight` 字段 `ApiBase` 根本不认,
|
||
任何人可增删改全站文章。白名单收窄为只读的 `index/detail/init`,
|
||
写操作需登录且只能操作自己的文章(新增 `assertOwner()`),create 改为字段白名单且归属 `uid` 由服务端写入。
|
||
- **SEC-4 后台登录防护缺失**:验证码参数被静默丢弃、账号锁定逻辑从未被调用、后台无限流。
|
||
`AdminAuth::login()` 补齐验证码校验、账号锁定 `isLocked()`、IP 与账号双维度限流封禁(配置项 `login_fail_*`)。
|
||
- **SEC-5 开发者令牌明文回显且邮箱可枚举**:POST 任意邮箱即返回 token(可用于发布插件、改价、提现)。
|
||
改为只发邮件不回显、统一响应文案防枚举、随机延时防时序侧信道、IP 与邮箱限流。
|
||
- **SEC-6 模板包 Zip Slip**:`templates/<name>/` 前缀匹配后直接拼接路径,可写入任意目录。
|
||
新增模板名白名单、相对路径 `..` 拦截、落盘前 `realpath` 越界校验三道防护。
|
||
|
||
### 变更(Changed)
|
||
|
||
- `config/ratelimit.php` 的 RateLimit 中间件仍只注册于 api 应用,后台登录改由 `AdminAuth` 自带计数。
|
||
- `.env.production.example` 补齐 `JWT_SECRET`、安全开关、缓存与 Session 驱动、市场角色。
|
||
- `config/cache.php` 的 `default`、`config/session.php` 的 `type` 支持 `CACHE_DRIVER` / `SESSION_TYPE`(多副本部署切 redis)。
|
||
- `config/ywxapp.php` 新增:`framework_package_verify`、`package_public_key_path`、`login_fail_limit/window/block_time`;
|
||
`addon_license_check` 支持 `ADDON_LICENSE_CHECK`。
|
||
- `composer.json`:`yansongda/pay`、`hyperf/pimple` 由通配 `*` 锁定到 `^3.7.20` / `^2.2.2`;
|
||
`platform-check` 由 false 改 true;`composer.lock` 不再被忽略(可复现构建)。
|
||
- 删除 `.travis.yml`(ThinkPHP 官方脚手架残留,含他人加密 deploy key)。
|
||
|
||
### 升级须知(Breaking)
|
||
|
||
1. **升级包必须签名**:1.1.2 起的客户机默认要求发布包带 `signature.json`。
|
||
自建升级服务器的内网场景可临时用 `FRAMEWORK_PACKAGE_VERIFY=false` 降级(不推荐)。
|
||
2. **未配置 `JWT_SECRET` 将无法签发任何 token**(刻意的 fail-closed)。
|
||
升级前请执行 `openssl rand -base64 64` 并写入 `.env`。
|
||
3. **`/api/v1/article` 的 create / update / delete 需登录**。
|
||
此前依赖匿名写库的下游客户端需改为携带 token。
|
||
4. **开发者令牌找回页不再回显令牌**,改为邮件发送;
|
||
前端 `app/appmall/view/developer/mine.html` 已兼容(无 token 时不展示令牌块)。
|
||
|
||
### 已知限制与后续(Known Issues)
|
||
|
||
本节记录本次**未处理**、需要在后续版本跟进的问题,避免它们被误当成「已修复」:
|
||
|
||
1. **数据库自愈无版本号、无法回滚**:约 60 处模型依赖 `BaseModel.php` 从 `public/install/install.sql` 补表,
|
||
且该路径写死在代码里 —— 按安全要求删掉 install 目录后自愈会静默失效;多副本冷启动还存在并发建表竞态。
|
||
计划改为「升级 SQL 清单 + 已执行版本表」,自愈降级为兜底。
|
||
2. **插件包(addon)尚未接入发布包签名体系**:本次只加固了主框架升级链路。
|
||
插件在线安装有 `addon_secret` 下载签名可选调用,但没做包内完整性校验,下一步复用 `PackageVerifier`。
|
||
3. **无 CI / 单元测试 / 静态分析**:本次修复的自检均为临时脚本(已删除)。
|
||
建议补 `tests/` + GitHub Actions,至少覆盖支付回调签名、Zip 安装路径安全、JWT 密钥策略三条主线。
|
||
4. **`catch (\Throwable)` 静默吞异常**:全仓约 144 处(尤以 `BackendSchemaMiddleware`、`BaseModel` 居多),
|
||
故障排查成本高,建议逐步替换为「记录 + 上报」。
|
||
5. **`app/api/controller/v1` 的 paginate 分页数偏大**(如 1000),缺少服务端上限,建议统一由 `paginate()` 默认限制。
|