繁体   English   中英

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

[英]CSS/JavaScript/hacking: Detect :visited styling on a link *without* checking it directly OR do it faster than me

这是出于研究目的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').getComputedStyle (或在Internet Explorer, currentStyle )或该元素上的任何其他直接方法。

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

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

    请注意,仅出于此目的,场景是浏览器将谎言JavaScript关于<a>元素的所有属性(而不是其他属性),并且它将仅呈现color: in :visited 因此,依赖于例如文本大小或background-image将不满足该要求。

  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. 设置颜色或显示:上面访问过,并直接用getComputedStyle检查每一个
  2. 将链接的ID(加上一个空格)放在<a>标签内,并使用jQuery的:visible选择器,只提取可见文本(=访问过的链接ID)

FWIW,我是一个白帽子 ,我正在与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:目前的测试表明,使用offsetWidth (1.8%)的offsetWidth (而不是getCalculatedStyle / currentStyle )和Firefox中的~24ms(4.3%)可以节省速度,这不是我想要的10%的实力奖励赢得。 知道如何维持剩余的10%?

[新更新]

如果您希望结果仅用于视觉呈现,那么最快的方法是使用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:visited{height:1px;display:block;}然后检查offsetHeight

  1. 在锚点内添加子项(例如跨度)
  2. 使用color : inherit
  3. 检测孩子的颜色(JS)

警告:afaik它不会对lte ie7起作用

对于lte ie7 ull必须

  • 添加visibility : hiddena:visitedvisibility : inherit孩子
  • 使用javascript检查孩子的可见性(隐藏=已访问)

一个类似的想法,但回避.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与monospace字体)并将它们设置为inline-block以便可以通过clientWidth访问它们的宽度。 经测试可用于FF3.6,IE7,Chrome 4和Opera 10。

在我的测试中,访问clientWidth始终比依赖计算样式的任何东西都快(有时多达~40%,但差异很大)。

(哦,并为<body onload="...">胡说八道道歉;因为我试图在没有框架的情况下在IE中做事件已经太久了,我厌倦了打架。)

由于所有版本的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;}

XPath的:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM