Javascript 检查是否启用了第三方 cookie

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3550790/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 05:08:02  来源:igfitidea点击:

Check if third-party cookies are enabled

javascriptcookies

提问by Maurits de Boer

I have an application that needs to check whether the client browser has third-party-cookies enabled. Does anyone know how to do this in JavaScript?

我有一个应用程序需要检查客户端浏览器是否启用了第三方 cookie。有谁知道如何在 JavaScript 中做到这一点?

回答by Alan H.

Technical Background

技术背景

The third party sets & reads cookies over HTTP (not in JavaScript).

第三方通过 HTTP(而不是 JavaScript)设置和读取 cookie。

So we need two requests to an external domain to test if third-party cookies are enabled:

所以我们需要向外部域发出两个请求来测试是否启用了第三方 cookie:

  1. One where the third party sets the cookie(s)
  2. The second, with a differing response depending on whether the browser sent the cookie(s) back to the same third party in a second request.
  1. 第三方设置 cookie 的地方
  2. 第二个,根据浏览器是否在第二个请求中将 cookie 发送回同一个第三方,具有不同的响应。

We cannot use XMLHTTPRequest (Ajax) because of the DOM security model.

由于 DOM 安全模型,我们不能使用 XMLHTTPRequest (Ajax)。

Obviously you can't load both scripts in parallel, or the second request may be made beforethe first request's response makes it back, and the test cookie(s) will not have been set.

显然您不能并行加载两个脚本,或者第二个请求可能第一个请求的响应返回之前发出,并且不会设置测试 cookie。

Code Example

代码示例

Given:

鉴于:

  1. The .htmlfile is on one domain, and

  2. The .js.phpfiles are on a second domain, we have:

  1. .html文件位于一个域中,并且

  2. 这些.js.php文件位于第二个域中,我们有:

The HTML test page

HTML 测试页

Saved as third-party-cookies.html

另存为 third-party-cookies.html

<!DOCTYPE html>
<html>
<head id="head">
  <meta charset=utf-8 />
  <title>Test if Third-Party Cookies are Enabled</title>
<style type="text/css">
body {
  color: black;
  background: white none;
}
.error {
  color: #c00;
}
.loading {
  color: #888;
}
.hidden {
  display: none;
}
</style>
<script type="text/javascript">
window._3rd_party_test_step1_loaded = function(){
  // At this point, a third-party domain has now attempted to set a cookie (if all went to plan!)
  var step2Url = 'http://third-party.example.com/step2.js.php',
    resultsEl = document.getElementById('3rd_party_cookie_test_results'),
    step2El = document.createElement('script');

  // Update loading / results message
  resultsEl.innerHTML = 'Stage one complete, loading stage 2&hellip;';
  // And load the second part of the test (reading the cookie)
  step2El.setAttribute('src', step2Url);
  resultsEl.appendChild(step2El);
}
window._3rd_party_test_step2_loaded = function(cookieSuccess){
  var resultsEl = document.getElementById('3rd_party_cookie_test_results'),
    errorEl = document.getElementById('3rd_party_cookie_test_error');
  // Show message
  resultsEl.innerHTML = (cookieSuccess ? 'Third party cookies are <b>functioning</b> in your browser.' : 'Third party cookies appear to be <b>disabled</b>.');

  // Done, so remove loading class
  resultsEl.className = resultsEl.className.replace(/\bloading\b/,' ');
  // And remove error message
  errorEl.className = 'hidden';
}
</script>
</head>
<body id="thebody">

  <h1>Test if Third-Party Cookies are Enabled</h1>

  <p id="3rd_party_cookie_test_results" class='loading'>Testing&hellip;</p>
  <p id="3rd_party_cookie_test_error" class="error hidden">(If this message persists, the test could not be completed; we could not reach the third-party to test, or another error occurred.)</p>

  <script type="text/javascript">
  window.setTimeout(function(){
    var errorEl = document.getElementById('3rd_party_cookie_test_error');
    if(errorEl.className.match(/\berror\b/)) {
      // Show error message
      errorEl.className = errorEl.className.replace(/\bhidden\b/,' ');
    } else {
    }
  }, 7*1000); // 7 sec timeout
  </script>
  <script type="text/javascript" src="http://third-party.example.com/step1.js.php"></script>
</body>
</html>

The first third-party JavaScript file

第一个第三方 JavaScript 文件

Saved as step1.js.php

另存为 step1.js.php

This is written in PHP so we can set cookies as the file loads. (It could, of course, be written in any language, or even done in server config files.)

这是用 PHP 编写的,因此我们可以在文件加载时设置 cookie。(当然,它可以用任何语言编写,甚至可以在服务器配置文件中完成。)

<?php
  header('Content-Type: application/javascript; charset=UTF-8');
  // Set test cookie
  setcookie('third_party_c_t', 'hey there!', time() + 3600*24*2);
?>
window._3rd_party_test_step1_loaded();

The second third-party JavaScript file

第二个第三方 JavaScript 文件

Saved as step2.js.php

另存为 step2.js.php

This is written in PHP so we can read cookies, server-side, before we respond. We also clear the cookie so the test can be repeated (if you want to mess around with browser settings and re-try).

这是用 PHP 编写的,因此我们可以在响应之前读取服务器端的 cookie。我们还清除了 cookie,以便可以重复测试(如果您想弄乱浏览器设置并重试)。

<?php
  header('Content-Type: application/javascript; charset=UTF-8');
  // Read test cookie, if there
  $cookie_received = (isset($_COOKIE['third_party_c_t']) && $_COOKIE['third_party_c_t'] == 'hey there!');
  // And clear it so the user can test it again 
  setcookie('third_party_c_t', '', time() - 3600*24);
?>
window._3rd_party_test_step2_loaded(<?php echo ($cookie_received ? 'true' : 'false'); ?>);

The last line uses the ternary operator to output a literal Javascript trueor falsedepending on whether the test cookie was present.

最后一行使用三元运算符输出文字 Javascripttruefalse取决于测试 cookie 是否存在。

Test it here.

在这里测试一下

Available for your testing pleasure at https://alanhogan.github.io/web-experiments/3rd/third-party-cookies.html.

可在https://alanhogan.github.io/web-experiments/3rd/third-party-cookies.html为您提供测试乐趣。

(As a final note — don't use someone else's serverto test third-party cookies without their permission. It could break spontaneously or inject malware. And it's rude.)

(最后一点 -未经他人许可,请勿使用其他人的服务器来测试第三方 cookie。它可能会自发中断或注入恶意软件。这是不礼貌的。)

回答by Gojko Adzic

Here's a pure JS solution not requiring any server-side code, so it can work from a static CDN: https://github.com/mindmup/3rdpartycookiecheck- the first script sets the cookie in the code, then redirects to a second script that will post a message to the parent window.

这是一个不需要任何服务器端代码的纯 JS 解决方案,因此它可以从静态 CDN 工作:https: //github.com/mindmup/3rdpartycookiecheck- 第一个脚本在代码中设置 cookie,然后重定向到第二个脚本这将向父窗口发布一条消息。

You can try out a live version using https://jsfiddle.net/tugawg8y/

您可以使用https://jsfiddle.net/tugawg8y/试用实时版本

client-side HTML:

客户端 HTML:

third party cookies are <span id="result"/>
<iframe src="https://mindmup.github.io/3rdpartycookiecheck/start.html"
    style="display:none" />

client-side JS:

客户端JS:

 var receiveMessage = function (evt) {
   if (evt.data === 'MM:3PCunsupported') {
     document.getElementById('result').innerHTML = 'not supported';
   } else if (evt.data === 'MM:3PCsupported') {
     document.getElementById('result').innerHTML = 'supported';
   }
 };
 window.addEventListener("message", receiveMessage, false);

Of course, this requires that the client runs JavaScript which is a downside compared to the server-based solutions; on the other hand, it's simpler, and you were asking about a JS solution.

当然,这需要客户端运行 JavaScript,这与基于服务器的解决方案相比是一个缺点;另一方面,它更简单,您正在询问 JS 解决方案。

回答by Greg Dubicki

Alan's solutionis great, but you don't have to use PHP or any other server-side programming language.

Alan 的解决方案很棒,但您不必使用 PHP 或任何其他服务器端编程语言。

At least if you use nginx. :)

至少如果你使用nginx。:)

This is a pure* nginx server-side configuration for Alan's solution:

这是 Alan 解决方案的纯* nginx 服务器端配置:

Nginx config start

Nginx 配置启动

server {
    listen 80;
    server_name third-party.example.com

    # don't allow user's browser to cache these replies
    expires -1;
    add_header Cache-Control "private";
    etag off;

The first third-party "JavaScript file" - served by nginx

第一个第三方“JavaScript 文件”——由 nginx 服务

    location = /step1.js.php {
        add_header Content-Type 'application/javascript; charset=UTF-8';

        add_header Set-Cookie "third_party_c_t=hey there!;Max-Age=172800";

        return 200 'window._3rd_party_test_step1_loaded();';
    }

The second third-party "JavaScript file" - served by nginx

第二个第三方“JavaScript文件”——由nginx提供

    location = /step2.js.php {
        add_header Content-Type 'application/javascript; charset=UTF-8';

        set $test 'false';
        if ($cookie_third_party_c_t = 'hey there!') {
            set $test 'true';
            # clear the cookie
            add_header Set-Cookie "third_party_c_t=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
        }

        return 200 'window._3rd_party_test_step2_loaded($test);';
    }

Nginx config end

Nginx 配置结束

}



Side notes:

旁注:

  • Yeah, yeah, I know that IfIsEvil,
  • I kept the names ending with ".php" for complete compatibility with Alan's "The HTML test page" (third-party-cookies.html),
  • You can also move common "setting the Content-Type header" line of both locations to the serversection (scope) of the config - I have kept it this way for the keep it more "1:1" translation.
  • 是的,是的,我知道IfIsEvil
  • 为了与 Alan 的“HTML 测试页”( third-party-cookies.html)完全兼容,我保留了以“.php”结尾的名称,
  • 您还可以将两个位置的常见“设置 Content-Type 标头”行移动到配置的server部分(范围) - 我保持这种方式是为了保持更多的“1:1”翻译。

回答by Marc B

In theory you'd just have a page call out somewhere that would set a thirdparty cookie and then check for that cookie's existence. However, standard browser security does not allow scripts from domain A to do anything with cookies set on domains B,C,etc... e.g. you can't access "foreign" cookies.

从理论上讲,您只需在某处调用一个页面来设置第三方 cookie,然后检查该 cookie 是否存在。但是,标准浏览器安全性不允许域 A 中的脚本对域 B、C 等上设置的 cookie 执行任何操作……例如,您无法访问“外部”cookie。

If you have some specific usage in mind, such as checking if ads are blocked (which would also block the 3rd party tracking cookie), you could check if the ad server's content is within the page's DOM, but you couldn't see if the cookie's there.

如果您有一些特定的用途,例如检查广告是否被阻止(这也会阻止第 3 方跟踪 cookie),您可以检查广告服务器的内容是否在页面的 DOM 内,但您无法查看饼干在那里。

回答by yashhy

Third Party Cookie detection with Whitelisting of URLs

使用 URL 白名单进行第三方 Cookie 检测

Alan H& Gojko Adzicare good enough for majority of use cases, but these solutions won't work if you want your users to do whitelisting of third party cookies only to certain domains.

Alan H& Gojko Adzic对于大多数用例来说已经足够好了,但是如果您希望您的用户仅将第三方 cookie 列入特定域的白名单,这些解决方案将不起作用。

I'm presenting a slightly modified version of Gojko Adzic's answer

我提出的一个稍作修改的版本戈杰科·阿德齐奇答案

For this we need two domains :

为此,我们需要两个域:

  • Domain 1, this is the page your user lands, it initially sets tpc=pending, then it redirects to Domain 2
  • Domain 2 injects Domain 1's url in an iFrame, tries to set a cookie tpc=trueand redirects back to Domain 1
  • Now, Domain 1 reads the cookie tpcand checks if its true, if we get value as true, third party cookies are allowed if it is still in pendingthird party cookies are blocked blocked.
  • 域 1,这是您的用户登陆的页面,它最初设置为tpc=pending,然后重定向到域 2
  • 域 2 在 iF​​rame 中注入域 1 的 url,尝试设置 cookietpc=true并重定向回域 1
  • 现在,域 1 读取 cookietpc并检查它的true,如果我们得到的值为 true,则允许第三方 cookie,如果它仍然在pending第三方 cookie 中被阻止。

Now, you might ask your users to whitelist (allow third party cookies) ONLYfor Domain 1, also by this technique third party detection will be accurateif the users had white listed your domain.

现在,你可能会问你的用户白名单(允许第三方cookie)ONLYDomain 1,也通过这种技术的第三方检测将是accurate,如果用户有白色列出您的域名。



This is tested in Chrome 74, 75, 76 & Edge 78

这是在 Chrome 74、75、76 和 Edge 78 中测试的

Unfortunately, Mozilla doesn't provide whitelisting of urls like Chrome does and Safari has it own mechanisms of detecting third party cookies (ITP).

不幸的是,Mozilla 不像 Chrome 那样提供 URL 白名单,Safari 有自己的检测第三方 cookie (ITP) 的机制。

P.S. Will upload this demo in my github when I get time.

PS有时间会在我的github上传这个demo。

回答by PHP Guru

My solution works by loading a <script> from an external domain that sets a cookie, checks if it was successful, and then passes the result (1 or 0) as an argument to a callback function.

我的解决方案通过从设置 cookie 的外部域加载 <script> 来工作,检查它是否成功,然后将结果(1 或 0)作为参数传递给回调函数。

The HTML:

HTML:

<script>
function myCallback(is_enabled) {
    if (is_enabled===1) {//third party cookies are enabled
    }
}
</script>
<script src="https://third-party-domain/third-party-cookies.php?callback=myCallback"></script>

If you prefer to run it asynchronously, you may use the async and defer attributes.

如果您更喜欢异步运行它,您可以使用 async 和 defer 属性。

This also works with jQuery:

这也适用于 jQuery:

<script>
$.ajax({
    url: 'https://third-party-domain/third-party-cookies.php',
    dataType: 'jsonp',
}).done(function(is_enabled) {
    if (is_enabled===1) {//third party cookies are enabled
    }
})
</script>

Here is the third-party-cookies.php code. This must be hosted on a different domain. The server must support PHP:

这是第三方cookies.php 代码。这必须托管在不同的域上。服务器必须支持 PHP:

<?php

header('Cache-Control: no-store');
header('Content-Type: text/javascript');

if ($_GET['callback']=='') {
    echo 'alert("Error: A callback function must be specified.")';
}
elseif (!isset($_GET['cookieName'])) {// Cookie not set yet
    $cookieName = strtr((string)$_SERVER['UNIQUE_ID'], '@', '_');
    while (isset($_COOKIE[$cookieName]) || $cookieName=='') {
        $cookieName = dechex(mt_rand());// Get random cookie name
    }
    setcookie($cookieName, '3rd-party', 0, '/');
    header('Location: '.$_SERVER['REQUEST_URI'].'&cookieName='.$cookieName);
}
elseif ($_COOKIE[$_GET['cookieName']]=='3rd-party') {// Third party cookies are enabled.
    setcookie($_GET['cookieName'], '', -1, '/'); // delete cookie
    echo $_GET['callback'].'(1)';
}
else {// Third party cookies are not enabled.
    echo $_GET['callback'].'(0)';
}