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)或该元素上的任何其他直接方法。

    这样做的目的是绕过潜在的浏览器限制,该限制会阻止直接检查访问链接的样式。

    例如,也许你可以在&lt;a&gt;标签中放置一个子元素,或者直接检查文本的样式;等等。直接或间接依赖$('1').anything 的任何方法都是可以接受的。与孩子或父母一起做一些聪明的事情可能是必要的。

    请注意,仅出于这一点的目的,这种情况是浏览器将对 javascript 欺骗 &lt;a&gt; 元素的所有属性(但不是其他属性),并且它只会在 @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(加上一个空格)放在&lt;a&gt; 标记内,并使用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。 这实际上链接到我的&lt;noscript&gt; 段中。 :-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%,但差异很大)。

(哦,对 &lt;body onload="..."&gt; 的废话表示歉意;我已经很久没有尝试在没有框架的情况下在 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:检测:链接上的访问样式*无需*直接检查或比我快的主要内容,如果未能解决你的问题,请参考以下文章

javascript能不能用变量改变css的值?

缩放 css/javascript

CSS - JavaScript 没有被实现

Thymeleaf 加载 CSS 但不加载 Javascript

使用 html、javascript、css 制作 IOS 应用程序

CSS CSS Media Targeted JavaScript