ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

CodeIgniter 4.7.4 安全与稳定性更新详解:四个安全公告与十余项缺陷修复

CodeIgniter 4.7.4 安全与稳定性更新详解:四个安全公告与十余项缺陷修复 后端Web框架【免费下载链接】CodeIgniter4Open Source PHP Framework (originally from EllisLab)项目地址https://gitcode.com/gh_mirrors/co/CodeIgniter4点击查看免费下载CodeIgniter 4.7.42026 年 7 月 7 日发布是一次以安全加固与稳定性修正为核心的维护版本重点修复了 HTTPS 检测信任代理绕过、批量删除 SQL 注入、上传文件路径穿越、上传校验扩展名绕过四类高危问题并同步修复了查询构造器、Transformer、加密、Session、验证规则等模块的十余个缺陷。本文以官方发布说明为骨架结合仓库源码逐一解析每个修复的成因、补丁行为与防御建议帮助你在升级后正确配置尤其是Config\App::$proxyIPs与上传校验规则彻底理解本次变更的影响范围。安全修复四个安全公告逐一拆解4.7.4 共修复了四个安全公告涉及的问题GHSA-7wmf-pw8j-mc78、GHSA-c9w5-rwh3-7pm9、GHSA-hhmc-q9hp-r662、GHSA-mmj4-63m4-r6h5全部属于攻击者可主动触发的输入处理缺陷以下按模块分别说明。1. HTTPS 检测不再轻信客户端头IncomingRequest::isSecure()问题此前IncomingRequest::isSecure()对X-Forwarded-Proto、Front-End-Https两个客户端可伪造的请求头过于信任。攻击者直接发送X-Forwarded-Proto: https即可让应用误判当前连接为 HTTPS从而绕过依赖必须走 HTTPS的强制跳转或安全策略。修复后的判定逻辑源码见 system/HTTP/IncomingRequest.php先检查真实服务器变量HTTPS来自$_SERVER[HTTPS]非空且不等于off时直接判定安全只有当请求确实来自Config\App::$proxyIPs中配置的受信代理时isFromTrustedProxy()实现见 system/HTTP/RequestTrait.php才允许读取X-Forwarded-Proto与Front-End-Https头否则一律返回false。isFromTrustedProxy()会比较REMOTE_ADDR与$proxyIPs的键名支持单个 IP 与 CIDR 子网含 IPv4/IPv6因此配置必须落在代理层// app/Config/App.php —— $proxyIPs 配置示例 public array $proxyIPs [ 10.0.1.200 X-Forwarded-For, // 单个代理 IP 192.168.5.0/24 X-Real-IP, // CIDR 子网 ];配置见 app/Config/App.php。要点只有真实反向代理的 IP 才应加入白名单且代理需自行剥离/覆盖客户端伪造的转发头若直接暴露在公网且未配置$proxyIPs则X-Forwarded-Proto等头将不再被信任这是本次修复的预期行为。2. 批量删除 SQL 注入deleteBatch()的 WHERE 绑定逃逸问题当deleteBatch()与where()条件组合使用时WHERE 子句中的绑定值在替换进最终 SQL 时忽略了逃逸标记escape标志既不转义也不加引号形成 SQL 注入通道。漏洞触发路径位于 system/Database/BaseBuilder.php 的deleteBatch()与批量 SQL 骨架构建逻辑。修复方式新增convertWhereBindsForBatch()system/Database/BaseBuilder.php在构建批量 SQL 时将QBWhere中的每个绑定值按原始绑定携带的escape标志统一走$this-db-escape()处理数组值则生成(v1,v2)形式使 WHERE 绑定的转义方式与普通delete()完全一致// 修复前概念绑定值原样拼入 WHERE id :w0: // 修复后绑定值经 escape() 转义后替换 WHERE id escaped_value对升级用户而言无需修改业务代码——只需确保批量删除仍通过 Query Builder 绑定传参不要手写拼接 SQL。3. 上传文件路径穿越UploadedFile::move()默认文件名消毒问题UploadedFile::move($targetPath)在未传第二个参数文件名时直接使用客户端原始文件名作为落盘名。攻击者可将文件名构造为../../public/shell.php利用路径穿越把文件写出目标目录、直达可执行目录。修复后行为源码见 system/HTTP/Files/UploadedFile.php省略第二个参数时文件名必须经过sanitize_filename()security helper清洗剥离路径穿越序列与危险字符显式传入第二个参数$name时不做消毒文件名合法性由调用方负责方法注释明确提示$name不会被净化。同时$targetPath参数本身也不会被消毒UploadedFile.php 的 docblock 已明确警告因此目标路径必须由应用代码控制绝不能用不可信输入拼接。4. 上传校验扩展名绕过is_image与mime_in规则升级问题is_image与mime_in两条上传校验规则此前只依据内容推导的 MIME 类型判定。攻击者把.php文件前面拼上图片魔数magic bytes即可骗过校验同时保留磁盘上的原始危险扩展名。修复后行为实现见 system/Validation/StrictRules/FileRules.phpis_image当客户端文件名扩展名非空时若该扩展名不是图片扩展名通过Mimes::guessTypeFromExtension()反查直接拒绝上传hasInvalidImageClientExtension()见 FileRules.phpmime_in当客户端扩展名非空时要求其与内容检测出的扩展名一致hasMismatchedClientExtension()FileRules.php即采用与ext_in相同的扩展名-内容一致判定两条规则还额外通过hasUnsafeClientFilename()FileRules.php拒绝尾点文件名、以及最终扩展名前带 PHP 扩展名的双扩展名攻击如shell.php.jpg无扩展名的上传如 JavaScript Blob 上传仍然放行因为校验依据的是文件内容而非文件名。实际使用示例$this-validate([ avatar uploaded[avatar]|is_image[avatar]|mime_in[avatar,image/jpg,image/jpeg,image/png]|max_size[avatar,2048], ]);缺陷修复按模块分类的十余项变更API / Transformerfields与include参数不再泄漏到嵌套 Transformer根请求的?fields...与?include...查询参数此前会渗透进include*()方法内部创建的嵌套 Transformer导致子资源字段过滤错误、出现意外的 include甚至触发无限递归。修复后的关键逻辑在 system/API/BaseTransformer.php仅当请求是显式传入的IncomingRequest或self::$depth 0根层级时才解析查询参数嵌套实例不再重复读取请求参数。include*()返回的嵌套 Transformer 应在transformMany()中独立处理参见 BaseTransformer.php。命令生成make:model --return entity保留子命名空间make:model生成关联 Entity 时丢失了子命名空间如Admin。修复在 system/Commands/Generators/ModelGenerator.php当--return entity时从类名推导出的 Entity 类会保留完整的子命名空间如Admin\User避免生成的类落在错误的命名空间导致自动加载失败。命令选项见 ModelGenerator.php。Commonenv()处理非字符串值、esc()编码传播修复env()此前在遇到非字符串值时如 CLI 下$_SERVER[argc]为 int、$_SERVER[argv]为数组会因strtolower()抛出TypeError。修复后在类型转换前先判断is_string()非字符串原样返回system/Common.phpesc()修复了编码参数$encoding的传播问题并消除引用泄漏数组递归转义时按引用遍历且Escaper实例按编码缓存复用system/Common.php保证非 UTF-8 场景下转义前后的编码往返一致。命令spark lang:find不再覆盖已有翻译lang:find --show-new此前把框架或其他命名空间如system/Language中的Errors.*已提供的翻译键当作新键误列到--show-new输出中并在无--show-new时把未翻译占位符写进app/Language覆盖现有翻译。命令定义见 system/Commands/Translation/LocalizationFinder.php用法# 只查看新增待翻译键不写文件 php spark lang:find --show-new # 指定语言与扫描目录后写入 php spark lang:find --locale zh-CN --dir Controllers配置BaseService::injectMock()统一小写化injectMock()此前未一致应用strtolower()导致 Service 注册名与 Mock 注入名大小写不一致时测试中的 Mock 无法命中。修复后注册、解析路径统一小写化system/Config/BaseService.php。数据库updateBatch()禁止与where()组合、XML 导出保留0值此前updateBatch()在已有where()条件时仍可调用但语义并不被支持产生不可预期的 SQL。现在一旦检测到QBWhere非空直接抛出DatabaseException并给出替代建议使用updateBatch($data, $constraints)、onConstraint()或把约束字段放入批量数据见 system/Database/BaseBuilder.phpBaseUtils::getXMLFromResult()生成的 XML 导出此前会把数值0/ 字符串0当作空值丢弃。修复后仅null与被转为空标签0正常保留system/Database/BaseUtils.php。加密SodiumHandler异常类型与blockSize处理system/Encryption/Handlers/SodiumHandler.php 修复了三类问题运行时仅覆盖blockSize而未传key时的处理非法密钥长度不再泄漏原生 Sodium 错误解密时blockSize不匹配时SodiumException被统一转换为EncryptionException如forAuthenticationFailed()避免框架向应用层抛出第三方异常类型。过滤器InvalidChars检查数组键InvalidChars过滤器此前只检查数组值未检查字符串类型的数组键中的非法 UTF-8 与控制字符。修复后checkEncoding()与checkControl()在遍历数组时对键同样执行校验system/Filters/InvalidChars.php使该过滤器对整棵输入树做到无死角覆盖。HTTPgetPostGet()/getGetPost()支持索引数组此前向IncomingRequest::getPostGet()或getGetPost()传入索引数组如[username, email]会抛出TypeError。修复后两者均支持数组索引逐个按键取 POST/GET 回退值并组装为关联数组返回system/HTTP/IncomingRequest.php。HTTPUser Agent 正确识别 Safari 浏览器版本User Agent 库此前把 Safari 的WebKit 内核版本误报为浏览器版本。修复在 system/HTTP/UserAgent.php当识别到 Safari 时改为从 UA 中的Version/...令牌解析真实浏览器版本。ModelobjectToRawArray()尊重$recursive参数BaseModel::objectToRawArray($object, $onlyChanged, $recursive)此前忽略了$recursive内部 Entity 不会被递归展开为数组。修复后该方法将$recursive原样传递给Entity::toRawArray()system/BaseModel.php含嵌套 Entity 的模型数据转换现在行为符合文档约定。安全CheckPhpIni容忍ini_get_all()返回null当ini_get_all()对某个配置指令返回null时CheckPhpIni可能抛出类型错误。修复后通过显式断言与?? 兜底保证指令缺失时输出disabled而非异常system/Security/CheckPhpIni.php。SessionRedisHandler尊重锁重试配置RedisHandler获取会话锁时此前无视配置的$lockMaxRetries与$lockRetryInterval。修复后构造函数从Config\Session读取这两个值system/Session/Handlers/RedisHandler.php重试循环按lockRetryInterval微秒间隔执行、最多lockMaxRetries次后放弃并报错RedisHandler.php。测试MockInputOutput不再破坏StreamFilterTrait的过滤器同一测试中同时使用MockInputOutput与StreamFilterTrait时前者的流过滤器拆装会连带拆除 trait 注册的过滤器导致tearDown()等阶段产生的 CLI 输出不再被捕获而泄漏到控制台。修复后MockInputOutput在挂载自身过滤器前快照共享CITestStreamFilter的状态结束后恢复system/Test/Mock/MockInputOutput.php保证两者可安全共存。验证required_without数组点号逻辑修正required_without使用点号数组语法如required_without[items.0.email]时此前存在两个问题早期continue退出导致忽略后续字段缺失键触发Undefined array key警告。修复后的逻辑system/Validation/Rules.php在遍历其他字段时非点号键直接查$data顶层点号键经dot_array_search()解析并用?? null安全取值缺失时正确返回false。升级建议与验证路径立即升级到 4.7.4四个安全修复均为攻击面较大的输入处理问题若使用反向代理务必配置 app/Config/App.php 的$proxyIPs否则 HTTPS 检测将回退为仅信任$_SERVER[HTTPS]检查所有UploadedFile::move()调用若依赖默认文件名现在会自动消毒若传了自定义$name请确认该名称来自可信来源对is_image/mime_in校验失败的既有上传业务如带非标准扩展名的图片需调整允许的扩展名/MIME 列表或改用无扩展名上传涉及updateBatch()的代码若与where()组合使用请按异常提示改写为constraints或onConstraint()方式。完整的缺陷修复清单可查阅仓库根目录的 CHANGELOG.md 与各版本的发布说明changelogs 目录相关的回归测试覆盖可在 tests/system 目录中按模块Database、HTTP、Validation、Encryption 等进一步追踪。赞分享后端Web框架【免费下载链接】CodeIgniter4Open Source PHP Framework (originally from EllisLab)项目地址https://gitcode.com/gh_mirrors/co/CodeIgniter4点击查看免费下载相关推荐CodeIgniter 4.7.5 更新详解setJSON()/setXML() 类型契约调整与 18 项缺陷修复全解析CodeIgniter 4.7.5 更新详解setJSON /setXML 类型契约调整与 18 项缺陷修复全解析 本篇技术指南以 CodeIgniter 4后端Web框架CodeIgniter 4.5.8 版本解析HTTP 头校验安全修复与 affectedRows、CSRF 两项缺陷修复CodeIgniter 4.5.8 版本解析HTTP 头校验安全修复与 affectedRows、CSRF 两项缺陷修复 本文围绕 CodeIgniter4后端Web框架Neon安全公告问题修复与安全更新通知Neon安全公告问题修复与安全更新通知 重要安全更新 Neon团队近期发现并修复了多个安全问题这些问题可能影响Neon Serverless Post数据库后端分布式数据库云原生上一篇告别格式混乱wangEditor 5自定义节点序列化完全指南下一篇SumatraPDF 中 Gumbo 解析器的 amalgamation 更新实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进