PHP 曝出 9.2 分漏洞后,C# 的“不可能三角”还成立吗
PHP 曝出 9.2 分漏洞后,我重新想了下"不可能三角"对 C# 成不成立 - 张善友
PHP 解释器被 AI 辅助工具扫出两个潜伏十余年的 UAF 漏洞 CVE-2026-109618 与 CVE-2026-109619(合称 PHP2Shell),CVSS v4.0 均为 9.2,无需认证即可远程执行代码。
前几天 PHP 出了件大事。
两个藏了十几年的漏洞被扒了出来:CVE-2026-109618 和 CVE-2026-109619,统称 PHP2Shell,CVSS v4.0 评分双双 9.2,无需认证即可远程执行代码。更要命的是发现方式——不是安全研究员逐行审计出来的,是 AI 辅助工具扫出来的。在 C 代码里埋了十多年,全世界没人看见。
出事的代码甚至不是 PHP 语言本身,是 PHP 解释器。
每当这种时候,技术圈总会有人搬出那个经典论调:编程语言存在"不可能三角"——功能强、易用、安全,三者最多占俩。PHP 常年被当成这个论点的头号证据。
作为一个常年写 C# 的人,我第一反应是:这个说法,对 C# 成立吗?
先把事件本身拆开看,再下结论。
一、这次翻车的,不是"PHP 这门语言"
很多人对 PHP 不安全的印象,还停留在语言层面:弱类型、unserialize、历史上各种魔幻默认值。但这次 PHP2Shell 跟这些都没关系。
两个漏洞的机制都很典型:
第一个(09618)出在内存耗尽的处理路径上。请求触发 OOM 时,解释器通过 longjmp() 直接跳到退出流程,导致请求内存还没初始化完,就被 shutdown 阶段的代码拿去用了。
第二个(09619)更直白:worker 进程的全局状态在上一个请求结束后没重置干净,下一个请求进来,访问到的是已经释放的内存。
两个都是 UAF(释放后使用),都是 C 手动内存管理最经典的死法。再配上 mod_php / PHP-FPM 这种共享 worker 进程模型——一个进程反复处理成百上千个请求,请求之间的状态边界全靠人手维护——出问题只是早晚的事。
划重点:它爆在"运行时实现层",不是"语言语义层"。PHP 解释器是一坨有二十多年历史的 C 代码,这才是事故真正的主角。
这个区别,直接决定了后面 C# 部分的结论。
二、"不可能三角"不是定理,是预算表
"功能强、易用、安全不可兼得"听起来很像 CAP 定理,但它没有数学证明,也不是物理定律。
它真正说的是:在工程资源有限的前提下,你必须在三个维度之间做取舍。各家语言的牌其实都是摊开的:
Rust 选了功能强和内存安全,代价是易用性——所有权和借用检查劝退了多少人,社区自己心里都有数。
Go 选了易用和内存安全,代价是表达力——泛型姗姗来迟,错误处理靠 if err != nil 复读。
PHP 当年选了易用和生态,安全交给开发者自律。这个选择在 2005 年没问题,在 2026 年就要还债。
那 C# 选了什么?
C# 的答案是:我全都要——但要付别的钱。

三、C# 的打法:把安全的成本转移给运行时
C# 用来换内存安全的筹码,不是开发者的头发(Rust 路线),而是运行时性能。
托管模型的这几个设计,让 PHP2Shell 这类漏洞在 C# 里几乎无从下手:
对象生命周期归 GC 管。托管堆里不存在"手工释放后复用"这回事,ASP.NET Core 的请求之间没有共享的可变内存池,"请求状态重置边界"这个概念压根不存在——09619 的成因直接落空。
边界检查是默认行为。数组、Span<T>、Memory<T> 全部带运行时边界检查。恶意构造的请求打到 Kestrel(C# 写的 HTTP 服务器),最坏的结果是抛异常,而不是踩内存。09618 那种"内存没初始化完就被消费"的路径,在托管代码里构造不出来。
危险操作必须显式声明。想玩裸指针?可以,写 unsafe,打开编译开关,代码评审时所有人都看得见。安全的实现方式从"靠程序员记得检查"变成"默认安全,越界留痕"。
IL 可验证。JIT 之前可以做类型系统层面的验证,类型混淆类漏洞在托管层被结构性排除。
所以我的结论是:这个"不可能三角"对 C# 基本不适用。它不是打破了三角,而是微软用几十年的工程投入——JIT 团队、GC 团队、MSRC 安全响应、整个工具链——把三角形硬生生撑大了。
反观 PHP,与其说是语言的原罪,不如说是一个资源有限的开源社区,在维护一个二十多年历史的 C 代码库。
三角困住的不是语言,是预算。
四、先别飘,C# 的安全边界在哪
说"不适用"不等于说"免疫"。C# 的账,记在别的地方:
CLR 本身就是 C++ 写的。CoreCLR 几十万行 C++,理论攻击面和 PHP 解释器同源。漏洞密度低一两个数量级是真的,但不是零。这次 AI 从陈年 C 代码里挖洞的模式,对所有 C/C++ 实现的运行时都是警钟——CLR、JVM、V8、CPython,谁也别笑谁。
逃逸舱一打开就打回原形。P/Invoke、COM 互操作、unsafe、Unity 生态里大片非托管代码——跨过这条线,你写的就是 C。
反序列化是祖传重灾区。BinaryFormatter 的 RCE 黑历史长到微软官方宣布弃用;Newtonsoft.Json 的 TypeNameHandling 配置不当,至今仍是经典入口。
应用层的洞,语言管不了。SQL 注入、XSS、SSRF、配置错误,C# 拦不住业务代码犯错。它只能给你好的默认值:EF Core 参数化、Razor 默认编码、防伪令牌。用不用,是你的事。
供应链不分语言。NuGet 包投毒和 npm、PyPI 面对的是同一类威胁,这是生态层的问题,语言帮不上忙。
写在最后
PHP2Shell 真正的教训,不是"PHP 不行",而是:
任何语言的安全上限,最终取决于它运行时实现层的内存安全性,以及维护那层代码的资源。
PHP 爆在了用 C 写的、历史包袱沉重的解释器上。C# 把同类风险压缩到了 CLR 这一个更小、被重兵把守的面上——这是工程投入的差异,不是语言哲学的胜负。
至于"不可能三角",下次再有人拿它说事,可以回一句:
三角困不住语言,三角困住的是预算。
参考链接
事件综述
- 维基百科:PHP2Shell —— https://zh.wikipedia.org/zh-cn/PHP2Shell
- PHP2Shell 事件官网(漏洞发现方 Calif / Wiz 维护) —— https://www.php2shell.com/
漏洞技术细节
- 腾讯云安全通告:longjmp 提前退出与跨请求全局状态残留的完整机制 —— https://cloud.tencent.com/announce/detail/2525
- 阿里云文档:PHP2Shell 漏洞影响范围与修复建议 —— https://help.aliyun.com/zh/alinux/product-overview/cve-2026-109618-cve-2026-109619-vulnerability-remediation-instructions
- PHP 官方安全公告(GHSA-w8hw-w9fx-j79w / GHSA-6wmf-4rv5-p3rp) —— https://github.com/php/php-src/security/advisories
发现过程与全球影响
- CBS News:What to know about the PHP bug affecting 70% of the world's websites —— https://www.cbsnews.com/news/php2shell-vulnerability-ai-security-flaw/
- Newsweek:维基百科预防性下线部分系统,荷兰、芬兰、法国等政府网站临时关闭 —— https://tech.yahoo.com/cybersecurity/articles/php-vulnerability-sparks-scramble-major-190358953.html
- 界面新闻:腾讯云、谷歌紧急预警,PHP 高危漏洞波及全球互联网 —— https://m.jiemian.com/article/15223103.html
.NET 侧背景
- Microsoft Learn:BinaryFormatter 安全风险指南(官方弃用说明) —— https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide
- InfoWorld:Microsoft cuts BinaryFormatter from .NET 9 —— https://www.infoworld.com/article/3497772/microsoft-cuts-binaryformatter-from-net-9.html
来源:博客园 · cnblogs.com