在 JavaScript 中隐藏/欺骗引荐来源网址的最可靠方法是啥?

Posted

技术标签:

【中文标题】在 JavaScript 中隐藏/欺骗引荐来源网址的最可靠方法是啥?【英文标题】:What is the most reliable way to hide / spoof the referrer in JavaScript?在 JavaScript 中隐藏/欺骗引荐来源网址的最可靠方法是什么? 【发布时间】:2012-02-12 04:14:40 【问题描述】:

通常,引荐来源网址可通过以下方式追踪:

javascriptdocument.referrer 请求标头,例如php$_SERVER['HTTP_REFERER']

我已经设置了一个 Codepad demo 来显示这些属性,用于测试目的。

#要求:

    应该有效地隐藏原始引荐来源网址,至少对于所有鼠标事件。 跨浏览器支持(至少 Chrome 和 Firefox)。 独立,没有任何外部内容(插件、库、重定向页面等)。 没有副作用:链接应该被重写,历史条目应该保留

该解决方案将用于在点击<a href="url">链接时隐藏引荐来源。


##用例的准确描述 如this question on Webapps 中所述,Google 搜索中的链接会在点击时进行修改。因此,

    Google 能够跟踪您的搜索行为(隐私权--) 页面请求略有延迟。 链接页面无法跟踪您的 Google 搜索查询(隐私++) 拖动/复制的 URL 看起来像 http://google.com/lotsoftrash?url=actualurl

我正在开发一个Userscript (Firefox) / Content script (Chrome) (code),它会删除 Google 的链接破坏事件。结果,处理了第 1、2 和 4 点。

第 3 点仍然存在。

铬:<a rel="noreferrer"> 火狐:data-URIs。我已经创建了一种复杂的方法来为左键和中键实现此功能,同时仍然执行第 4 点。但是,我正在努力使用右键单击方法。

【问题讨论】:

FWIW,Facebook 将所有外部链接重定向到l.php?the_url_you_want_to_visit,以确保推荐人属性中不包含任何个人信息。这可能暗示“这是不可能的”。 Their detailed engineering note might be of interest. @Matt 我不想使用外部重定向页面的原因是1)右键复制会返回重定向链接(而不是实际的)。 2)涉及到外部页面,降低了浏览速度。见this userscript。 能达到目的吗?它有效地阻止搜索引擎过分重视用户生成的链接,例如论坛上的链接(人们放在他们的标志上) 我认为有一个更好的办法来破解 google 的代码,用他们的 spyredirector 替换纯链接 +1 - 这是一个经久不衰的问题。无论是用于良好还是 ad [sic] 这都有很多优点,有时您只需要绕过引荐来源网址(我刚才有一个实例,通过我的链接引荐会产生正确的网址,但随后基本 url 检测到这个 redirsct 并发出它自己的重定向回我的域 - 不是我想要的。我会尝试你的解决方案,看看它是否有效。但是,+1 仍然是任何一种方式,因为这里的逻辑激起了我的想法!! 【参考方案1】:

我找到了适用于 Chrome 和 Firefox 的解决方案。我已经在用户脚本中实现了代码,Don't track me Google

演示(在 Firefox 9 和 Chrome 17 中测试):http://jsfiddle.net/RxHw5/

Webkit(Chrome、..)和 Firefox 37+ (33+*) 的引用隐藏

基于 Webkit 的浏览器(例如 Chrome、Safari)support<a rel="noreferrer">spec。 通过将此方法与两个事件侦听器相结合,可以完全实现引用者隐藏:

mousedown - 单击时、中键单击、右键单击上下文菜单... keydownTab Tab Tab ... Enter)。李>

代码:

function hideRefer(e) 
   var a = e.target;
   // The following line is used to deal with nested elements,
   //  such as: <a href="."> Stack <em>Overflow</em> </a>.
   if (a && a.tagName !== 'A') a = a.parentNode;
   if (a && a.tagName === 'A') 
      a.rel = 'noreferrer';
   

window.addEventListener('mousedown', hideRefer, true);
window.addEventListener('keydown', hideRefer, true);

* rel=noreferrer 从 33 开始在 Firefox 中得到支持,但支持仅限于页内链接。当用户通过上下文菜单打开选项卡时,仍然会发送推荐人。此错误已在 Firefox 37 [bug 1031264] 中修复。

旧 Firefox 版本的引用隐藏

Firefox 不支持 rel="noreferrer" 直到版本 33 `[bug 530396](或 37,如果您还希望隐藏上下文菜单的引用者)。

data-URI + &lt;meta http-equiv=refresh&gt; 可用于在 Firefox(和 IE)中隐藏引荐来源网址。实现这个功能比较复杂,但也需要两个事件:

click - 单击时,中键时,Enter contextmenu - 右键单击​​时,Tab Tab ... 上下文菜单

在 Firefox 中,每个mouseup 都会触发click 事件并且在链接(或表单控件)上点击Entercontextmenu 事件是必需的,因为对于这种情况,click 事件触发得太晚了。

基于数据 URI 和瞬间超时: 当click 事件被触发时,href 属性被临时替换为一个 data-URI。事件结束,并发生默认行为:打开数据 URI,取决于 target 属性和 SHIFT/CTRL 修饰符。 同时,href 属性恢复到原来的状态。

contextmenu 事件被触发时,链接也会瞬间改变。

Open Link in ... 选项将打开数据 URI。 Copy Link location 选项指的是恢复的原始 URI。 ☹ Bookmark 选项指的是数据 URI。 ☹ Save Link as 指向数据 URI。

代码:

// Create a data-URI, redirection by <meta http-equiv=refresh content="0;url=..">
function doNotTrack(url) 
   // As short as possible. " can potentially break the <meta content> attribute,
   // # breaks the data-URI. So, escape both characters.
   var url = url.replace(/"/g,'%22').replace(/#/g,'%23');
   // In case the server does not respond, or if one wants to bookmark the page,
   //  also include an anchor. Strictly, only <meta ... > is needed.
   url = '<title>Redirect</title>'
       + '<a href="' +url+ '" style="color:blue">' +url+ '</a>'
       + '<meta http-equiv=refresh content="0;url=' +url+ '">';
   return 'data:text/html,' + url;

function hideRefer(e) 
   var a = e.target;
   if (a && a.tagName !== 'A') a = a.parentNode;
   if (a && a.tagName === 'A') 
      if (e.type == 'contextmenu' || e.button < 2) 
         var realHref = a.href; // Remember original URI
         // Replaces href attribute with data-URI
         a.href = doNotTrack(a.href);
         // Restore the URI, as soon as possible
         setTimeout(function() a.href = realHref;, 4);
      
   

document.addEventListener('click', hideRefer, true);
document.addEventListener('contextmenu', hideRefer, true);

结合两种方法

不幸的是,没有直接的方法来检测此功能(更不用说考虑错误了)。所以你可以选择基于navigator.userAgent的相关代码(即UA-sniffing),或者使用How can I detect rel="noreferrer" support?中的一种复杂检测方法。

【讨论】:

不幸的是,数据:URI 不能在 IE 中使用,它只支持可下载的内容,不支持 HTML。 在 Firefox 28 中使用事件监听器在元素(不是文档)上单击鼠标中键不会触发 hideRefer。有什么想法吗? 带有 rel='noreferrer'(无 javascript)的上下文菜单不会在 Chrome 34 上隐藏引荐来源网址。有什么想法吗? @Lukas 救援网络档案:web.archive.org/web/20131105004231/http://userscripts.org/… bug 530396 已修复。【参考方案2】:

您不能创建一个驻留在 iframe 中的链接系统吗?

如果您在每个链接周围包裹 iframe,则 iframe 可以充当外部取消引用。用户将单击框架内的链接,打开一个页面,其引用者设置为 iFrame 的位置,而不是实际页面。

【讨论】:

我刚刚再次阅读了您的答案。这是个好主意。您能否详细说明您对在不使用外部页面的情况下设置 iFrame 的不同 URL 的想法?如何定位 iFrame? 我已将赏金奖励给您的答案,因为它包含一个潜在有用的概念,经过调整。这种方法虽然有一些缺点/问题。主要问题是框架的定位和定位。使用tab 键在链接之间导航也变得更加复杂。最后,在所有锚点上动态添加帧的性能命中/平滑度也是一个值得关注的主题。 jpgerek 实现了此答案中描述的方法。见this answer on this page。【参考方案3】:

根据要求,使用 JavaScript:

var meta = document.createElement('meta');
meta.name = "referrer";
meta.content = "no-referrer";
document.getElementsByTagName('head')[0].appendChild(meta);

这会将以下元标记添加到网页的 head 部分:

<meta name="referrer" content="no-referrer" />

截至 2015 年这是防止发送 Referer 标头的方法。

【讨论】:

这似乎适用于 Firefox、Chrome 和 Opera(据说也适用于最新版本的 Safari - caniuse.com/referrer-policy),但我在 the specification 中没有看到明确声明插入通过 JavaScript 的元标记立即生效。如果 UA 停止处理注入脚本的元标记,它们仍然符合标准。显然(基于在bugzil.la/704320 阅读有关 Firefox 实现的信息),最后处理的元标记总是“获胜”。 (待续) &lt;meta name=referrer&gt; 如果您总是想声明特定的引荐来源网址策略,这似乎是一个很好的选择,但否则(如果您只想定位特定链接)使用 &lt;a rel="noreferrer"&gt; 更合适,因为 1 ) 它优先于引用策略,2) 它特定于链接,对文档中的其他链接没有副作用,3) 它具有更好的浏览器支持。 对于链接,是的。但是,元标记也适用于 Ajax 请求。这似乎是禁用 Ajax 引用的唯一方法。【参考方案4】:

在 Javascript 中有一个跨浏览器的解决方案,它删除了引用者,它使用动态创建的 iframe,你可以看一下proof of concept(免责声明:它使用了我写的一个小 JS 库)。

【讨论】:

感谢发布this answer 中描述的方法的实现。但它确实在 Opera 中不起作用(测试 11.62、12.00b、12.02)。另一方面,它确实适用于 Safari 3+、Chrome 1+、Firefox 1+ 和 IE6、7 和 8。它不适用于 Internet Explorer 9 和 10。因此,在实践中,它只在 Chrome、Safari 和 Firefox 中有用。 此链接已失效【参考方案5】:

您可以使用新的Referrer Policy standard draft 来防止将referer 标头发送到请求源。示例:

<meta name="referrer" content="none">

虽然 Chrome 和 Firefox 已经实施了推荐人政策的草稿版本,但您应该小心使用它,因为例如 Chrome 需要no-referrer 而不是none(我也在某处看到了never)。如果您只添加三个单独的元标记,我不知道行为,但如果这不起作用,您仍然可以只实现一个简短的脚本,它遍历所有三个值并检查在设置属性后是否真的设置了值/元标记的属性。

此元标记适用于当前页面上的所有请求(ajax、图像、脚本、其他资源...)和导航到另一个页面。

【讨论】:

【参考方案6】:

这比乍看起来要复杂。看一下这个项目的代码:

https://github.com/knu/noreferrer

他承诺了你想要的,但你必须在链接页面上做到这一点。

【讨论】:

最初看起来很有希望。但是,它与我自己的方法(当前使用 data-urls+meta,rel="noreferrer")没有什么不同,除了禁用鼠标中键方法,这是不希望的。我通常使用滚轮点击链接。【参考方案7】:

您所要求的无法在 Firefox 中完成。

current context menu implementation 始终将当前文档作为引用者传递:

// Open linked-to URL in a new window.
openLink: function () 
    var doc = this.target.ownerDocument;
    urlSecurityCheck(this.linkURL, doc.nodePrincipal);
    openLinkIn(this.linkURL, "window", 
        charset: doc.characterSet,
        referrerURI: doc.documentURIObject // <----------------
    );
,

// Open linked-to URL in a new tab.
openLinkInTab: function () 
    var doc = this.target.ownerDocument;
    urlSecurityCheck(this.linkURL, doc.nodePrincipal);
    openLinkIn(this.linkURL, "tab", 
        charset: doc.characterSet,
        referrerURI: doc.documentURIObject // <----------------
    );
,

// open URL in current tab
openLinkInCurrent: function () 
    var doc = this.target.ownerDocument;
    urlSecurityCheck(this.linkURL, doc.nodePrincipal);
    openLinkIn(this.linkURL, "current", 
        charset: doc.characterSet,
        referrerURI: doc.documentURIObject // <----------------
    );
, 

显然,用户脚本不允许更改上下文菜单实现,因此唯一的出路是浏览器扩展。

(或者,这将是一个非常糟糕的 hack,通过在 contextmenu 事件上调用 preventDefault() 禁用上下文菜单,并使用您自己的自定义上下文菜单)

【讨论】:

openLinkIn 的实现可以在utilityOverlay.js 中找到 实际上,你有一个非常小的机会来欺骗上下文菜单,因为“复制到剪贴板”命令使用a different method 来获取 URL,而忽略了this.linkURL 刚刚浏览了您的链接资源。似乎不可能在没有任何副作用的情况下实现引用者隐藏功能。如果没有其他人发布替代方案,那么赏金就是你的。【参考方案8】:

可以在以下位置找到非常全面(但简短)的分析:

http://lincolnloop.com/blog/2012/jun/27/referrer-blocking-hard/

本文分析了其他答案中解释的两种方法(js 方法、iframe 重定向),最后提出了一种中介重定向器页面方法,就像在 google 搜索链接中看到的那样。

【讨论】:

感谢您的回答。不幸的是,该博客仅提及选项。此外,博客文章中几乎所有可能的解决方案都已在此处介绍:rel="noreferrer",Github 上的 noreferrer 和 iframe 路由。 “妥协可用性”解决方案依赖于创建一个丑陋的重定向 URL——这正是我想要避免的。【参考方案9】:

我已经使用 jquery 实现了一个简单但有效的 iframe 解决方案。

https://jsfiddle.net/skibulk/0oebphet/

(function($)
  var f = $('<iframe src="about:blank" style="display: none !important;">').appendTo('body');
  $('a[rel~=noreferrer]').click(function(event)
    var a = $(event.target.outerHTML);
    a.appendTo(f.contents().find('body'));
    a[0].click();
    return false;
  );
)(jQuery);

【讨论】:

【参考方案10】:

如果我们使用 JavaScript 提交 FORM,这样就没有推荐人了。

document.form_name.submit()

基本上我们是用所需的 ACTION 方法提交表单。

【讨论】:

不起作用。访问jsfiddle.net/Bp52M/show/1 (source 并在控制台中输入document.referrer。您会看到引荐来源网址仍然可用。

以上是关于在 JavaScript 中隐藏/欺骗引荐来源网址的最可靠方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

停止将引荐来源网址发送到目的地的链接

PHP HTTP 引荐来源网址

如何在 playframework 中获取引荐来源网址

在 ASP.NET 中获取 HTTP 引荐来源网址

如何在 ASP.NET MVC 操作中获取引荐来源网址?

如何在Unity3d游戏中检索Android安装引荐来源网址