Skip to content

security: fix critical/high/medium vulnerabilities (authcode AES-256-GCM, CSRF timing, cookies, UUID, logging)#14

Merged
biglyan merged 2 commits into
masterfrom
claude/wonderful-wozniak-0qp911
Jun 28, 2026
Merged

security: fix critical/high/medium vulnerabilities (authcode AES-256-GCM, CSRF timing, cookies, UUID, logging)#14
biglyan merged 2 commits into
masterfrom
claude/wonderful-wozniak-0qp911

Conversation

@biglyan

@biglyan biglyan commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Summary

本 PR 对 PlumePHP 框架进行了全面安全加固,修复了代码审计中发现的所有 Critical、High、Medium 级别漏洞,335 个测试全部通过。


修复详情

立即修复(Critical / High)

文件 问题 修复
library/core/Plume/Libs/Action.php CSRF token 最终比较使用 ===,存在时序攻击 改为 hash_equals() 常量时间比较
library/core/Plume/Libs/Action.php setCookie() 缺少 HttpOnly / Secure / SameSite 新增三个安全属性参数,HTTPS 自动启用 Secure
library/core/Plume/Libs/Action.php CSRF 验证失败返回 401 语义错误 改为 403 Forbidden
library/Plume/Engine/Engine.php 生产环境 500 错误泄露 getMessage() / getCode() 生产环境返回通用提示,开发环境输出经 htmlspecialchars 转义
library/Plume/Engine/Engine.php session_start() 前未设置安全 ini 新增 httponly / use_strict_mode / samesite / HTTPS secure 配置
library/Plume/Engine/Engine.php BIZ 路径用黑名单过滤(str_replace('..')),可绕过 改为白名单正则 /^[a-zA-Z0-9_\-\.]+$/ + 逐 segment 校验
library/PlumeHelper.php signature() 使用 MD5,可被碰撞伪造 替换为 hash_hmac('sha256', ...)
library/PlumeHelper.php uuid() 使用 rand() / uniqid() / md5(),熵不足 使用 random_bytes(16) 生成符合 RFC 4122 v4 的 UUID
library/PlumeHelper.php authcode() 使用废弃的 MD5 + RC4 流加密(Discuz 遗产) 替换为 AES-256-GCM 认证加密,SHA-256 密钥派生,保留 $expiry 语义兼容性
library/PlumeHelper.php redirect() 未过滤 javascript: / data: URI,输出未转义 拦截危险协议,对 HTML 输出做 htmlspecialchars 转义

计划修复(Medium / Low)

文件 问题 修复
library/Plume/Engine/ActionInvoker.php 日志敏感字段过滤列表过少(仅 7 个) 扩充至涵盖 PII、支付、密钥等 30+ 字段,并增加子串模糊匹配兜底
library/Plume/Support/Logger.php 日志目录权限 0755(世界可读) 改为 0700(仅属主可读写)
library/Plume/Http/Router.php 路由缓存目录权限 0755 改为 0700
library/Plume/Support/View.php extract() 无标志,外部变量可覆盖内置变量 添加 EXTR_SKIP 标志

兼容性说明

  • authcode() 破坏性变更:新实现(AES-256-GCM)与旧实现(RC4)的密文格式不兼容。若应用中有旧密文存储在数据库/Cookie 中,需要在部署前完成数据迁移。
  • uuid() 格式变更:返回值由 32 位纯 hex 改为标准 UUID 格式(xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx),带前缀时格式为 prefix-uuid。已更新对应测试。
  • signature() 破坏性变更:输出由 MD5 hex(32 位)改为 HMAC-SHA256 hex(64 位)。若与外部系统(如微信支付)对接需要 MD5 签名,请在调用方自行使用 md5()
  • setCookie() 新增参数:新增 $httpOnly$secure$sameSite 参数,默认值向后兼容(true, auto, 'Lax')。

Test plan

  • ./vendor/bin/phpunit tests/ --no-coverage — 335 tests, 555 assertions, all passing
  • 验证 HTTPS 环境下 Cookie 正确携带 Secure 标志
  • 验证 authcode() ENCODE/DECODE 往返加解密正确
  • 验证 BIZ 路径含 .. 时正确抛出异常
  • 验证生产模式(plumephp.env=production)500 页面不暴露错误细节

🤖 Generated with Claude Code

https://claude.ai/code/session_01KbNQpz52cgzdcqPw3fhYbD


Generated by Claude Code

…n audit

立即修复:
- Action.php: 将 CSRF token 最终比较由 === 改为 hash_equals() 防止时序攻击
- Action.php: setCookie() 添加 HttpOnly/Secure/SameSite 安全属性(auto-detect HTTPS)
- Action.php: CSRF 验证失败响应码由 401 改为语义更准确的 403
- Engine.php: 生产环境 500 错误不再泄露 getMessage()/getCode(),开发环境输出经 htmlspecialchars 转义
- Engine.php: session_start() 前设置 httponly/strict_mode/samesite ini 选项
- Engine.php: BIZ 路径验证由黑名单改为白名单正则 + segment 逐段校验,防路径遍历
- PlumeHelper.php: signature() 由 md5() 替换为 hash_hmac('sha256', ...)
- PlumeHelper.php: uuid() 使用 random_bytes(16) 生成符合 RFC 4122 v4 的 UUID,弃用 rand()/uniqid()/md5
- PlumeHelper.php: authcode() 废弃 MD5+RC4,替换为 AES-256-GCM 认证加密,保持 expiry 语义兼容
- PlumeHelper.php: redirect() 拦截 javascript:/data:/vbscript: URI,对输出内容做 htmlspecialchars 转义

计划修复:
- ActionInvoker.php: sanitizeForLog() 敏感字段列表大幅扩充(PII/支付/密钥),新增子串模糊匹配兜底
- Logger.php: 日志目录权限由 0755 改为 0700(仅属主可读)
- Router.php: 路由缓存目录权限由 0755 改为 0700
- View.php: extract() 添加 EXTR_SKIP 防止外部变量覆盖内置变量

测试: 335 tests, 555 assertions, all passing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbNQpz52cgzdcqPw3fhYbD
@biglyan biglyan marked this pull request as ready for review June 28, 2026 01:45
setcookie() options array requires samesite to be one of the literal
union types 'Lax'|'lax'|'Strict'|'strict'|'None'|'none'. Add runtime
validation with fallback to 'Lax' and a @var annotation so PHPStan
can verify the narrowed type at the call site.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbNQpz52cgzdcqPw3fhYbD
@biglyan biglyan merged commit aa6a4de into master Jun 28, 2026
14 checks passed
@biglyan biglyan deleted the claude/wonderful-wozniak-0qp911 branch June 28, 2026 04:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants