CSS / JavaScript / hacking:检测:链接上的访问样式*无需*直接检查或比我快
Posted
技术标签:
【中文标题】CSS / JavaScript / hacking:检测:链接上的访问样式*无需*直接检查或比我快【英文标题】:CSS/JavaScript/hacking: Detect :visited styling on a link *without* checking it directly OR do it faster than me 【发布时间】:2011-01-24 14:12:27 【问题描述】:这是用于http://cssfingerprint.com的研究目的
考虑以下代码:
<style>
div.csshistory a display: none; color: #00ff00;
div.csshistory a:visited display: inline; color: #ff0000;
</style>
<div id="batch" class="csshistory">
<a id="1" href="http://foo.com">anything you want here</a>
<a id="2" href="http://bar.com">anything you want here</a>
[etc * ~2000]
</div>
我的目标是检测 foo 是否已使用 :visited 样式呈现。
我想检测是否访问了 foo.com, 没有直接查看 $('1').getComputedStyle
(或在 Internet Explorer 中,currentStyle
)或该元素上的任何其他直接方法。
这样做的目的是绕过潜在的浏览器限制,该限制会阻止直接检查访问链接的样式。
例如,也许你可以在<a>
标签中放置一个子元素,或者直接检查文本的样式;等等。不直接或间接依赖$('1').anything
的任何方法都是可以接受的。与孩子或父母一起做一些聪明的事情可能是必要的。
请注意,仅出于这一点的目的,这种情况是浏览器将对 javascript 欺骗 <a>
元素的所有属性(但不是其他属性),并且它只会在 @987654339 中呈现 color:
@。因此,依赖于例如的方法文字大小或background-image
将不符合此要求。
我想提高当前抓取方法的速度。
大部分时间(至少使用 Firefox 中的 jQuery 方法)都花在document.body.appendChild(batch)
上,因此找到一种改进该调用的方法可能是最有效的。
请参阅http://cssfingerprint.com/about 和http://cssfingerprint.com/results 了解当前的速度测试结果。
我目前使用的方法可以在http://github.com/saizai/cssfingerprint/blob/master/public/javascripts/history_scrape.js看到
总结为 tl;dr,它们是:
-
在 :visited per above 上设置颜色或显示,并通过
getComputedStyle
直接检查每一项
将链接的ID(加上一个空格)放在<a>
标记内,并使用jQuery 的:visible 选择器,仅提取可见文本(= 访问的链接ID)
FWIW,我是 white hat,我正在咨询 EFF 和其他一些相当知名的安全研究人员。
如果您贡献了一种新方法或加速,您将在http://cssfingerprint.com/about(如果您想成为 :-P)中获得感谢,并且可能在未来发表的论文中。
ETA:赏金将仅针对以下建议提供奖励
可以在 Firefox 上避免上述第 1 点中描述的假设限制,或者 在我有足够当前数据的任何浏览器上,执行速度至少比http://cssfingerprint.com/about 图表中列出的最佳执行方法快 10%如果有多个建议符合任一标准,则最适合的建议胜出。
ETA 2:我添加了两种以前最佳测试方法的基于宽度的变体(reuse_noinsert,在 Firefox/Mozilla 上最好,和 mass_insert,它的非常接近的竞争对手)。请使用不同的浏览器多次访问http://cssfingerprint.com;我会自动得到速度测试结果,所以我们会发现它是否比以前的方法好,如果好,提高多少。谢谢!
ETA 3:当前测试表明,在 Chrome 中使用 offsetWidth
(而不是 getCalculatedStyle
/currentStyle
)可以节省约 2 毫秒 (1.8%) 的速度,而在 Firefox 中使用约 24 毫秒 (4.3%) 的速度,这不是我想要的 10% 来获得丰厚的赏金。知道如何维持剩下的 10% 吗?
【问题讨论】:
查看了该网站。这非常酷,有点吓人。哇。 @incrediman:谢谢。 “非常酷,有点吓人”是我最喜欢的一种hack。 :-) 你见过这个:ha.ckers.org/weird/CSS-history.cgi 吗?我刚刚找到它,它看起来很有趣,因为它不依赖于 javascript。 这实际上链接到我的<noscript>
段中。 :-P 不幸的是,它可能比我当前的实现慢几个数量级(其最大本地速度约为每分钟 340 万个 URL),因为它需要浏览器对每次点击进行独立调用。 OTOH,我还没有实际测试过(还没有?)...
@incrediman:我添加了一堆指向cssfingerprint.com/about 的链接,这样会更清楚。
【参考方案1】:
[新更新]
如果您只想要视觉呈现的结果,那么最快的方法是使用 CSS 计数器..
CSS:
body
counter-reset: visited_counter;
a:visited
counter-increment: visited_counter;
#results:before
content:counter(visited_counter);
这将在 id 为“results”的元素之前添加已访问链接的数量。
不幸的是,无法从 JavaScript 访问它,只能显示它..
[初步回答]
你知道jQuery直接支持:visited
选择器吧?
点赞$('a:visited')
[更新]
作为替代方案,您可以应用不依赖于 getComputedStyle
的 CSS 属性来检索..
喜欢a:visitedheight:1px;display:block;
,然后检查offsetHeight
。
【讨论】:
-1 因为我很确定它不会。 api.jquery.com/category/selectors 这不符合“不检查直接元素”这一点。你认为它会更快吗? jQuery 的 :visible 已经基于 offsetHeight。 @Gaby:在 Chrome 中工作,在 Fx 和 IE8 中不执行任何操作,并将两个链接的边框置于兼容模式。我并不感到惊讶:-) @Andy,我的系统中只有 IE 失败...FF、Chrome、Opera 和 Safari 都在 *** 链接周围添加了一个红色边框(前提是您从每个浏览器访问 ***.com 主页。 .) @Sai,是的.. 确实很奇怪。我还没有设法以任何方式访问它……不是 js,不是任何类型的调试器…… w3 规范提到了Generated content does not alter the document tree. In particular, it is not fed back to the document language processor (e.g., for reparsing).
【参考方案2】:
-
在锚点内添加一个子项(例如跨度)
使用
color : inherit
检测孩子的颜色 (JS)
警告:afaik 它不适用于 lte ie7
对于 lte ie7 ull 必须
在a:visited
上添加visibility : hidden
并在孩子上添加visibility : inherit
使用 javascript 检查孩子的可见性(隐藏 = 已访问)
【讨论】:
基于可见性的东西不适合我的第 1 点;那必须纯粹依靠颜色。我将测试颜色:继承。 那么您可以添加 ie7 js ie7-js.googlecode.com/svn/test/index.html - 这样将支持继承属性 好的,这是您可以尝试的 LTE ie7 // 使用方向 (css) 将其设置为 RTL(并为子级继承),然后将 DIR 属性 (LTR) 放在标签上以恢复它返回然后检查孩子的方向(在JS中)【参考方案3】:类似的想法,但回避.getComputedStyle()
:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<style type="text/css">
a:visited display: inline-block; font-family: monospace;
body font-family: sans-serif;
</style>
<script type="text/javascript">
function test()
var visited = document.getElementById("v").childNodes[1].firstChild.clientWidth;
var unvisited = document.getElementById("u").childNodes[1].firstChild.clientWidth;
var rows = document.getElementsByTagName("tr");
for (var i = 1, length = rows.length; i < length; i++)
var row = rows[i];
var link = row.childNodes[1].firstChild;
var width = link.clientWidth;
row.firstChild.appendChild(document.createTextNode(link.href));
row.childNodes[2].appendChild(document.createTextNode(width === visited ? "yes" : (width === unvisited ? "no" : "unknown")));
</script>
</head>
<body onload="test()">
<table>
<tr><th>url</th><th>link</th><th>visited?</th></tr>
<tr id="u"><td></td><td><a href="http://invalid_host..mplx/">l</a></td><td></td>
<tr id="v"><td></td><td><a href="css-snoop.html">l</a></td><td></td>
<tr><td></td><td><a href="http://***.com/">l</a></td><td></td>
<tr><td></td><td><a href="http://www.dell.com/">l</a></td><td></td>
</table>
</body>
</html>
当然,诀窍是确保已访问和未访问的链接具有不同的宽度(在这里,使用 sans-serf 与等宽字体)并将它们设置为 inline-block
以便可以通过 clientWidth
访问它们的宽度.经测试可在 FF3.6、IE7、Chrome 4 和 Opera 10 上运行。
在我的测试中,访问clientWidth
始终比任何依赖计算样式的方法都要快(有时高达 ~40%,但差异很大)。
(哦,对 <body onload="...">
的废话表示歉意;我已经很久没有尝试在没有框架的情况下在 IE 中进行事件了,我已经厌倦了与之抗争。)
【讨论】:
任何依赖于不同字体(或颜色以外的任何东西)的东西都不适用于我的第 1 点。对于#2,这基本上是我已经在使用名为“jquery”的方法所做的事情,它使用 jQuery 的 :visible 选择器,它基于宽度(未访问的链接是 display:none,所以宽度为零)。为什么你的方法会更快? 正如我所说,它非常相似;我只是想看看避免计算样式是否会提高速度。似乎是这样,但我不相信我得到的数字(误差幅度太大)。如果我能得到更紧密的样本分组,我会发布结果。 你为什么使用 clientWidth 而不是上面 Gaby 建议的 offsetWidth? 习惯。 8 之前的 IE 在处理相关元素时错误地计算了一些 offsetFoo 属性,所以当我主要使用 DOM 方法时,我倾向于使用 clientFoo 代替。并不是说这些问题会影响这个测试,因为没有相关的元素。不过,我没有看到 Gaby 的评论? 我将把“使用宽度”的想法交给 Gaby,因为 zie 先说了。请参阅 zir 回复的“[update]”部分。【参考方案4】:由于所有版本的 IE(是的,如果您启用了 quirks,即使是版本 8)都支持 CSS 表达式,所以 color 属性仍然不安全。您可能可以使用此(未经测试)加速 IE 测试:
a:visited color: expression( arrVisited.push(this.href) );
此外,您的问题并未真正涵盖这一点,但您当然可以非常轻松地在子节点中设置属性以启动检测,并且任何解决方案也必须防止这种情况发生:
a.google:visited span background-image: url(http://example.com/visited/google);
您也需要保护相邻的兄弟姐妹,而不仅仅是后代:
a.google:visited + span
同样未经测试,但您可能会使用content
属性来修改 DOM,然后使用一些 XPath 来查找新节点,从而大大提高速度。
a.google:visited:before content: "visited"; visibility: hidden;
XPath:
visited links = document.evaluate('//a[text()="visited"]')
【讨论】:
#1 谈论的是 Mozilla 的潜在补丁。我认为 IE 将永远是脆弱的。 ISTR 认为 CSS 表达式经常被重新评估,这让我担心使用它们会相当低的 CPU 效率。背景图像技巧是众所周知的,但可能会有点慢(每次点击一个连接,并行限制 2-8 个)。我根本找不到访问 :before 内容的方法;请尝试测试一下。 :before 在 lte ie7 上不支持 问题不是:before
/:after
被支持,而是他们的content:
没有插入到DOM中。请参阅有关 Gaby 回复的评论主题。以上是关于CSS / JavaScript / hacking:检测:链接上的访问样式*无需*直接检查或比我快的主要内容,如果未能解决你的问题,请参考以下文章
Thymeleaf 加载 CSS 但不加载 Javascript