【问题标题】:Set-Cookie is not working in Chrome - with two websitesSet-Cookie 在 Chrome 中不起作用 - 有两个网站
【发布时间】:2020-04-05 11:43:23
【问题描述】:

我遇到了Set-Cookie 在 Chrome 中无法运行的问题(我没有检查其他浏览器)。它过去有效,但最近停止工作。我有两个有两个域名的网站,我需要在两个网站中设置 cookie。我在每个域名中调用一个 URL 来设置 cookie。但它不会在其他网站(我现在没有浏览的网站)上设置 cookie。

用户登录或注销或注册到一个网站,我希望他们也自动从另一个网站登录或注销。目前,如果他们登录或注销一个网站,不会影响另一个网站。

Django 视图代码为:

@csrf_exempt
def set_session(request):
    """
    Cross-domain authentication.
    """
    response = HttpResponse('')
    origin = request.META.get('HTTP_ORIGIN')
    if isinstance(origin, bytes):
        origin = origin.decode()
    netloc = urlparse(origin).netloc
    if isinstance(netloc, bytes):
        netloc = netloc.decode()
    valid_origin = any(netloc.endswith('.' + site.domain) for site in Site.objects.all().order_by("pk"))
    if (not (valid_origin)):
        return response
    if (request.method == 'POST'):
        session_key = request.POST.get('key')
        SessionStore = import_module(django_settings.SESSION_ENGINE).SessionStore
        if ((session_key) and (SessionStore().exists(session_key))):
            # Set session cookie
            request.session = SessionStore(session_key)
            request.session.modified = True
        else:
            # Delete session cookie
            request.session.flush()
    response['Access-Control-Allow-Origin'] = origin
    response['Access-Control-Allow-Credentials'] = 'true'
    return response

JavaScript 代码是:

window.speedy = {};

window.speedy.setSession = function (domain, key) {
    $.ajax({
        url: '//' + domain + '/set-session/',
        method: 'post',
        data: {
            key: key
        },
        xhrFields: {
            withCredentials: true
        }
    });
};

然后有一段 JavaScript 代码调用了这个函数两次:

speedy.setSession('speedy.net', 'session_key');
speedy.setSession('speedymatch.com', 'session_key');

其中'session_key' 替换为用户的会话密钥。

这个问题有什么解决办法吗?我认为这是由于 Chrome 最近的变化。

更新:我们有一个临时服务器,其中两个网站域都是相同注册域名的子域。在那里,Set-Cookie 工作正常。但是在生产网站中,我认为其他站点的 cookie 被 Chrome 阻止了,因为其他站点的域与用户当前正在浏览的域不同。

我检查过,其他网站的 cookie 也不适用于 Firefox 和 Dolphin。可能和我们最近升级到Django 2.1有关。

【问题讨论】:

  • 尝试在您的设置模块中设置SESSION_COOKIE_SAMESITE = None
  • @aaron 是的,它有效!请看我的回答。

标签: javascript python django cookies


【解决方案1】:

此处触发 cookie 的同源策略;从一个域中,您可以设置 cookie:

  • 自己的域
  • 父域(除非父域是 (g)TLD)

因此,由于所讨论的两个域不共享父子关系,并且它们的唯一共同父级可能是 TLD(假设相同的 TLD),因此您不能这样做。

来自MDN doc

Cookie 使用单独的来源定义。页面可以为自己的域或任何父域设置 cookie,只要父域不是公共后缀即可。 Firefox 和 Chrome 使用公共后缀列表来确定域是否是公共后缀。 Internet Explorer 使用自己的内部方法来确定域是否为公共后缀。无论使用哪种协议 (HTTP/HTTPS) 或端口,浏览器都会为给定域(包括任何子域)提供 cookie。设置 cookie 时,您可以使用域、路径、安全和 Http-Only 标志来限制其可用性。当您读取 cookie 时,您无法看到它的设置位置。即使您只使用安全的 https 连接,您看到的任何 cookie 也可能是使用不安全的连接设置的。

【讨论】:

  • 每个网站都从自己的 URL 设置自己的 cookie,并且直到最近才有效。从这个意义上说,最近有什么变化吗?
  • @Uri 如果您从一个域引用另一个域的某些外部资源,则被引用域可以设置自己的 cookie,而后一个域可以看到。否则,我认为一个域无法看到其他域的 cookie。
【解决方案2】:

感谢@aaron,我发现了问题。这个问题最近才开始,在我将 Django 升级到 2.1 之后。 Django 2.1 引入了SESSION_COOKIE_SAMESITE 设置,必须将其设置为None,我们的网站才能正常使用会话cookie。另一方面,我们网站的 CSRF_COOKIE_SAMESITE 可以设置为 'Strict',因为我们为每个网站使用单独的 CSRF cookie。因此,我在我们的基本设置中添加了以下几行:

SESSION_COOKIE_SECURE = True
SESSION_COOKIE_SAMESITE = None

CSRF_COOKIE_SECURE = True
CSRF_COOKIE_SAMESITE = 'Strict'

从这些行来看,只有SESSION_COOKIE_SAMESITE = None 是解决我在这个问题中提到的问题所必需的。我依赖 Django 2.1 的默认设置为 SESSION_COOKIE_SAMESITE 的值,在这种情况下这对我们不起作用。

目前登录和注销可以在我的桌面上的 Chrome 和一部手机上运行。但是我检查了我的另一部手机,但它不起作用 - 问题仍然存在。我不确定这是由于此手机或 Chrome 应用程序中的个人设置造成的吗?但是同时登录和注销两个网站在那里不起作用。如果我登录一个网站,我仍然会从另一个网站退出,反之亦然。

目前登录和注销在 Chrome 中有效。问题在于 cookie 设置 - 请在 chrome://settings/cookies(桌面)或 settings > site settings > cookies(移动)检查您的设置。

(2020 年 8 月)更新:现在需要对 Chrome 使用以下设置。请看this questionand answer

SESSION_COOKIE_SECURE = True
SESSION_COOKIE_SAMESITE = 'None'

【讨论】:

    猜你喜欢
    • 2020-12-11
    • 2018-11-03
    • 2017-07-19
    • 2012-11-09
    • 2019-04-16
    • 2013-08-08
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    相关资源
    最近更新 更多