这两年因为业务需要我一直在跟各种“年代感”十足的企业系统打交道其中碰到最多的两类技术遗产就是Java小程序和ActiveX控件。很多人一听到这两个词就觉得是化石但在银行、制造、政务、教育这些行业里大量核心业务页面仍然依赖它们才能正常干活。更麻烦的是这些技术的安全模型已经多年没人真正维护了属于典型的“还能开但玻璃已经裂了”的状态。这篇文章我想从攻防视角把这两项技术的老底翻出来看看客户端控制到底是怎么设计的、为什么会被绕过、以及作为防御方我们应该从哪些角度来加固和排查。先说一个基本判断研究“绕过客户端控制”并不是为了教人干坏事而是因为如果连攻击者怎么想、怎么做都不清楚防御加固就永远是空的。安全领域有一条老规矩叫“不知道敌人怎么进的门就永远不知道自己家的锁有多没用”。所以这篇文章的落点始终是检测、排查和加固素材全部来自真实场景中常见的技术问题和安全事件形态不会涉及任何具体的RCE利用链或越权工具。1. 为什么这两项老技术还是攻防热点1.1 Java小程序的前世今生Java小程序Applet最早是作为网页里跑的“富客户端”出现的核心思路是浏览器把Java字节码下载到本地然后交给浏览器内置的JVM来执行。它能做动画、图表、报表甚至能做完整的业务客户端在那个Web技术还很原始的年代这几乎是唯一能在网页里实现复杂交互的方案。安全上Java为Applet设计了所谓的“沙箱机制”即未经签名的Applet默认跑在受限环境里没有文件读写、网络连接、系统属性访问等权限经过签名且获得用户许可的Applet则被放到信任域拥有完整权限。这个设计本身是合理的问题出在后面——JVM的安全组件庞杂、版本迭代频繁而且浏览器端旧版本JVM长期残留导致“沙箱逃逸”类漏洞在2010年前后集中爆发。也正因为如此主流浏览器陆续放弃了对Java插件的支持Java官方也在2017年前后正式把Applet与浏览器插件从技术路线中移除。但业务的迁移永远比技术宣言慢得多。很多单位的旧版报表系统、电子签章、单点登录组件、专用硬件管理页面至今还在用Applet实现关键交互没有它们业务就跑不起来。1.2 ActiveX控件的存在逻辑ActiveX是IE时代另一套客户端扩展机制本质上是将编译好的本地组件对象注册到系统中然后通过网页里的对象标签加载和调用。它比Applet更“野”因为ActiveX一旦被信任运行手上就握着本地操作系统的完整访问能力可以读文件、写注册表、启动进程、调用任意系统API。浏览器为了控制这个“猛兽”设计了安全区域策略把站点分成Internet、本地Intranet、受信任站点、受限站点几个等级不同等级允许或禁止ActiveX的行为。同时下载运行ActiveX必须以代码签名为准浏览器会检查发布者身份和签名有效性再结合用户确认弹窗来授予“放行”权力。ActiveX最大的历史包袱是它太容易写也太容易出漏洞。随便一个商用软件厂商都能写个ActiveX控件然后塞进网页里而这类控件的代码质量往往不高C语言的内存错误再加上权限直接拉满缓冲区溢出几乎成了ActiveX的代名词。XP时代针对浏览器的网页挂马攻击大量就是以ActiveX漏洞为入口展开的。1.3 如今还在哪些角落里服役如果你想当然地以为这些技术已经退出江湖那说明你还没有去一线巡检过。我自己的实际经历里至少这几类场景都还重度依赖它们。老牌ERP和OA系统的附件预览、打印模板参数设置报表引擎的交互端。银行网银、证券交易系统的U盾管理、安全输入控件很多仍然通过ActiveX或Applet与本地硬件交互。设备网管页面例如机房精密空调、UPS、老式打印机、投影仪的管理后台有的还要求安装配套ActiveX控件。部分高校和培训机构的老版多媒体教学系统、考试系统客户端端是Java小程序做的答题界面。工业控制系统的上位机配置页面指纹识别、人脸比对等专用设备的本地驱动调用。上半年我给某家单位做例行安全评估光是扫描内网业务系统就找出了47个页面还在加载ActiveX控件其中12个控件的代码签名证书早已过期还有几个控件厂商都已经不存在了。这不是孤例而是大量传统企业的普遍现状。2. 客户端控制机制是如何设计的要理解“绕过”先得理解“控制”。这一节我先把两项技术各自的安全防线拆开讲清楚后面再说攻击者通常从哪些角度突破。2.1 Java小程序的控制链路沙箱、类加载与签名Java的客户端控制体系主要由三块构成。第一块是类加载器。浏览器在加载Applet时会用专用的类加载器去读取远端字节码它负责把“来自外部网络的代码”和“本地核心API”隔离成不同的命名空间使宿主环境的核心库不能被装进来的代码随意篡改。应用代码里不能直接访问或者替换内部类对象。第二块是安全管理器。Java运行时里维护着一个全局安全管理器实例当代码想要执行文件操作、网络连接、打开新窗口这类敏感行为时核心类库会先调用安全管理器的检查方法如果权限不足就直接抛异常。注意这个安全逻辑是运行时强制执行的而不是靠开发者自己自觉所以攻击者要做的就是绕过安全检查逻辑本身。第三块是JDK 1.2以后引入的访问控制机制引入了“代码从哪里来”的维度。每个类文件都带有代码源属性系统根据代码源与权限策略计算最终能否执行某个操作。未签名Applet只会得到一个极其狭窄的基础权限签名Applet会弹窗询问是否信任如果信任则获得更高权限甚至完整权限。这套机制在纸面上相当严密但它依赖一个前提——JVM内部实现不能有漏洞。而历史上大量漏洞恰恰出在JVM实现本身有的漏洞能让沙箱内代码直接拿到系统内部对象的引用有的能通过序列化、类型混淆等途径逃逸出沙箱。只要JVM出现一个这种漏洞安全模型就被从底部击穿了。2.2 ActiveX由什么来管区域策略、签名与KillbitActiveX的安全控制分成了好几层。第一层是浏览器安全区域的隔离。Internet区域默认情况下对未签名的ActiveX是禁止运行或需要确认的本地Intranet区域的策略相对宽松受信任站点区域可以运行几乎所有ActiveX受限站点区域则一概禁止。浏览器在加载一个ActiveX控件时会根据页面所在的URL归属判断当前区域再按区域策略决定控件的下载和执行权限。第二层是代码签名校验。生产ActiveX的厂商需要拿代码签名证书对编译产物进行数字签名浏览器下载后首先校验签名链是否有效、证书是否过期或被吊销。签名验证通过后浏览器再弹窗询问用户“是否允许安装此控件”用户点了“是”系统才会把它注册为可用组件。第三层是Killbit机制。这是微软为“禁用特定ActiveX控件”给出的官方手段——通过修改注册表里组件类标识的兼容标志位强制浏览器拒绝加载该控件即使这个控件已经被安装并且有合法签名。网络安全更新补丁通常就是为一系列已知漏洞控件设置Killbit从而阻断攻击入口。有了这三层正常流程下想运行一个ActiveX确实不容易但每一层都存在被突破的可能安全区域可以靠注册表错误配置放宽签名校验可能因为证书链检查不严格被伪造用户可能在“证书发布者不可识别”的弹窗上盲目点“是”Killbit也可能没有覆盖到所有有漏洞的控件。2.3 两者的共同边界信任链一旦断裂就全盘皆输把Java小程序和ActiveX的机制摆在一起会发现它们走的其实是同一套模型代码从外部来系统在运行前对它做身份认证再根据身份决定权限。Java用的是“代码签名 沙箱”ActiveX用的是“代码签名 区域策略”。模型通畅的前提是攻击者无法伪造身份、无法绕过权限判定、无法突破运行时隔离。所以“绕过客户端控制”这个命题本质上就是在问攻击者能否做到其中任意一条以及系统有没有因为版本老旧、配置失误或用户误操作而主动把这条防线“送”出去。搞清楚了这一点再看各种攻击案例时就会觉得它们并不玄妙就是冲着信任链上的薄弱环节去的。3. 攻击者习惯从哪些角度下手这节的内容不是教读者去复现攻击而是以防御审计的角度把攻击者常用的突破路径梳理出来。知道了这些路径你才能在自己的环境里按图索骥地去找对应的风险点。3.1 针对Java小程序的攻击面在Java插件还开放的年代攻击者最常用的手段是诱导用户访问挂马页面再通过Java沙箱漏洞直接获得代码执行权限。这类攻击的核心不是Applet业务逻辑写得多巧妙而是JVM本体存在被利用的缺陷。由于老版本JRE在用户机器上残留极广哪怕只有一台机器还在用2013年以前的运行时整个办公网都等于留了一扇朝外开的门。另一种路径是“假签名Applet”。攻击者注册或者盗用一张代码签名证书给恶意Applet签名然后通过社交渠道诱导用户点击“信任”按钮。在这种场景里技术层面的沙箱其实没有被绕过攻击者骗的是“人”这个环节。签名一旦被信任Applet就变成了本地完整权限的程序后续想干什么都行。还有一个往往被忽视的攻击面是Java部署缓存。Java在小程序运行时会把缓存文件写入本地目录的缓存文件夹中如果用户访问过恶意页面这个文件夹里会留下精心构造的jar包或class文件。安全团队在排查时如果忽略这个文件夹就很容易漏掉关键攻击痕迹。3.2 针对ActiveX的攻击面ActiveX的攻击故事比Java还要密集。最粗放的攻击路径是直接找已安装控件里的缓冲区溢出漏洞只要页面能加载这个控件攻击者就可以构造特殊的参数让控件处理数据时触发内存破坏进而获得代码执行权限。那些无人维护、没有补丁、没有Killbit的老控件几乎是白送。第二种常见的攻击路径是“区域跨越”。有些单位的网络管理员为了方便把部分业务域名直接加进了受信任站点区域而且这个区域启用了“允许运行未签名ActiveX控件”的策略。攻击者只要能让受害用户访问任意一个受信任域名下的页面——比如通过子域名劫持、存储型XSS、或者直接利用该域名上的上传功能——就能在受信任区域框架里加载任意ActiveX原有的区域隔离形同虚设。第三种路径是“静默加载”。正常情况下浏览器加载ActiveX会弹窗确认但浏览器中一些允许脚本自动实例化控件的设置、或者某些控件自身提供了“标记为安全可脚本化”属性会让控件无需用户交互即可被脚本调用。攻击者利用这一点可以让用户在不知不觉间加载并调用一个有漏洞的控件。3.3 控制失效的三种典型模式把以上攻击路径抽象出来可以发现所有“绕过客户端控制”最终都落进三个模式里一是“沙箱失效”即隔离机制本身被攻击者用漏洞击穿二是“身份假冒”即攻击者伪造或盗用了信任身份三是“交互滥用”即攻击者利用提示弹窗、区域信任等交互机制诱导用户作出错误决定。做防御时不一定要把所有漏洞都堵死把这三种失效模式分别对应上排查清单反而更高效。看到沙箱失效就去清点JRE版本和漏洞补丁看到身份假冒就去核查证书链和已安装组件的签名状态看到交互滥用就去审查弹窗策略、受信任站点列表和用户安全意识培训情况。4. 防御与加固把门槛抬到足够高攻击面清楚了接下来就进入正题作为防御方我们能做什么。这一节给的方案都是拿实际环境验证过、明确可操作的不需要什么“零信任神兵”就是基础的资产管理和配置加固。4.1 第一步永远是资产体检不要一上来就想着关插件、禁用控件因为很多业务系统会立刻罢工业务部门会找到你头上。正确的做法是先搞清楚到底还有哪些页面在用这些技术、用到了什么程度、有没有替代方案。具体排查动作有三个都很土但非常有效抓内网HTTP请求日志或者流量镜像筛出包含小程序、控件加载关键字的响应定位加载页面。直接叫上运维和开发一起翻业务系统的页面源码找出嵌入的标签和对象标签。终端侧用软件清单盘点工具统计每个终端的Java运行环境列表和已注册ActiveX组件列表。做完这步你会得到一张“技术债地图”后面所有加固动作都应该按这张图来排优先级。那些只在一台特定机器、一个特定页面上出现的组件优先评估全公司都依赖的核心组件要特别谨慎地处理。4.2 Java侧加固的实操要点如果确认还依赖Java小程序第一原则是“能关就关、能清就清、能锁就锁”。先说“能关就关”。把浏览器插件里所有Java相关内容禁用这是大方向。但要注意如果你的业务系统真的还在用Applet贸然全禁会导致业务不可用。折中方案是启用“点击播放/点击运行”模式让浏览器默认不加载Java内容只有当用户主动点击页面上的占位符时才运行。这样至少切断了“访问页面即中招”的静默利用链。再说“能清就清”。终端上往往残留着多个历史版本的JRE这是漏洞重灾区。应该做一次全面的存量清理只保留业务所需的最后一个受支持版本其余全部卸载。卸载后还要检查部署缓存目录确保没有遗留的jar包缓存。最后检查浏览器的Java插件配置确认“启用Java内容”和“启用安全级别”都设置为最严格档位。“能锁就锁”的意思是对于确实需要运行的少量Applet先验签证书再把它所在的业务URL加入“站点例外”列表并且只对指定终端开放其他终端一律保持禁用状态。这条策略能把“攻击面”从“全网任意浏览页面”收窄到“极少数受控终端访问固定URL”风险等级完全不一样。4.3 ActiveX侧加固的实操要点ActiveX加固的关键词是“区域策略、Killbit、白名单”。区域策略上要把Internet区域里所有ActiveX相关选项全部设为“禁用”或者“提示”受信任站点区域只保留业务上确实需要运行ActiveX的极少数域名并关掉该区域内的“启动无需签名控件”和“启用不安全项目”等开关。注意受信任站点的域名列表要定期审计删掉那些已经没有任何业务用途的旧域名。Killbit方面不要只依赖系统补丁自带的Killbit要主动建立自己的“Killbit黑名单”。把资产盘点阶段发现的、无签名或证书过期的、厂商已经停止维护的、以及有公开高危漏洞记录的控件全部手动添加到Killbit注册表项里。这里有个经验在域环境下用组策略下发Killbit比逐台机器手动改注册表可靠得多也方便后续统一回滚。白名单手段则要配合软件的部署机制来做。对于业务需要使用的ActiveX控件优先考虑使用软件分发工具统一安装和升级不要允许浏览器从网页“即点即装”。如果要实现“仅允许指定站点加载指定控件”可以通过IE的“受信任站点”加“站点锁定”策略组合来实现但前提是配套的日志审计要跟上否则白名单形同虚设。4.4 替换路径与兼容方案说实话加固做得再细也只是在延长一项过时技术的生命周期。比加固更重要的是规划替换路径。根据项目的实际经验有三种比较现实的过渡方式。第一种是“服务端渲染替代”。很多页面用ActiveX控件其实只是为了打开本地软件、调用打印组件、或者做文件预览。现在这些场景都可以用纯Web方案替代比如服务端把文档转成PDF再下发预览或者使用无插件的打印协议与本地服务配合实现静默打印。这样就能绕开控件本身同时把业务功能完整保留下来。第二种是“IE模式过渡”。新版浏览器基本保留了对IE内核的兼容模式可以把老页面配置到企业兼容列表中让用户在新浏览器里以IE模式打开这些页面。要注意的是IE模式仍然遵循原有安全机制ActiveX控件的漏洞风险并没有消失所以这只适合“功能迁移尚未完成、但必须先控制风险”的过渡期。第三种是“虚拟化隔离”。把老页面整体放进远程桌面服务或者虚拟专用浏览器里用户通过远程方式访问终端本机完全禁止加载Applet和ActiveX。这种方案对终端侧的安全增益最明显但需要一定的基础设施成本和体验上的让步适合作为“尚未完成替换前的兜底”。5. 排查实战当怀疑被绕过时怎么定位最后这部分我想分享一些在实战排查中验证过的思路主要解决一个问题如果你已经怀疑客户端控制被突破应该从哪里下手找证据。5.1 从静态痕迹开始静态痕迹是排查的第一站。浏览器侧要看访问历史、下载记录和网页缓存重点搜那些加载组件/控件标签的页面记录。Java侧不要漏掉部署缓存目录前缀“javacpl”相关配置项以及浏览器插件目录里残留的jar包文件。ActiveX侧则要翻注册表里的已加载项查可疑组件的生成时间和来源URL对应关系。这里有个很隐蔽但值得注意的点攻击者往往会把恶意组件伪装成正常业务组件的名称。比如注册表里出现一个与厂家命名规则高度相似的组件名不一定就是入侵痕迹但如果它的类标识出现在页面加载记录里同时没有对应签名信息就要提高警惕。5.2 动态行为监控更可靠静态痕迹容易被人为清理动态行为监控的可信度更高。推荐在关键业务终端上部署三层监控进程层关注浏览器进程有没有派生出新的子进程尤其是命令行里带PowerShell、脚本、可执行文件路径的以及新启动进程的父进程是不是浏览器。网络层注意是否有异常外联连接。尤其要关注浏览器的子进程发出的外联因为正规业务页面极少会从内容进程里再发起与业务无关的加密隧道。文件层监控临时目录、下载目录、部署缓存目录、启动项注册表位置的写入行为。恶意组件几乎必然要在这些位置留下痕迹或者释放载荷。如果监测到以上三类行为同时发生基本可以认定存在一次活跃的控件相关攻击这时候应该立刻断开终端网络、保留内存镜像和日志再进行后续分析。5.3 那些年踩过的坑说到底这类排查工作最大的坑不是技术难度而是对旧业务的“感情分”太重。很多管理员明知道某个控件风险高但因为业务部门一句“我们一直这么用的”就迟迟不下杀伐决断。我见过不止一个小环境出问题之后复盘发现风险征兆早在一年前的日志里就出现过只是当时没人把“访问页面时弹出证书错误”当一回事。另一个常见误区是“只清终端不查根因”。发现终端被植入了恶意组件就赶紧重装系统却忘了溯源攻击入口用户当时访问了什么页面是浏览器漏洞还是控件漏洞是不是有内部页面被挂了马不查清楚源头下一台终端还会以同样的方式中招。还有一个细节验证签名状态这件事不能只看“有签名”还要看签名链的完整性和时间戳。攻击者用过期证书给恶意组件签名的情况并不少见如果终端签名校验策略不严格这种组件也会被正常加载。在排查时养成“右键查看属性、看数字签名页、查看签名详细信息”三步走的习惯能帮你识别掉一大半伪造签名的样本。最后再分享一个小经验我在实际排查过程中养成了一套固定操作顺序——先看浏览器缓存和部署目录再查进程树与网络外联最后才翻注册表和文件监控记录。这个顺序不是拍脑袋定的而是因为前两个动作最快、最容易形成初步判断后两个动作则用来确认和取证。如果你所在的单位还有大量遗留系统建议你尽早做一次资产盘点把“哪些页面还在加载组件、哪些终端还在跑老版本运行时”这张底账摸清楚。技术上的答案其实都在前面几章里真正拉开差距的是你有没有把加固动作落到实处。希望这篇内容能给正在跟旧系统搏斗的同行一些参考。