摘要
开源软件包生态持续扩张背景下,攻击者不再局限于利用 npm 包在安装阶段执行恶意代码的传统供应链攻击模式,转而将 npm 注册表及其全球镜像站点作为恶意静态网页的托管载体。OX Security 威胁情报团队监测到的安全事件显示,共计 24 个恶意 npm 软件包被投放至公共注册表,包体内部仅携带单一 HTML 页面,页面实现伪造 Cloudflare 人机验证界面,结合混淆脚本完成远程动态跳转,具备分发 ClickFix 钓鱼攻击的能力。该类攻击区别于传统供应链威胁,软件包下载、安装行为本身不会直接对主机造成损害,风险触发条件为受害者在浏览器访问镜像站点下的恶意 HTML 资源。攻击者借助 unpkg、npmmirror 等被企业安全策略普遍信任的域名承载钓鱼页面,利用合法第三方键值存储服务实现跳转目标远程变更,以此绕过域名信誉检测、邮件网关过滤等传统防护手段。本文基于该真实威胁样本,完整还原攻击全链路,拆解基础设施滥用的技术实现逻辑,剖析该攻击能够突破现有安全管控体系的内在成因,评估该威胁对开发人员、企业内网带来的安全风险。反网络钓鱼技术专家芦笛指出,该类攻击的核心本质属于信任边界崩塌,攻击者将开源生态公共分发基础设施转化为钓鱼攻击的前端载体,模糊了正常开发资源与恶意钓鱼内容的识别边界。研究针对注册表运营方、镜像服务商、企业安全运维人员、终端使用者分别提出分层处置与防御方案,同时客观讨论现有防护体系存在的现实短板,为开源包生态的新型钓鱼威胁研判提供分析参考。
关键词:网络钓鱼;ClickFix;npm;镜像站点;供应链安全;信任边界
1 引言
JavaScript 开源生态当中,npm 作为全球规模最大的软件包公共注册表,支撑海量项目依赖管理,配套衍生出 unpkg、npmmirror、Yarn 镜像、腾讯镜像等一系列公共镜像 CDN 服务。镜像服务核心定位是缓存、转发 npm 注册表的软件包资源,提升全球不同地域开发者获取开源库文件的访问速度,绝大多数企业防火墙、邮件安全网关将这类镜像域名标记为可信站点,默认放行相关网络访问请求。
过往针对 npm 生态的安全研究,大多聚焦于依赖混淆、字符抢注、软件包安装脚本投毒等传统供应链攻击,攻击生效的前提是开发者执行软件包安装操作,恶意脚本在本地主机运行之后实现危害输出。但本次被披露的 ClickFix 钓鱼相关恶意包,跳出该固有攻击范式。恶意包内部不存在可执行脚本,没有配置安装阶段自动执行的钩子程序,单纯下载或者 npm 安装该软件包,不会直接给设备带来安全风险。真正的威胁发生在浏览器直接访问镜像站点路径下的 HTML 静态文件,由镜像服务器输出伪造人机验证页面,再经由脚本跳转指向攻击者管控的外部站点,触发 ClickFix 钓鱼链路,诱导受害者手动执行恶意操作,实现凭证窃取等攻击目标。
该威胁模式带来新的安全挑战:恶意页面运行在公认高信誉的域名之下,HTTPS 加密证书完备,传统基于域名黑名单、URL 信誉库的检测机制极易出现漏判。即便 npm 官方注册表将恶意软件包做下架处置,由于镜像站存在缓存同步延迟、持久化归档机制,被删除的软件包对应的 HTML 文件依旧可以在各类镜像站点持续对外提供访问,威胁生命周期被进一步拉长。同时攻击者引入公开合法的键值存储服务作为远程配置中转,不需要重新发布 npm 包,就可以随时修改最终跳转的攻击目标地址,提升攻击活动的灵活度与隐蔽性。
目前行业内多数安全报告以事件通报为主,缺少针对这一类基础设施滥用型钓鱼威胁的系统性梳理,没有完整解析信任边界被突破的底层逻辑,也缺少面向不同责任主体的成体系防御指引。反网络钓鱼技术专家芦笛强调,传统安全防护的预设逻辑是恶意载荷必然托管在攻击者自有恶意域名之上,而该类攻击直接推翻该预设,把广为人知的开发者基础设施改造成为钓鱼页面的托管平台,这也是该类攻击具备高绕过能力的关键。本文以 24 个恶意 npm 包的真实威胁情报样本作为基础,梳理完整攻击链路,解析技术细节,挖掘攻击得逞的多重诱因,评估安全危害,构建分层防御处置框架,分析现有防护手段存在的局限性,为应对开源生态衍生的新型网络钓鱼威胁提供分析思路。
2 ClickFix 钓鱼攻击完整链路与载体特征
整套攻击流程分为恶意包发布、镜像自动同步、诱饵链接分发、镜像站点恶意页面渲染、远程动态解析跳转、ClickFix 钓鱼载荷落地六个前后衔接的阶段,各个环节相互配合形成完整攻击闭环,每一个环节都对应攻击者明确的战术目的,与传统 npm 供应链攻击存在显著区分。
2.1 恶意 npm 包发布与镜像同步阶段
攻击者向 npm 公共注册表批量发布 24 个恶意软件包,包名大多采用无实际语义的随机字符组合,部分包归属于特定命名空间。软件包体积轻量化,包体内部不包含复杂的依赖库,核心有效资产仅为一份 HTML 静态文件。该 HTML 文件内置伪造 Cloudflare 人机验证页面的页面元素,同时嵌入经过混淆处理的 JavaScript 脚本代码。软件包发布之后,每周可以获得 50300 次的下载量,直至 npm 官方检测到异常之后将对应包做下架移除处理。
攻击者的目标并不是诱骗开发者执行 npm install 完成本地安装。发布软件包的核心目的是利用 npm 生态的自动镜像复制机制。unpkg、npmmirror、Yarn 镜像、腾讯镜像等公共镜像服务会自动同步注册表上新发布的软件包资源。部分镜像服务不只是对外提供压缩后的 tgz 归档包下载,还支持直接解析包内的单个静态文件,浏览器访问特定 URL 路径,服务器会直接读取包内 index.html,将完整网页渲染输出到访问者浏览器,镜像站点由此被动充当免费、高可信的钓鱼网页托管服务器。
这里需要明确一项关键风险点:当 npm 官方将恶意包从主注册表删除,并不代表所有镜像站点同步完成清理。镜像系统存在归档留存机制、更新时间差,部分镜像会长期保留历史版本资源。即便源头已经清除恶意包,指向镜像站点的访问链接依旧可以正常打开恶意钓鱼页面,威胁不会随着注册表下架操作立刻消失,会在各个镜像节点继续存续一段时间,增加威胁处置的复杂度。
2.2 诱饵链接分发与访问触发
完成镜像同步之后,攻击者会构造指向镜像域名下 HTML 文件的完整 URL 链接,例如 unpkg 域名下直接定位恶意包版本的 index.html 资源路径。该链接域名属于知名开源 CDN 服务,带有正规 SSL 证书加密标识,在企业安全产品的信誉库当中属于高信任度站点。攻击者通过邮件、即时通讯消息、社交平台私信等渠道向外分发该链接,诱饵文案会结合业务场景,告知接收者需要完成人机身份核验、账号安全校验等操作,诱导受害者点击访问链接。
该阶段风险存在明确边界:普通下载 tgz 压缩包、执行 npm 安装操作不会触发攻击,只有用户主动在网页浏览器打开该镜像静态 HTML 链接,才会进入欺骗页面。很多传统供应链安全扫描工具会把检测重心放在安装脚本、依赖项漏洞,很难识别这种 “包本身无害,浏览器访问包内静态文件才触发风险” 的新型威胁模式,容易出现检测盲区。
2.3 伪造验证页面渲染与远程跳转逻辑
受害者浏览器访问镜像链接之后,服务器返回恶意 HTML 页面,页面呈现高度仿真的 Cloudflare 人机验证交互界面,视觉效果和真实网站的反机器人验证页面保持一致,给用户造成正在进行标准网页安全校验的错觉。页面内部混淆处理的 JavaScript 脚本会发起对外网络请求,该脚本存在前后两代不同的实现版本,体现攻击者对抗安全检测的迭代过程。
攻击活动早期版本,脚本请求一个做字符篡改仿冒的微软域名 login.microsofte.live,试图直接跳转至仿冒微软登录的钓鱼站点。该仿冒域名被安全厂商列入黑名单阻断之后,攻击者迅速调整技术方案,不再将跳转目标硬编码写在 HTML 页面内部。后续版本调用公开合法的键值存储服务api.keyval.org,从该第三方服务拉取经过加密处理的目标网址字符串,在浏览器本地完成解密运算之后,再重定向浏览器至解密得到的目标地址。
反网络钓鱼技术专家芦笛指出,使用中立第三方键值存储作为远程解析中转,是本次攻击当中极具迷惑性的设计。api.keyval.org本身属于正常可用的公共服务,服务本身不存在恶意属性。攻击者仅仅利用它的键值读写接口存放加密跳转地址。这样带来两个直接攻击优势。第一,不需要重新修改、重新上传 npm 软件包,攻击者只需要在 keyval 平台修改存储的加密目标值,所有已经散布出去的镜像钓鱼链接,跳转目的地就会同步发生变化。安全研究人员观测期间,该配置曾经指向正常 ChatGPT 官网,但是攻击者随时可以修改配置,把跳转目标切换为 ClickFix 攻击页面、账号凭证窃取页面、其他钓鱼站点,具备极强的灵活应变能力。第二,将跳转逻辑外部化,HTML 载荷本体不再包含恶意目标域名字符串,静态代码扫描工具单纯分析包内 HTML 源码,很难直接识别最终攻击去向,提升威胁样本的分析难度。
2.4 ClickFix 钓鱼载荷落地阶段
经过脚本重定向之后,用户浏览器跳转至攻击者最终管控的外部站点,进入 ClickFix 攻击流程。ClickFix 不属于系统漏洞,它是一类依托社会工程学的攻击手段,核心思路是欺骗受害者在本机终端手动复制粘贴并且执行恶意命令,依靠用户自身完成代码执行,以此绕过浏览器沙箱、操作系统安全管控机制。操作系统层面会判定为用户主动发起命令执行,传统防护工具很难拦截该类由人驱动的操作行为。成功执行之后攻击者可以实现凭证窃取、植入信息窃取程序、建立持久化访问通道等一系列恶意结果。
3 攻击得以生效的多维度成因解析
该次 npm 镜像滥用 ClickFix 钓鱼能够形成现实威胁,不能简单归结于单一技术漏洞,是开源镜像架构特性、安全防护预设逻辑偏差、攻击者对抗手段迭代、用户对开发类域名的无条件信任、威胁检测机制固有短板多重因素叠加共同造成。
3.1 npm 镜像服务架构带来的托管能力溢出
npm 镜像 CDN 设计初衷是为 JavaScript 项目提供库文件分发,供网页项目加载 js、css、图片等前端静态资源。架构上支持直接访问软件包内部任意静态文件,该功能对于正常前端开发场景具备实用价值。但该能力同时可以被攻击者挪用,用来托管 HTML 网页文件,镜像站点转变为免费、高可用的网页托管基础设施。
镜像域名长期在企业安全体系内处于白名单地位。企业防火墙、网页代理、邮件安全网关为保障研发人员正常开展开发工作,会对 unpkg、npmmirror 这类域名放行访问,不会做严格的深度内容检测。攻击者正是利用这一点,将钓鱼页面部署在已经被信任的域名之下,恶意载荷藏身于合法域名的 URL 路径之后,域名本身信誉良好,传统 URL 信誉检测只会评估域名主体,很难识别同一个域名下部分路径承载恶意内容的场景,检测规则很容易被绕过。
同时镜像的多节点缓存归档特性拉长威胁生存周期。npm 官方注册表完成恶意包下架,全球大量镜像节点完成同步清理存在时间差,部分镜像策略会永久保存历史版本资源。源头删除之后,外部已经传播的诱饵链接依旧可以正常访问恶意页面,提升威胁处置的难度。
3.2 攻击者的对抗迭代:外部化远程配置规避静态检测
早期攻击版本将钓鱼目标域名直接写在 HTML 脚本内部,安全人员通过静态解析页面代码,就能够提取恶意目标域名,完成拉黑处置。攻击者在域名被封禁之后快速迭代方案,引入中立第三方键值存储服务作为外部配置仓库,跳转目标地址以加密形式存放在第三方平台,npm 包内的 HTML 仅保留拉取、解密逻辑。
这种改造让恶意包内的静态样本不再包含攻击目标信息。安全人员下载分析软件包,解析 HTML 和混淆 JS,无法直接获知后续会跳转去往什么站点。攻击目标在外部第三方服务动态变更,静态扫描手段失效,威胁情报的提取难度显著提升。反网络钓鱼技术专家芦笛指出,把攻击配置剥离到样本之外,已经成为现代钓鱼活动重要的对抗手法,安全检测不能只局限于分析本地载荷文件,还需要关注载荷发起的外部网络调用链路。
3.3 安全防护体系原有假设存在认知偏差
传统针对 npm 生态的安全检测,重点扫描软件包安装生命周期的行为,检测 preinstall、postinstall 等钩子脚本,检查依赖项漏洞,研判软件包在安装阶段会不会执行恶意操作。这套防护逻辑建立在一个固有假设:npm 生态的恶意危害,必然来源于软件包安装执行过程。
而本次攻击当中,软件包本身在安装阶段完全没有异常行为,恶意能力只在浏览器访问镜像站点静态 HTML 文件的时候才被触发。这种攻击路径不在传统供应链安全扫描的覆盖范围之内,大量现有工具不会对软件包内部的 HTML 静态文件做网页钓鱼内容检测,形成明显的检测盲区。
另外传统网页钓鱼防护的预设,认为钓鱼页面必然部署在全新、低信誉的攻击者自有域名。当钓鱼页面运行在行业公认可信的 CDN 域名之上,基于域名信誉、黑名单的防护体系效果被大幅削弱。邮件安全产品识别邮件内链接风险时,域名信誉权重很高,诱饵链接使用 unpkg 等域名,邮件网关就会降低风险告警等级,诱饵邮件更容易抵达收件人。
3.4 社会工程与用户认知偏差放大受害风险
对于开发人员、企业员工群体,看到 unpkg、npmmirror 这类熟悉的域名,主观上会降低心理戒备,默认来自该域名的链接属于正常开发资源。攻击者依托这种心理认知,搭配伪造 Cloudflare 验证页面,利用大众对人机校验网页的普遍熟悉感完成欺骗。普通互联网用户日常访问各类网站时经常遇到 Cloudflare 人机验证,看到外观一致的页面,很少会怀疑页面背后属于钓鱼欺骗。
ClickFix 攻击本身不依靠漏洞利用,全部依靠社会工程操纵用户行为。即便网络层面阻断外部恶意域名,只要受害者已经打开镜像站点的伪造页面,页面文案诱导用户复制命令粘贴至终端,防护工具很难阻止人手动执行操作。技术防御可以拦截很多自动化威胁,但面对人为参与的社会工程欺骗,防护效果会受到限制。
4 分层识别与防御处置体系构建
针对 npm 镜像被滥用托管 ClickFix 钓鱼页面这类新型威胁,不存在单一技术手段实现彻底阻断,需要注册表运营方、镜像服务商、企业安全运维、终端使用者多方协同,从源头管控、流量检测、日志审计、用户行为规范、事件应急处置多个维度建立多层防护闭环。
4.1 注册表与镜像服务商侧源头管控优化
npm 注册表运营方需要完善恶意包检测规则,除传统恶意安装脚本检测之外,增加针对包内包含独立 HTML 网页文件这类异常样本的识别能力。大量无业务意义、仅携带单一 HTML 文件的无名包应当触发风险告警,优先人工复核,及时完成下架处置。同时需要完善下架包的同步通知机制,当注册表移除恶意包,向各个合作镜像节点推送风险通知,推动镜像节点加速对应版本资源的清理。
各个公共镜像 CDN 服务商需要重新评估直接浏览器访问包内 HTML 文件这一功能的安全风险。可以区分访问场景:对于程序脚本加载 js、css 资源的场景保持原有能力;对于浏览器直接访问渲染 HTML 完整网页的访问行为增加限制或者强告警。镜像站点应当记录访问包内静态网页资源的访问日志,当收到恶意包通报,可以快速定位访问来源。同时镜像平台自身安全能力当中,需要引入网页钓鱼内容检测,对向外输出的 HTML 内容做风险识别,发现伪造登录、伪造验证类页面进行拦截。
4.2 企业机构层面安全防护策略调整
企业安全运维人员需要重新审视对于 npm 镜像域名的安全策略,不可以对 unpkg、npmmirror 等镜像域名做无条件全盘信任。反网络钓鱼技术专家芦笛强调,可信域名不等于域名下面的全部路径全部可信,同一域名之下既存在合法开发资源,也可能被注入钓鱼页面,不能简单依靠域名白名单完成防护。
第一,在 URL 信誉流水线当中,将 npm 镜像域名纳入钓鱼检测流程,专门针对镜像域名下直接请求.html 后缀文件的访问路径增加风险检测规则。代理服务器、DNS 服务器做好日志留存,重点审计内网主机对外发起的指向镜像域名、请求包内 HTML 文件的访问记录。这类访问行为对于绝大多数业务研发场景属于异常行为,真实业务大多加载 js、css 资源,很少会浏览器直接打开包内 HTML 页面,出现该类访问记录需要触发安全告警,开展事件排查。
第二,邮件安全网关、终端浏览器防护工具,不能仅仅依靠域名信誉判断链接风险。即便域名属于知名 CDN,链接指向包内 HTML 网页路径,同样应当提升风险等级,向用户展示风险提示。企业内部安全科普需要补充这类新型威胁案例,告知研发人员,来自 npm 镜像域名的链接并不全部安全,收到外部消息发来的镜像 HTML 链接,不可以随意点击访问。
第三,强化终端层面针对 ClickFix 攻击的防护与告警,做好员工安全培训,明确提醒不要复制网页上面的代码粘贴至终端命令行。完善终端日志审计,监控异常剪贴板行为、陌生命令执行行为,尽可能在攻击落地之后及时发现入侵迹象。
4.3 终端使用者识别准则与安全行为规范
普通开发人员以及企业员工,面对来自邮件、聊天消息转发而来的 unpkg、npmmirror 等镜像域名链接,应当建立基础风险判别习惯。区分正常业务场景与可疑场景:项目代码当中引入镜像上的 js 库属于常规开发行为;但聊天消息、陌生邮件直接发来一条指向镜像内部 HTML 文件的完整浏览器链接,则具备很高的钓鱼嫌疑,应当拒绝直接点击打开。
即便访问镜像域名,同样需要完整观察 URL 全路径,判断访问资源类型。需要建立认知:HTTPS 加密、知名 CDN 域名,并不代表网页内容安全可信。遇到页面弹出人机验证之后,又要求复制命令粘贴终端的场景,直接判定为高风险 ClickFix 钓鱼行为,立刻关闭页面,不要执行页面提示的任何复制粘贴操作。
开发者下载 npm 软件包开展本地项目开发,保持现有软件包安全审查习惯,但也要建立新认知:软件包本地安装没有异常不等于该包完全没有安全隐患,部分威胁只在特定浏览器访问镜像资源场景才会触发,不能因为本地安装没有异常就判定样本完全安全。
4.4 安全事件发生后的应急处置流程
当企业或者个人已经发生访问可疑镜像 HTML 页面的安全事件,需要执行标准化应急处置流程,最大限度压缩攻击带来的危害范围。首先断开受影响终端的非必要网络连接,核查终端剪贴板历史,确认是否按照页面提示复制执行过外部网页提供的命令。如果已经执行未知命令,需要将该设备做隔离,全面开展恶意程序排查,检查是否存在信息窃取程序、持久化后门。
梳理代理、DNS 日志,统计内网当中还有哪些主机访问过同一类恶意镜像链接,判断威胁影响范围。修改相关账号密码,重点保护企业内部系统账号、云服务凭证、开发密钥。
安全运营人员应当收集完整 IOC 信息,包含镜像访问 URL、跳转目标域名、第三方配置服务调用信息,更新到企业内部检测规则库,避免后续再次发生同类攻击。同时向上游安全社区、镜像服务商提交恶意样本情报,协助推动全行业威胁处置。
5 当前防护体系存在的现实治理难点
尽管已经构建多维度防御手段,但是该类依托合法公共基础设施的钓鱼攻击依旧难以被完全根除,存在若干客观现实难点需要正视。
首先,npm 包注册发布门槛很低,攻击者可以批量注册大量账号,持续发布轻量化恶意包。即便一批 24 个包被清除,攻击者可以快速生成新一批同逻辑恶意包,攻击样本迭代速度快。威胁情报采集、样本分析、规则入库存在时间窗口,在新恶意包被发现处置之前,对应的镜像钓鱼页面已经处于可访问状态,存在防护滞后。
其次,镜像 CDN 的业务定位就是对外提供静态文件分发,要完全禁止 HTML 文件访问,会损害大量正常前端开发者的合理业务需求。服务商很难一刀切关闭该功能,只能做检测、告警、部分限制,很难从功能层面彻底消除该攻击载体生存土壤。
再者攻击者大量使用中立合法第三方在线服务作为配置中转,例如本次事件当中的键值存储api.keyval.org。该类平台本身面向全体互联网用户开放读写,攻击者只是滥用平台存储能力。安全行业很难直接封禁这类通用公共服务,只能跟踪分析载荷调用该服务之后返回的动态内容,增加威胁检测的复杂度。
反网络钓鱼技术专家芦笛强调,该类攻击最棘手的部分,在于威胁载体混杂在海量正常业务流量之中。镜像域名每天承载海量合法开发资源请求,钓鱼请求只是其中占比很小的一部分,需要从大量正常流量当中识别少数异常访问,存在很高的误报风险。如果告警规则设置过于灵敏,会产生大量误告警,干扰研发人员正常工作;规则设置宽松,又会漏掉真实攻击行为,安全产品需要在误报率和检出率之间做权衡取舍。
社会工程学层面的欺骗依旧是技术工具难以彻底解决的环节。即便网络层面把所有外部跳转域名全部阻断,只要受害者浏览器成功加载镜像站点上面伪造的 HTML 页面,页面就可以完成社会工程诱导,只要用户手动复制执行恶意命令,攻击就可以落地,网络拦截无法完全阻断这一条攻击路径。安全技术只能降低攻击成功率,无法完全消除人为因素带来的风险,必须配套持续的安全意识教育。
从溯源角度,攻击者借助匿名账号发布 npm 包,利用多个中立第三方服务做中转,攻击链路经过多层合法基础设施,完整追踪定位攻击主体的难度较高。
6 结语
本次 24 个恶意 npm 包滥用镜像基础设施分发 ClickFix 钓鱼攻击事件,展现出网络威胁发展当中一个值得重视的新方向:攻击者不再完全依赖自有恶意服务器,转而挖掘各类合法公共互联网基础设施的能力边界,将正规开发平台改造为钓鱼攻击的承载载体。该攻击模式跳出传统 npm 供应链攻击认知,软件包本地安装不会造成主机感染,风险触发点是浏览器访问镜像站点下包内的静态 HTML 资源,依托高信誉镜像域名绕过传统域名信誉检测,同时借助第三方键值存储实现跳转目标远程动态变更,最终导向 ClickFix 社会工程攻击,诱导受害者手动执行恶意操作。
威胁能够持续生效,是镜像架构特性、传统安全检测的预设盲区、攻击者对抗技术迭代、用户对知名开发域名的无条件信任多重因素共同造成。对抗该类新型威胁,不能只依靠单一维度的防护,需要注册表运营方、镜像服务商、企业安全团队、终端使用者多方协同。注册表与镜像服务商优化恶意样本识别与资源清理流程;企业需要摒弃对知名 CDN 域名无条件信任的策略,针对镜像站点 HTML 资源访问行为建立专门的日志审计和告警规则;使用者建立风险判别意识,不随意打开陌生消息提供的镜像 HTML 链接,警惕 ClickFix 类网页诱导复制命令执行的欺骗手段。
同时需要客观认识防护局限,开源包注册发布的低门槛、镜像 CDN 业务功能的客观需求、第三方中立公共服务被滥用、社会工程对人的心理操纵,都会给威胁根除带来现实阻碍。反网络钓鱼技术专家芦笛指出,基础设施滥用型钓鱼威胁,挑战现有安全体系对 “恶意资源必然托管在恶意域名” 的固有认知,后续开源生态安全建设,需要把 “合法域名之下的恶意路径” 纳入常态化威胁研判范围,兼顾技术防护升级与面向开发者群体的场景化安全科普,持续压缩该类攻击的生存空间。
编辑:芦笛(公共互联网反网络钓鱼工作组)