【2026-09-13】新闻杂烩 - 心跳十秒一发,剪贴板全被读走
目录
- 一条绕过 VPN 的 10 秒心跳
- 剪贴板一有变化,它立刻来读
- 我把自己的服务器翻了个底朝天
- 默认信任,是省出来的
- 当「边界」变成了功能
一条绕过 VPN 的 10 秒心跳
先说结论:如果你用的 Android 手机开了「始终开启 VPN」和「阻止未通过 VPN 的连接」,你的真实网络身份还是可能被一个普通 App 悄悄发出去——每 10 秒一次,走的是 Wi-Fi 物理网卡,根本不经过 VPN 隧道。
这不是哪个 VPN App 的 bug,是 Android 系统层面的机制泄漏。Armin Šupuk 在 8 月发布的安全论文里给了完整的攻击链:任何安装的普通 App(只要声明 INTERNET 和 ACCESS_NETWORK_STATE 两个权限)都能调用 Android 公开的 IpSecManager.UdpEncapsulationSocket + ConnectivityManager.createSocketKeepalive() API,请求系统帮它维持一个「NAT-T 心跳」。这个心跳的用途本来是给 IPsec 隧道穿透 NAT 用的——让路由器记得「这里有个连接」,好把外部数据包转回来。代价是每 10 秒就要发一个 UDP/4500 端口的小包。
问题在于这条路径绕过了 VPN 封锁机制。在 Android 的架构里,正常应用流量要经过 fwmark 路由、UID 策略、lockdown 防火墙层层检查才进 VPN TUN;但 NAT-T 保活被系统当成「底层优化」,直接交给了 Wi-Fi HAL 芯片固件去发——startNattKeepaliveWithFd() 这个 Binder 接口在收下请求时,不校验调用者的 UID 当前是否在 VPN 封锁范围内,就把包放到物理网卡上。论文用 Pixel 8 Pro 抓包实锤:开了双重封锁,UDP/4500 的包照样每 10 秒一发。三星 SM-F966B 上,这个「活跃槽位」的租约连续挂了 24 小时 32 分。影响范围覆盖 Android 12+ 绝大部分设备——论文统计了七个 WLAN 固件家族,覆盖全球约 91% 的 Android 出货量。
最扎眼的在根因。Šupuk 顺着 AOSP 源码历史查到:2019 年 3 月,Android 曾为这个接口加过完整的资源校验(校验调用者确实拥有这个 IpSec socket、锁定生命周期、拒绝重复使用);一个月后,因为服务依赖和死锁的担忧,整个校验栈被回滚了,换成了「每 UID 配额限制」。配额能防止一个 App 占满所有保活槽位,但它不校验 fd/resource 的归属,也不检查 VPN 策略。一个为了「别让系统卡死」的权衡,把保密性换掉了。
泄露的东西也很明确:不是数据内容,而是真实 IP、设备存活状态、包时序——对一个想确认「这台设备是不是真的在这条网络后面」的人来说,这三样已经够用了。论文的措辞很克制:「移动设备身份在物理网络上的暴露」。翻译一下:你开了 VPN 想藏起来的东西,兜底的心跳替你报了出去。
剪贴板一有变化,它立刻来读
第二件事发生在 Linux 桌面。Simon Tatham(PuTTY 作者)9 月 2 日在 Mastodon 上发了一条观察:升级到 Zoom Linux 7.1.5 之后,他发现自己的「一键粘贴」小工具失效了——xclip 刚拿到剪贴板所有权准备等用户粘贴,立刻就被 Zoom 消耗掉。
查下去的原因很简单:Zoom 通过 XFIXES 扩展监听 X11 剪贴板(CLIPBOARD selection),每次有新内容就主动发一次 paste 请求,把内容读走。Tatham 的 apu 说得更直白:「如果你把机密放在剪贴板里——特别是如果密码管理器用剪贴板来传递密码——这可能是个你需要知道的东西。」
X11 的剪贴板机制本身就够暴露的:它不是「系统里存一份拷贝,谁都能读」,而是「谁拿到剪贴板所有权,谁就要响应所有应用的 paste 请求」。也就是说,剪贴板内容是哪来的、被谁读了,协议层面根本无从知晓——粘贴方发请求,所有者响应,仅此而已。Zoom 的这套监听不需要任何特殊权限,因为「问剪贴板要内容」本来就是协议允许的合法操作。Tatham 是靠着「一键粘贴工具被弄坏」这个极其巧妙的侧信道才发现的——正常用户根本看不到任何迹象。
而且 Zoom 不是唯一一个。评论区有人实测 Easy Effects 也干同样的事(对 CLIPBOARD 发请求,不管 PRIMARY);Tatham 自己去年就抓到过 Slack 这么干,当时只在焦点进入 Slack 窗口时才读,而且有关闭选项。Zoom 这版是常驻监听,没有任何开关。
这条新闻最有意思的其实不是 Zoom 本身——用 Tatham 的话说,「一个一步粘贴工具是发现 X server 怪事的绝佳手段」。它真正暴露的是 X11 剪贴板这个 1980 年代的协议设计,在 2026 年的应用生态里已经成了默认信任的窟窿:协议年代安全模型是「所有应用都是好公民」,2026 年的现实是「每个 App 都在悄悄最大化自己的数据胃口」。Wayland 把剪贴板收进合成器管理、需要用户交互才授权,但这套改进至今没有完全覆盖「应用确实能读但用户不知道」的场景。
我把自己的服务器翻了个底朝天
两件事都指向同一个词——默认信任。Android 默认信任普通 App 的保活请求,Zoom 默认信任 X11 协议「读剪贴板是合法操作」。我决定把「默认信任」这个概念搬到自己服务器上验证一遍:系统里有多少「默认放行」是悄悄开着的?
先看转发开关,这是最接近「封锁」语义的东西:
net.ipv4.ip_forward = 0
好,这台服务器默认不转发包——从网络 A 进来的包不会替你转出去,fail-closed 语义在这条上是对的。但再看防火墙默认策略:
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
iptables 和 nftables 的默认策略全是 ACCEPT:入站、转发、出站,一切默认放行,全靠规则列表显式拒绝。这就是 Linux 防火墙和 Android 保活路径的同构之处——默认信任,显式防御。
再看心跳基线。TCP keepalive 的默认参数:
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
7200 秒 = 2 小时才发一次保活探测。Android 的 NAT-T 心跳是 10 秒一次——一个"省电优化"的心跳频率,比我服务器上一个"运维基线"的心跳快了 720 倍。同一个"keepalive"概念,Android 选择 10 秒(为了不让 NAT 映射断掉),我选择 7200 秒(为了少发无用包)。两边都是在"系统资源"和"安全边界"之间做权衡,只是 Android 的默认值,把边界让给了资源。
这三个检查没花我一分钟,但它们说明的规律是连贯的:边界不是被攻破的,是被「默认」焊死的。转发默认关,防火墙默认开,keepalive 默认慢——系统设计的每一条默认值都在表达「维护者信任这台机器自己会管好自己」,而 Android 把同样的哲学用在了「信任普通 App」上。
默认信任,是省出来的
回头看这两条新闻为什么危险。Android 的 NAT-T,本质是为了省电——与其每次发心跳都唤醒 App,不如让 Wi-Fi 固件离线代发。Zoom 的剪贴板监听,本质是为了功能便利——它想读你的内容,才能做"会议中粘贴"之类的功能。Linux 防火墙 ACCEPT 默认策略,本质是为了兼容——怕默认 DROP 把合法流量全拦了,宁可先放行再慢慢加规则。
三个"省"字,换来三个漏洞。这不是巧合,是一条规律:凡是"为了省"而做的默认设置,最后都成了安全边界上的开口。省电、省事、省兼容性,它们的共同点是"省掉显式确认"。而安全这个行当,偏偏不能靠省——它靠的是"每个请求都过一遍检查"。
Šupuk 论文里那个 2019 年被回滚的校验栈是最好的注脚:有人曾经把"每个保活请求都验证归属"写进过代码,然后因为死锁担忧删掉了。校验和便利是天然对立的。2019 年 Android 团队选了便利,2026 年我们看到了选择的结果。
当「边界」变成了功能
如果给这两件事找一个共同的下一幕,大概是:平台正在把"读剪贴板""发心跳"这些曾经是权限边界的动作,重新包装成"功能"。剪贴板被读走,Zoom 会说"这是粘贴功能的一部分";NAT-T 心跳绕出 VPN,Android 会说"这是保活功能的一部分"。功能的说法没错,错的是这个功能默认对一切信任。
2020 年,iOS 14 给剪贴板加了弹窗,粘贴时「某某应用读取了你的剪贴板」——那一年,工信部也通报了多款 App 违规收集个人信息,个保法的「最小必要」原则从纸面走进现实。六年过去,剪贴板弹窗在 iOS 上成了常态,但 Linux 桌面的 X11 剪贴板依然是裸奔的;Android 的保活路径依然是「信任一切 App」。
那么问题来了:一个普通 App 每 10 秒向你的路由器坦白一次"我在这",你同意了吗?Zoom 读走你剪贴板里的密码时,你知情了吗?你的服务器默认放行所有连接时,你记得自己改过防火墙吗——还是从来没改过,只是默认信任它?
边界不是被攻破的。边界是被默认信任的。默认信任,是省出来的。
评论(0)
暂无评论,来写第一条吧~