ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

PHPMailer 安全公告深度解析:从 CVE-2005-1807 到 CVE-2021-3603 的漏洞演进与修复源码

2026/9/13 17:21:32 拓冰建站 浏览量
PHPMailer 安全公告深度解析:从 CVE-2005-1807 到 CVE-2021-3603 的漏洞演进与修复源码 PHPMailer 安全公告深度解析从 CVE-2005-1807 到 CVE-2021-3603 的漏洞演进与修复源码【免费下载链接】PHPMailerThe classic email sending library for PHP项目地址: https://gitcode.com/GitHub_Trending/ph/PHPMailerPHPMailer 是 PHP 生态中使用最广泛的邮件发送库之一其 SECURITY.md 记录了从 2005 年至今十余年的完整漏洞披露时间线。本文以该文档为主线逐一剖析每个 CVE 的成因、影响范围与修复方案并结合当前仓库版本 6.9.3见 VERSION中的 src/PHPMailer.php 源码与 test 目录下的测试用例讲清漏洞在哪里、为什么会被利用、如今如何被堵死帮助开发者理解 PHPMailer 的安全模型并给出可落地的升级与防御建议。漏洞披露渠道先私下报告再公开发布SECURITY.md 开篇即明确了 PHPMailer 的漏洞处理流程任何安全问题或漏洞都应当通过 Tidelift 的协调披露系统coordinated disclosure提交或私下联系维护者而不是直接在公开的 issue 跟踪器中讨论。这是一种负责任披露Responsible Disclosure的实践——先给维护者留出修复与发布的时间窗口避免 0-day 被公开滥用。从文档记录可以看出历史上多数漏洞正是经由这一渠道进入修复流程的例如 CVE-2021-34551 由吉林谛听信息技术有限公司经 Tidelift 上报CVE-2021-3603 由 Vikrant Singh Chauhan 经 huntr.dev 平台上报。作为使用者如果你在项目中发现了疑似安全问题应当遵循同样的渠道而不是在公开论坛发布细节。漏洞时间线总览SECURITY.md 按从新到旧的顺序记录了历次安全公告下表按修复版本从早到晚整理便于对照升级CVE 编号影响版本漏洞类型首次修复版本CVE-2005-1807≤ 1.7.2潜在 DDoS 漏洞1.7.2 之后CVE-2007-3215≤ 1.7SendmailSend方法中 shell 命令可能未消毒1.7 之后CVE-2006-5734 / CVE-2007-2021 / CVE-2010-4914早期版本SetLanguage的$lang_path未清理导致半任意本地文件包含各版本逐步收紧CVE-2011-3747Joomla 1.6.0第三方对 PHPMailer 的不安全使用泄露本地文件路径属 Joomla 侧问题CVE-2012-0796 2.0.7 / 2.2.1邮件头注入Email header injection2.0.7 / 2.2.1CVE-2008-5619 5.2.10内置 html2text 库远程代码执行5.2.10直接移除该库CVE-2015-8476 5.2.14SMTP CRLF 注入可任意发送邮件5.2.14CVE-2016-10033 5.2.18远程代码执行5.2.18CVE-2016-10045 5.2.20远程代码执行补丁绕过5.2.20CVE-2017-5223 5.2.22本地文件泄露5.2.22CVE-2017-11503 5.2.24示例代码 XSS5.2.24CVE-2018-19296 6.0.6 / 5.2.27phar://路径对象注入可能 RCE6.0.6 / 5.2.27CVE-2020-13625≤ 6.1.5附件文件名引号导致输出转义缺陷6.1.5 之后CVE-2020-363266.1.8 – 6.4.0CVE-2018-19296 的回归6.4.1CVE-2021-34551≤ 6.4.1setLanguage()的$lang_path可指向 UNC 路径导致 RCE6.5.0CVE-2021-3603≤ 6.4.1validateAddress()自定义校验器被劫持未信任代码执行6.5.0值得注意的是SECURITY.md 同时指出PHPMailer 5.2 系列已停止维护即使安全更新也不再提供见 README.md 的 Legacy versions 一节仍在生产环境使用 5.2 及更早版本的项目应当立即迁移到 6.x。近期高危漏洞与源码级修复分析CVE-2021-3603validateAddress()校验器名称被劫持这是影响 6.4.1 及更早版本的一个未信任代码执行漏洞。漏洞机理如下validateAddress($address, $patternselect)的$patternselect参数默认为php由静态属性PHPMailer::$validator定义表示使用 PHP 内置的filter_var($address, FILTER_VALIDATE_EMAIL)进行校验如果主机项目的作用域内恰好定义了一个名为php的函数例如攻击者通过其他途径向全局命名空间注入了恶意函数旧的实现会把php字符串当作可调用函数名去调用优先于内置校验逻辑执行从而达成任意代码执行。当前 src/PHPMailer.php 中的修复是拒绝使用简单字符串作为校验函数名只允许真正可调用的非字符串对象public static function validateAddress($address, $patternselect null) { if (null $patternselect) { $patternselect static::$validator; } //Dont allow strings as callables, see SECURITY.md and CVE-2021-3603 if (is_callable($patternselect) !is_string($patternselect)) { return call_user_func($patternselect, $address); } //Reject line breaks in addresses; its valid RFC5322, but not RFC5321 if (strpos($address, \n) ! false || strpos($address, \r) ! false) { return false; } ... }源码中的注释直接引用了 SECURITY.md 与 CVE-2021-3603属于典型的修复即留证。同时该方法还顺带拒绝了包含换行符的地址虽然 RFC5322 允许但 RFC5321 不允许且换行是注入攻击的载体。相关的校验行为可在 test/PHPMailer/ValidateAddressTest.php 与 test/PHPMailer/ValidateAddressCustomValidatorTest.php 中看到覆盖。CVE-2021-34551setLanguage()的$lang_path导致远程代码执行影响 6.4.1 及更早版本的另一个高危漏洞同样属于不可信输入进入文件操作的经典模式setLanguage($langcode, $lang_path)用于加载 language/ 目录下的翻译文件旧实现直接对$lang_path指定的文件做 PHP 代码处理加载执行如果$lang_path来自未过滤的用户输入可被设置为 UNC 路径形如\\server\share\...攻击者若能诱使服务器从该 UNC 路径加载脚本文件则其控制的脚本可能被执行该漏洞只在能够解析 UNC 路径的系统上生效通常仅限 Microsoft Windows。6.5.0 的修复思路是不再把翻译文件当作 PHP 代码执行而是直接按文本解析其内容。当前 src/PHPMailer.php 的实现可见端倪——加载文件后逐行用正则匹配$PHPMAILER_LANG[key] value;形式的文本仅提取键值对$lines file($lang_file); foreach ($lines as $line) { //Translation file lines look like this: //$PHPMAILER_LANG[authenticate] SMTP-Fehler: Authentifizierung fehlgeschlagen.; //These files are parsed as text and not PHP so as to avoid the possibility of code injection $matches []; if ( preg_match( /^\$PHPMAILER_LANG\[\([a-z\d_])\\]\s*\s*([\])(.)*?\2;/, $line, $matches ) //Ignore unknown translation keys array_key_exists($matches[1], $PHPMAILER_LANG) ) { //Overwrite language-specific strings so well never have missing translation keys. $PHPMAILER_LANG[$matches[1]] (string)$matches[3]; } }源码注释再次直接点明parsed as text and not PHP so as to avoid the possibility of code injection。此外setLanguage()对语言代码本身也做了白名单式正则校验/^(?Plang[a-z]{2})(?Pscript_[a-z]{4})?(?Pcountry_[a-z]{2})?$/并支持旧语言代码的自动映射如cz→cs、dk→da。翻译覆盖度可由 test/Language/TranslationCompletenessTest.php 验证语言加载逻辑的测试见 test/PHPMailer/LocalizationTest.php。文档同时提示当前的翻译格式已被标记为弃用将在下一个大版本中替换因为按文本解析只是安全与兼容之间的折中方案并非理想设计。CVE-2020-36326对象注入漏洞的回归CVE-2018-19296 曾在 6.1.8 中因修复 Windows UNC 路径问题而被意外回归影响 6.1.8 至 6.4.06.4.1 修复该回归并加强了对本地路径上下文中 URL scheme 的检查。这正是当前 src/PHPMailer.php 中isPermittedPath()与fileIsAccessible()两个方法的职责所在/** * Check whether a file path is of a permitted type. * Used to reject URLs and phar files from functions that access local file paths, * such as addAttachment. */ protected static function isPermittedPath($path) { //Matches scheme definition from https://www.rfc-editor.org/rfc/rfc3986#section-3.1 return !preg_match(#^[a-z][a-z\d.-]*://#i, $path); } protected static function fileIsAccessible($path) { if (!static::isPermittedPath($path)) { return false; } $readable is_file($path); //If not a UNC path (expected to start with \\), check read permission, see #2069 if (strpos($path, \\\\) ! 0) { $readable $readable is_readable($path); } return $readable; }也就是说任何形如phar://、http://等带 URL 协议前缀的路径在进入addAttachment()、DKIM 私钥加载src/PHPMailer.php 处同样调用isPermittedPath()等本地文件操作之前就会被拦截。对应的单元测试见 test/PHPMailer/IsPermittedPathTest.php 与 test/PHPMailer/FileIsAccessibleTest.php。这套机制是纵深防御的典型体现即使上层调用方忘了过滤用户输入底层文件访问也会把协议封装wrapper路径拒之门外。CVE-2020-13625附件文件名中的双引号绕过过滤影响 6.1.5 及更早版本的输出转义缺陷当传入addAttachment()及其他接受附件文件名的方法的文件名包含双引号字符时违反 RFC822 3.4.1Content-Type与Content-Disposition头中的输出转义存在问题。文档明确指出虽然当时未发现具体的可利用漏洞但可能允许附件绕过基于文件名扩展名匹配的附件过滤器——例如网关只拦截.php而evil.php这种畸形名可能在头解析时错位。这一案例提醒我们邮件头字段的构造必须严格符合 RFC任何看起来没出事的偏差都可能在特定收件端或安全网关处被放大。经典历史漏洞RCE、对象注入与文件泄露CVE-2018-19296phar://对象注入影响 6.0.6 与 5.2.27 之前版本。向addAttachment()及其他可能接收未过滤本地路径的函数传入phar://路径可触发 PHP 反序列化Phar 元数据反序列化可能导致远程代码执行。修复方式是阻断任何带 URL 协议风格前缀如phar://的路径——即前述isPermittedPath()的由来。文档建议对该类漏洞感兴趣的读者研究 PHP phar 反序列化利用原理。CVE-2017-11503示例代码 XSS影响 5.2.24 之前版本。code_generator.phps示例未对用户输入过滤即输出存在 XSS。需要注意两点缓解因素该文件以.phps扩展名分发默认不会被执行除非显式重命名通过 Composer 加载 PHPMailer 时并不包含该文件因此默认状态下是安全的。此外默认异常处理器默认未启用也存在一个未公开披露的潜在 XSS 问题。两个问题均由 Fedora 项目的 Patrick Monnerat 提供补丁。CVE-2017-5223msgHTML()本地文件泄露影响 5.2.22 之前版本。当传入msgHTML()的内容来源于未过滤的用户输入时相对路径会被解析为绝对本地文件路径并作为附件加入邮件造成本地文件泄露。当前 src/PHPMailer.php 的msgHTML()实现对此做了多重防护从源码可以看出处理逻辑相当谨慎仅当提供了$basedir时才处理相对 URL避免无依据的绝对本地路径探测忽略包含..目录穿越的 URL不改写已经是cid:的内联图片不改写带协议前缀的绝对 URL包括data:URI 则走独立的数据内嵌路径基于内容 SHA-256 哈希生成 cid见 src/PHPMailer.php。文档同时给出了一条通用安全铁律addAttachment()和file_get_contents、passthru、unlink等函数一样绝不应接收用户来源的参数。这条规则适用于所有接受文件路径的 API。CVE-2016-10033 / CVE-2016-10045远程代码执行双子星2016 年底连续曝出的两个 RCE 漏洞分别影响 5.2.18 与 5.2.20 之前版本是 PHPMailer 历史上最受关注的安全事件攻击者可通过精心构造的Sender等邮件头字段利用mail()函数的参数注入实现任意命令执行CVE-2016-10045 则是第一个补丁的绕过。修复由社区成员 Paul BuonopaneZenexer完成。此后 PHPMailer 系列对邮件头字段的构造与转义做了系统性加固这也是 README 中保护免受邮件头注入攻击特性的由来。更早期的安全记录与第三方责任边界SECURITY.md 还保留了若干更早的公告虽已远离现代版本但仍有借鉴意义CVE-2015-8476 5.2.14SMTP CRLF 注入允许攻击者插入额外命令实现任意邮件发送CVE-2008-5619 5.2.10内置 html2text 库存在 RCE5.2.10 直接移除了该文件。文档强调如果仍在使用 5.2.10 之前的版本且用到 html2text 函数必须立即升级并删除该文件CVE-2012-0796 2.0.7 / 2.2.1邮件头注入CVE-2011-3747这是第三方责任的典型案例——Joomla 1.6.0 以不安全的方式使用 PHPMailer导致本地文件路径泄露。漏洞在 Joomla 侧而非 PHPMailer 自身说明了库安全不等于应用安全的道理CVE-2010-4914 / CVE-2007-2021 / CVE-2006-5734SetLanguage的$lang_path参数未清理。文档特别指出PHPMailer 自身未清理该参数本身不是问题但 PHPClassifieds、ATutor 等应用未对传入的用户参数消毒才导致半任意本地文件包含。这与 CVE-2021-34551 是同一参数在不同时代的两次教训CVE-2005-1807≤ 1.7.2潜在 DDoSCVE-2007-3215≤ 1.7SendmailSend方法中 shell 命令可能未消毒。面向开发者的安全实践清单结合 SECURITY.md 的公告与当前源码实现可以提炼出四条可直接落地的实践立即升级并保持更新5.2 系列已停止安全维护任何仍在使用 5.2.x 或更早版本的项目都处于已知漏洞暴露面中。当前仓库版本为 6.9.3VERSION建议通过composer require phpmailer/phpmailer安装并定期执行composer update从 5.2 迁移到 6.x 的注意事项见 UPGRADING.md。永远不要把用户输入直接传给文件路径类 APIaddAttachment()、msgHTML()的$basedir、setLanguage()的$lang_path、DKIM 私钥路径都属于此类。即使库内部已有isPermittedPath()兜底应用层过滤才是第一道防线。不要依赖自定义字符串作为回调validateAddress()自 6.5.0 起已拒绝字符串形式的校验函数名CVE-2021-3603 的直接教训自定义校验请传入闭包或可调用对象而不是函数名字符串。留意弃用警告翻译文件按文本解析仅是过渡方案官方已明确将在下个主版本更换格式升级前应关注 changelog.md 中的破坏性变更说明。结语从 2005 年的 DDoS 隐患到 2021 年的两枚高危 CVESECURITY.md 堪称一部 PHP 邮件库的安全演进史。它的价值不止于公告本身——当你把每一条公告与 src/PHPMailer.php 中对应的修复代码isPermittedPath、validateAddress、setLanguage、msgHTML以及 test 目录下的回归测试对照阅读时就能清晰地看到安全工程中发现漏洞 → 修复 → 防回归 → 测试固化的完整闭环。对使用者而言最重要的结论始终只有一个及时升级并始终把外部输入挡在文件操作与回调机制之外。【免费下载链接】PHPMailerThe classic email sending library for PHP项目地址: https://gitcode.com/GitHub_Trending/ph/PHPMailer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考