
CodeIgniter 3.0.2 升级至 3.0.3 实战指南base_url 自动检测变更与 Host 头注入防护【免费下载链接】CodeIgniterOpen Source PHP Framework (originally from EllisLab)项目地址: https://gitcode.com/gh_mirrors/co/CodeIgniter本文面向正在使用 CodeIgniter 3.0.2 且计划升级到 3.0.3 的开发者系统梳理本次升级的两项关键操作——整体替换system/目录文件、以及手动配置base_url并深入剖析 3.0.3 中 base_url 自动检测逻辑的变更原因防御 Host 头注入与源码实现。读完本文你将能够安全地完成版本升级并掌握用 PHP 逻辑在配置文件中实现多域名、多协议动态 base_url 的实战方案。一、升级背景3.0.3 是一次安全修复版本在动手升级之前先了解这次升级的动机。根据 changelog.rstCodeIgniter 3.0.3 于 2015 年 10 月 31 日发布其核心内容属于安全修复修复了 Security 库xss_clean()方法中的一个 XSS 攻击向量更改了 Config 库的 base_url 自动检测逻辑当$config[base_url]为空时回退到$_SERVER[SERVER_ADDR]服务器 IP 地址而不是客户端请求的 Host 头以此避免Host 头注入Host header injection攻击CAPTCHA 辅助函数在可能的情况下改用操作系统提供的 PRNG 随机数生成器。此外3.0.3 还包含若干数据库、会话、事务相关的 Bug 修复详见 changelog 的 Bug fixes for 3.0.3 一节。其中与本次升级文档直接相关的就是base_url 自动检测行为的改变——它可能悄然改变现有站点生成的 URL。二、升级前的必要准备先让站点下线升级文档在开头明确要求在执行升级之前应先将站点下线。具体做法是把项目根目录下的 index.php 临时替换为一个静态页面例如一个包含 维护中 / 稍后回来 提示的静态 HTML 文件。这样做的目的是升级过程中访问者不会收到不完整的错误页面避免在文件替换的半途状态下有人触发 PHP 执行产生不可预期的行为升级完成后将静态 index.php 换回真正的框架入口文件即可恢复服务。这是所有 CodeIgniter 版本升级的标准前置操作务必在正式替换文件前完成。三、Step 1整体替换 system/ 目录下的文件升级的机械步骤非常简单用 3.0.3 版本中的全部文件和目录替换现有system/目录。需要注意的是替换范围是整个system/目录即本仓库中的 system/ 目录包含core/、database/、helpers/、libraries/、language/、fonts/等子目录不要替换application/目录——你的控制器、模型、视图、配置文件、辅助函数等业务代码都保存在这里版本升级不会动它们官方文档特别提醒如果你在system/目录中放置过自定义开发的文件例如改写过某个核心类请务必先复制备份再执行替换否则这些自定义改动会被覆盖丢失替换完成后用静态 index.php 换回真正的框架入口并验证站点功能。从源码结构看CodeIgniter 3.x 的核心类加载依赖system/core/下的 CodeIgniter.php、Common.php 等文件它们与application/config/config.php协同工作因此整体替换system/就能把 3.0.3 的安全修复如 Security.php 的 XSS 修复、Config.php 的 base_url 变更完整带入站点。四、Step 2确保 base_url 配置值非空4.1 为什么必须手动配置 base_url默认情况下application/config/config.php 中$config[base_url]的初始值是空字符串$config[base_url] ;当该值为空时CodeIgniter 会在 Config 类初始化时尝试自动检测站点 base URL。这种自动检测纯粹是为新应用开发起步阶段的便利而设计的官方文档明确指出自动检测从来都不可靠而且存在安全隐患因此你应当始终手动配置 base_url4.2 3.0.3 中自动检测逻辑的具体变更自动检测的逻辑实现在 system/core/Config.php 的构造函数中。3.0.3 之后的代码行为如下if (empty($this-config[base_url])) { if (isset($_SERVER[SERVER_ADDR])) { if (strpos($_SERVER[SERVER_ADDR], :) ! FALSE) { $server_addr [.$_SERVER[SERVER_ADDR].]; } else { $server_addr $_SERVER[SERVER_ADDR]; } $base_url (is_https() ? https : http).://.$server_addr .substr($_SERVER[SCRIPT_NAME], 0, strpos($_SERVER[SCRIPT_NAME], basename($_SERVER[SCRIPT_FILENAME]))); } else { $base_url http://localhost/; } $this-set_item(base_url, $base_url); }逐行解读这段关键源码判断依据改变3.0.3 之前自动检测会使用客户端请求的Host头$_SERVER[HTTP_HOST]来拼接 base URL3.0.3 之后改为使用$_SERVER[SERVER_ADDR]即服务器自身的 IP 地址。攻击者无法伪造服务器 IP这就堵死了通过伪造 Host 头影响站点生成 URL、进而实施注入攻击的路径。IPv6 地址处理如果SERVER_ADDR含冒号IPv6 地址会用方括号包裹例如http://[::1]/确保 URL 合法。协议判断通过is_https()定义于 system/core/Common.php判断当前请求是否为 HTTPS从而决定https://还是http://前缀。路径拼接在 IP 之后拼上入口脚本所在目录从SCRIPT_NAME中截取使自动生成的 URL 指向站点根目录。兜底逻辑若连SERVER_ADDR都不存在极少数 CLI 或异常环境则回退到http://localhost/。对你现有站点的影响如果你之前一直依赖自动检测即从未配置base_url升级到 3.0.3 后站点生成的链接会从客户端请求的域名变成服务器 IP 地址——站点行为将发生变化。这正是升级文档要专门用一个步骤提醒你手动配置的原因。4.3 手动配置最简单也最推荐的方案在 application/config/config.php 中直接填写站点地址即可$config[base_url] https://example.com/;注意结尾的反斜杠/——CodeIgniter 的site_url()/base_url()方法内部会调用slash_item(base_url)保证目录分隔符存在因此配置中显式带上结尾斜杠是推荐做法。手动配置后Config 构造函数中的自动检测分支将不再触发empty()判断为假。五、多域名 / 多协议动态 base_url 的实战方案官方文档特别指出如果你需要允许多个域名或者需要根据请求动态切换 http:// 与 https:// 前缀请记住application/config/config.php本质上仍是一个 PHP 脚本你可以用几行代码实现这一逻辑。下面是升级文档中给出的完整示例可直接复制到application/config/config.php中使用$allowed_domains array(domain1.tld, domain2.tld); $default_domain domain1.tld; if (in_array($_SERVER[HTTP_HOST], $allowed_domains, TRUE)) { $domain $_SERVER[HTTP_HOST]; } else { $domain $default_domain; } if ( ! empty($_SERVER[HTTPS])) { $config[base_url] https://.$domain; } else { $config[base_url] http://.$domain; }这个方案的工作流程是白名单校验定义允许的域名数组$allowed_domains并用in_array(..., TRUE)严格模式第三个参数TRUE表示严格类型比较校验$_SERVER[HTTP_HOST]是否在白名单内。只有通过校验的 Host 才会被采纳这本身就是对 Host 头注入的又一层防护——未列入白名单的任意 Host 都会被丢弃并回退到$default_domain。默认值兜底不在白名单内的请求统一使用$default_domain保证 URL 生成结果稳定可控。协议动态切换通过$_SERVER[HTTPS]是否非空判断请求是否走 HTTPS据此分别拼出https://或http://前缀。这样同一套配置即可同时服务 HTTP 与 HTTPS 两种入口。需要提醒的是示例中的域名与协议切换完全由 PHP 动态计算这要求$_SERVER变量可靠可用如果站点部署在反向代理如 Nginx 做 TLS 终止之后HTTPS变量可能需要由代理传递才能正确判断这一点在部署时需结合你的服务器环境验证。六、base_url 在框架中的实际使用路径手动配置base_url不只是为了配置项不报错它直接影响框架生成 URL 的所有环节。从源码看主要有两处消费该配置Config 库本身system/core/Config.php 的site_url()方法以base_url为前缀拼接index_page入口文件名与 URI 段base_url() 方法则直接基于base_url拼接 URI。两方法还支持通过$protocol参数生成协议相对链接传空字符串或切换协议该能力自 3.0.2 起引入。URL 辅助函数system/helpers/url_helper.php 中的site_url()与base_url()是视图模板中最常用的函数它们内部最终都会委托给 Config 库的对应方法。因此只要base_url配置正确视图中用base_url(assets/css/app.css)、site_url(news/view/1)等生成的所有链接都会自动指向正确地址。正因如此一个错误或不可靠的自动检测结果会导致全站链接CSS/JS 资源、跳转链接、分页、表单提交地址等整体出错这也是 3.0.3 升级文档把 base_url 列为必查项的根本原因。七、升级自检清单完成上述两步后建议按以下清单逐项验证确保升级干净利落升级前已用静态页面替换 index.php站点已下线system/目录已整体替换为 3.0.3 版本且自定义核心文件已事先备份application/config/config.php 中的$config[base_url]已手动配置为非空值固定域名或多域名/多协议动态逻辑换回真正的 index.php 后访问站点首页与若干深层路由确认页面正常渲染检查生成的 HTML 中资源链接、分页链接、表单 action 均指向正确域名与协议通过 changelog.rst 核对 3.0.3 的安全修复XSS、Host 头注入已随system/替换生效。如果你需要从更早的版本升级可先对照 升级总览 找到对应的版本路径升级到 3.0.3 之后的下一个版本是 3.0.4其升级说明见 upgrade_304.rst。按版本逐级升级、每次升级后回归验证是 CodeIgniter 长期演进中最稳妥的实践。【免费下载链接】CodeIgniterOpen Source PHP Framework (originally from EllisLab)项目地址: https://gitcode.com/gh_mirrors/co/CodeIgniter创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考