CSS/JavaScript/hacking:检测:链接上的访问样式*无需*直接检查或比我更快

发布于 2024-08-24 07:24:27 字数 3131 浏览 7 评论 0原文

这是出于研究目的 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 样式进行渲染。

  1. 我想检测 foo.com 是否被访问,无需直接查看 $('1').getCompulatedStyle (或在 Internet Explorer 中,currentStyle< /code>),或该元素上的任何其他直接方法。

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

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

    请注意,仅就这一点而言,情况是浏览器将在 元素的所有属性(但不是其他属性)方面向 JavaScript 撒谎,并且它会仅在 :visited 中渲染 color:。因此,依赖于文本大小或背景图像等的方法将无法满足此要求。

  2. 我想提高当前抓取方法的速度。

    大部分时间(至少对于 Firefox 中的 jQuery 方法)都花在 document.body.appendChild(batch) 上,因此找到一种改进该调用的方法可能是最有效的。

    请参阅 http://cssfingerprint.com/abouthttp://cssfingerprint.com/results 查看当前速度测试结果。

我当前使用的方法可以在 http:// github.com/saizai/cssfingerprint/blob/master/public/javascripts/history_scrape.js

总结一下 tl;dr,它们是:

  1. 在上面的 :visited 上设置颜色或显示,并直接使用 w/ 检查每一个getCompulatedStyle
  2. 将链接的 ID(加一个空格)放入 标记内,并使用 jQuery 的 :visible 选择器,仅提取可见文本(= 访问过的文本)链接 ID)

FWIW,我是一个白帽,我正在协商这样做与 EFF 和其他一些相当知名的安全研究人员合作。

如果您贡献了新方法或加速,您将在 http://cssfingerprint.com/about 处获得感谢(如果你想成为:-P),并且可能在未来发表的论文中。

的建议才会获得赏金

  • ETA:只有在 Firefox 上能够避免上述第 1 点中描述的假设限制,或者
  • 在我拥有足够当前数据的任何浏览器上比我的最佳执行方法执行速度至少快 10% 图表中列出 http://cssfingerprint.com/about

如果多个建议符合任一条件,表现最好的人获胜。

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% 吗?

This is for research purposes on http://cssfingerprint.com

Consider the following code:

<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>

My goal is to detect whether foo has been rendered using the :visited styling.

  1. I want to detect whether foo.com is visited without directly looking at $('1').getComputedStyle (or in Internet Explorer, currentStyle), or any other direct method on that element.

    The purpose of this is to get around a potential browser restriction that would prevent direct inspection of the style of visited links.

    For instance, maybe you can put a sub-element in the <a> tag, or check the styling of the text directly; etc. Any method that does not directly or indierctly rely on $('1').anything is acceptable. Doing something clever with the child or parent is probably necessary.

    Note that for the purposes of this point only, the scenario is that the browser will lie to JavaScript about all properties of the <a> element (but not others), and that it will only render color: in :visited. Therefore, methods that rely on e.g. text size or background-image will not meet this requirement.

  2. I want to improve the speed of my current scraping methods.

    The majority of time (at least with the jQuery method in Firefox) is spent on document.body.appendChild(batch), so finding a way to improve that call would probably most effective.

    See http://cssfingerprint.com/about and http://cssfingerprint.com/results for current speed test results.

The methods I am currently using can be seen at http://github.com/saizai/cssfingerprint/blob/master/public/javascripts/history_scrape.js

To summarize for tl;dr, they are:

  1. set color or display on :visited per above, and check each one directly w/ getComputedStyle
  2. put the ID of the link (plus a space) inside the <a> tag, and using jQuery's :visible selector, extract only the visible text (= the visited link IDs)

FWIW, I'm a white hat, and I'm doing this in consultation with the EFF and some other fairly well known security researchers.

If you contribute a new method or speedup, you'll get thanked at http://cssfingerprint.com/about (if you want to be :-P), and potentially in a future published paper.

ETA: The bounty will be rewarded only for suggestions that

  • can, on Firefox, avoid the hypothetical restriction described in point 1 above, or
  • perform at least 10% faster, on any browser for which I have sufficient current data, than my best performing methods listed in the graph at http://cssfingerprint.com/about

In case more than one suggestion fits either criterion, the one that does best wins.

ETA 2: I've added width-based variants of two previous-best test methods (reuse_noinsert, best on Firefox/Mozilla, and mass_insert, its very close competitor). Please visit http://cssfingerprint.com several times from different browsers; I'll automatically get the speed test results, so we'll find out if it's better than the previous methods, and if so by how much. Thanks!

ETA 3: Current tests indicate a speed savings using offsetWidth (rather than getCalculatedStyle/currentStyle) of ~2ms (1.8%) in Chrome and ~24ms (4.3%) in Firefox, which isn't the 10% I wanted for a solid bounty win. Got an idea how to eke out the rest of that 10%?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

情魔剑神 2024-08-31 07:24:27

[新更新]

如果您只想将结果用于视觉呈现,那么最快的方法是使用 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')

[update]

作为替代方案,您可以应用不依赖于 < code>getCompulatedStyle 来检索。

a:visited{height:1px;display:block;},然后检查 offsetHeight

[new update]

If you wanted the results just for visual presentation then the fastest method would be to use CSS counter..

CSS:

body{
    counter-reset: visited_counter;
}

a:visited{
    counter-increment: visited_counter;
}

#results:before{
    content:counter(visited_counter);
}

This would add the number of visited links before the element with id 'results'.

Unfortunately there is no way to access it from JavaScript, you can only display it..


[initial answer]

You are aware that jQuery supports the :visited selector directly right?

Like $('a:visited')

[update]

As an alternative, you could apply a CSS property that does not rely to the getComputedStyle to retrieve..

Like a:visited{height:1px;display:block;} and then check for offsetHeight.

俯瞰星空 2024-08-31 07:24:27
  1. 在锚点(例如跨度)内添加一个子项,
  2. 使用color:继承
  3. 检测子项的颜色(JS)

警告:afaik它在lte ie7上不起作用,

因为lte ie7 ull必须

  • 添加a:visited 上的 visibility :hidden 和子项上的 visibility:inherit
  • 使用 javascript 检查子项的可见性(hidden=visited)
  1. add a child inside the anchor (for example a span)
  2. use color : inherit
  3. detect the color of the child (JS)

caveat: afaik it won't work on lte ie7

for lte ie7 ull have to

  • add visibility : hidden on a:visited and visibility : inherit on the child
  • check the visibility of the child using javascript (hidden = visited)
夜吻♂芭芘 2024-08-31 07:24:27

类似的想法,但回避了 .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://stackoverflow.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%,但差异很大)。

(哦,对 废话表示歉意;自从我尝试在没有框架的 IE 中执行事件以来已经太久了,我厌倦了与之抗争.)

A similar idea, but sidestepping .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://stackoverflow.com/">l</a></td><td></td>
            <tr><td></td><td><a href="http://www.dell.com/">l</a></td><td></td>
        </table>
    </body>
</html>

The trick, of course, is ensuring that visited and unvisited links have different widths (here, by using sans-serf vs. monospace fonts) and setting them to inline-block so that their widths can be accessed via clientWidth. Tested to work on FF3.6, IE7, Chrome 4, and Opera 10.

In my tests, accessing clientWidth was consistently faster than anything which relied on computed styles (sometimes by as much as ~40%, but widely varying).

(Oh, and apologies for the <body onload="..."> nonsense; it's been too long since I tried to do events in IE without a framework and I got tired of fighting it.)

貪欢 2024-08-31 07:24:27

由于所有版本的 IE(是的,即使是版本 8,如果您启用怪癖)都支持 CSS 表达式,因此颜色属性仍然不安全。您可能可以用这个(未经测试)加速 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;}

X路径:

visited links = document.evaluate('//a[text()="visited"]')

Since all versions of IE (Yes, even version 8 if you enable quirks) support CSS expressions the color property is still unsafe. You could probably speed up IE testing with this (untested):

a:visited { color: expression( arrVisited.push(this.href) ); }

Also this isn't really covered by your question but you can of course set properties in child nodes very easily to initiate detection and any solution would have to prevent that too:

a.google:visited span { background-image: url(http://example.com/visited/google); }

You need to protect adjacent siblings too, not just descendants:

a.google:visited + span { }

Also untested but you could probably do a heavy speedup using the content property to modify the DOM and then some XPath to find the new nodes.

a.google:visited:before {content: "visited"; visibility: hidden;}

XPath:

visited links = document.evaluate('//a[text()="visited"]')
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文