【问题标题】:Chrome CORS request sending two cookies with the same nameChrome CORS 请求发送两个具有相同名称的 cookie
【发布时间】:2015-12-26 01:13:50
【问题描述】:

我正在使用基于 Laravel 的较新 PHP 版本迁移较旧的 perl 应用程序。这需要 perl 应用程序向新的 Laravel 应用程序发出 XHR 请求,而我在 Chrome 中遇到了一些问题,无法返回 cookie。

当已经登录到这两个应用程序时,我正尝试向 Laravel 应用程序发出两个请求:第一个请求 CSRF 令牌,第二个使用该令牌发出 POST 请求。

我已将 CORS 配置为可以正常发送和接收 cookie,并且初始 /token GET 调用正常工作(根据 XHR 请求发送的 cookie 进行身份验证)

/token 调用然后返回一个带有 laravel_session cookie 的 Set-Cookie 标头(如预期的那样),但我的问题是以下 POST 请求正在发送同一个 cookie 的两个版本,而 PHP 似乎只查看错误的一个,因此加载了错误的会话并针对错误的 CSRF 令牌进行测试。

这里是所有 3 个请求的详细信息 - 正如您所看到的,最终的 POST 发送的是同一 cookie 的两个版本,具有不同的值。 (为清楚起见,在 cookie 标头中添加了换行符)

这只发生在 Chrome 中,在 Safari 中它似乎发送了正确的 cookie,并且 CSRF 令牌得到了正确验证。 Chrome 版本是 45.0.2454.101。

令牌请求标头:

GET /token HTTP/1.1
Host: laravel.domain.com
Connection: keep-alive
Accept: */ *
Origin: https://perl.domain.com
X-FirePHP-Version: 0.0.6
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36
Referer: https://perl.domain.com/original/page.html
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Cookie: XSRF-TOKEN=eyJpdiI6Im5kSG02TVhsc08wUVZCZkd2WnZQa1E9PSIsInZhbHVlIjoiWFE0MXFBNlZIMnNXVHppXC9hN0dqNlJ2K1psUU9JZlFqTUdZZ3RJVmc0N1ZqV0MrVEczOGVFV0ExcDRDYmQxZDBTbFhGaWFiUkh5TGowOUgxdzVKOCtBPT0iLCJtYWMiOiJhOTYzNDFlZjUyYTdjMWFmMDE1MTFlMjczYTA0NTE2NThlYjVlNTkyOWUyZWNjZWM1MGYxODc4MmVjMTM5YTFhIn0%3D;
laravel_session=eyJpdiI6ImdSM0VTT25FUzZoY3JOeVwvN2JLWFFnPT0iLCJ2YWx1ZSI6Ilp3WHBFZlNuTnZibVMyMUlvbk1YM1YwdXF5VjRnTW1CNWVjUU1ReXlLZldSeEJxeTJFSmgyN2pyTjAydXlzMzE1TmJseWZrQmRraStDUkFqNTFReUp3PT0iLCJtYWMiOiI5MWMxM2YyNzFjOTY3ZjIxMmVjYmNlZWNlNDAzYjI2MjZkNmJhMzIyM2VlNTAwNGJlNTQ4OTU4OTMxZjJhYjE5In0%3D;
_ga=GA1.3.1924987937.1443461035;
_dc_gtm_UA-5119192-1=1

令牌响应标头:

Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:https://perl.domain.com
Cache-Control:no-cache
Connection:Keep-Alive
Content-Length:40
Content-Type:text/plain; charset=UTF-8
Date:Mon, 28 Sep 2015 17:24:18 GMT
Keep-Alive:timeout=2, max=80
P3P:policyref="/w3c/p3p.xml", CP="IDC DSP COR CURa ADMa DEVa CUSa PSAa IVAa CONo OUR IND UNI STA"
Server:Apache
Set-Cookie:XSRF-TOKEN=eyJpdiI6ImFiT3ZSWWVDUnlKcWMraGFrWnBVY2c9PSIsInZhbHVlIjoiOTVnc05UM3puVGRwTUNUbDl3T1FNTVpWdGxVM29VaHNLSUt0XC9LTkhzMG5iOGlNbmhHXC9KMDBBTW9qRjZFQXZaSmlHTmhKUVpmTGdpXC80K0lkSUhUdnc9PSIsIm1hYyI6IjI5Njc1ZWE2NTRiYTY4NWJhMmE5Y2UwNjBlZDRkOWE4OGQwOWQ5NjE1YjAyNTMwNTFmZDczY2RjNzRiNjExNDIifQ%3D%3D; expires=Mon, 28-Sep-2015 19:24:23 GMT; Max-Age=7200; path=/
Set-Cookie:laravel_session=eyJpdiI6IjJqbTRyWG1GOEd1c2NIRnd4eE4yMGc9PSIsInZhbHVlIjoiZzk2SFE2emxcL0xGNjI3aGtYd1NmWURUVEduMVZVY2dYeUlRTVo2UTYyU0I2dFljalhxTjJSY3JFMGpvXC9nc2N0N3dJUFZYbGQya3pUNit1eWtrM3JqZz09IiwibWFjIjoiNDBhYzAzZjkwNDA5ZDE4Y2Y5ZjQ1MjdiYTUwYWU2M2Y5NjVjY2I1ZmMxZWFlMzAwZWM4MmVjNWRlYjM2Yjc2ZSJ9; expires=Mon, 28-Sep-2015 19:24:23 GMT; Max-Age=7200; path=/; httponly
Vary:Origin
X-Powered-By:PHP/5.5.9-1ubuntu4.11

预检请求标头:

OPTIONS /destination/of/post HTTP/1.1
Host: laravel.domain.com
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: https://perl.domain.com
X-FirePHP-Version: 0.0.6
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36
Access-Control-Request-Headers: accept, content-type
Accept: */*
Referer: https://perl.domain.com/original/page.html
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

预检响应标头:

HTTP/1.1 200 OK
Date: Mon, 28 Sep 2015 17:24:24 GMT
Server: Apache
X-Powered-By: PHP/5.5.9-1ubuntu4.11
Allow: POST
Cache-Control: no-cache, private
access-control-allow-credentials: true
access-control-allow-origin: https://www.readytoship.com.au
access-control-allow-methods: GET, POST, PUT, DELETE
access-control-allow-headers: ACCEPT, CONTENT-TYPE
Set-Cookie: XSRF-TOKEN=eyJpdiI6ImVRTGM3Q1I5RUttXC83NlVLNEN3Z3ZRPT0iLCJ2YWx1ZSI6IlE0SVRjVnJHRHhRUXFYYUhZbVwvSEpLSFp2VVZSa0creW5OUzR2aFdXTEI5VWFEMzBCSkNjeHBzR0dycjVuYWxsOVJ4KzdNVWhhR3dMSmhiam8yUDZcL1E9PSIsIm1hYyI6ImRiYzE4ODRlMTAyOTFkMmY0NTI2YjkzMmExMGZjM2EzOTU2ZDc3N2Q1ZGQzYjNhM2EyNDY5YjhjNGIxMjVlMWYifQ%3D%3D; expires=Mon, 28-Sep-2015 19:24:24 GMT; Max-Age=7200; path=/
Set-Cookie: laravel_session=eyJpdiI6InR5M3JjWkltaVdoSldIa3FsWVp2YUE9PSIsInZhbHVlIjoibjFuODdiVXRKQmdvU1hVcTdcL3VQeWF4K243d2h3Z3EwNWtVeTNWZUdBWGFWQ21QQXlid2RFSmNLSklpanVpZUNhZGE5UlU2Q1FqUCtnSVd4UWkwM2ZRPT0iLCJtYWMiOiI1ZjNjOWQyNmZlNGI1MDI5OGQxOGY2ZGI5M2M1MTMwNWRjZGY4MDVjMGViODNjYjg0MmU5ZWQ0MzRjNjYyN2VhIn0%3D; expires=Mon, 28-Sep-2015 19:24:24 GMT; Max-Age=7200; path=/; httponly
Vary: Accept-Encoding
Content-Encoding: gzip
P3P: policyref="/w3c/p3p.xml", CP="IDC DSP COR CURa ADMa DEVa CUSa PSAa IVAa CONo OUR IND UNI STA"
Content-Length: 3501
Keep-Alive: timeout=2, max=80
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8

POST 请求标头:

POST /destination/of/post HTTP/1.1
Host: laravel.domain.com
Connection: keep-alive
Content-Length: 72
Accept: application/json, text/javascript, */ *; q=0.01
Origin: https://perl.domain.com
X-FirePHP-Version: 0.0.6
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36
Content-Type: application/json
Referer: https://perl.domain.com/original/page.html
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: _dc_gtm_UA-5119192-1=1; _ga=GA1.3.2141864485.1441288526;
__zlcmid=WXevTAW8aGLGrO; 
XSRF-TOKEN=eyJpdiI6ImQ1TFRGaWFwK3cyd3RRa3BzbUNmc0E9PSIsInZhbHVlIjoiNGEydmlLWE96NzZueWtaWWlUa3UzMjZOK29NbmNPb2VidVdVYzdSbkZsaWJMVmxBRitLT05oK3hodUc1ejRMOWJWYzVIeEl6UlpzQ0dIeWlob3pFOFE9PSIsIm1hYyI6IjkzNTczMDJlOWVhZjM5NTU0NGEyNmE5YWNiODcxNDk4YmE0ODEyYTE3ZWExODBiMmNhNDFmMGFhMjVmNjhhYjgifQ%3D%3D;
laravel_session=eyJpdiI6IkIrc3QzUk1iQnNEKysxOEg2UCtSbmc9PSIsInZhbHVlIjoiYXVDalVhaUpDMms3K3AwZFVLV0EyMDMwK25tVUQyYWw5c1MxTVRkZ0ZvVWpcL2lZUndubitsQ2VVMDF1UFcwNzNsR1doNG9TY2diMEhadHdXMEoxamt3PT0iLCJtYWMiOiI5MjE1NWE0MGNmMDgyYzhlYjBjMDUwY2JhOGYxNThjZTM0MjMwM2E3M2VjZjg1ZTgxMzIxZjE5OTkzZDEzZDhhIn0%3D;
_ga=GA1.3.1924987937.1443461035;
_dc_gtm_UA-5119192-1=1;
XSRF-TOKEN=eyJpdiI6ImFiT3ZSWWVDUnlKcWMraGFrWnBVY2c9PSIsInZhbHVlIjoiOTVnc05UM3puVGRwTUNUbDl3T1FNTVpWdGxVM29VaHNLSUt0XC9LTkhzMG5iOGlNbmhHXC9KMDBBTW9qRjZFQXZaSmlHTmhKUVpmTGdpXC80K0lkSUhUdnc9PSIsIm1hYyI6IjI5Njc1ZWE2NTRiYTY4NWJhMmE5Y2UwNjBlZDRkOWE4OGQwOWQ5NjE1YjAyNTMwNTFmZDczY2RjNzRiNjExNDIifQ%3D%3D;
laravel_session=eyJpdiI6IjJqbTRyWG1GOEd1c2NIRnd4eE4yMGc9PSIsInZhbHVlIjoiZzk2SFE2emxcL0xGNjI3aGtYd1NmWURUVEduMVZVY2dYeUlRTVo2UTYyU0I2dFljalhxTjJSY3JFMGpvXC9nc2N0N3dJUFZYbGQya3pUNit1eWtrM3JqZz09IiwibWFjIjoiNDBhYzAzZjkwNDA5ZDE4Y2Y5ZjQ1MjdiYTUwYWU2M2Y5NjVjY2I1ZmMxZWFlMzAwZWM4MmVjNWRlYjM2Yjc2ZSJ9

POST 响应标头

HTTP/1.0 302 Found
Date: Mon, 28 Sep 2015 17:24:24 GMT
Server: Apache
X-Powered-By: PHP/5.5.9-1ubuntu4.11
Cache-Control: no-cache
Location: https://laravel.domain.com/auth/login
P3P: policyref="/w3c/p3p.xml", CP="IDC DSP COR CURa ADMa DEVa CUSa PSAa IVAa CONo OUR IND UNI STA"
Content-Length: 416
Connection: close
Content-Type: text/html

【问题讨论】:

    标签: javascript laravel cookies cross-domain


    【解决方案1】:

    同名的两个 cookie 可能是因为它们位于不同的路径中,当您编辑 cookie 时,您必须指定与令牌响应标头中相同的路径和相同的域。

    【讨论】:

    • 我认为这可能是问题所在,尽管我在示例中给出的标头中的任何 cookie 都没有“/”以外的路径,所以我不确定它们是如何设置的。另一个困难是 Chrome devtools 似乎没有显示来自跨源请求的 cookie 的路径。无论如何,我发现了一个单独的 CORS 问题,它也导致了问题,并且似乎已经让它工作了。
    • 您能否使用$request->cookie() 转储您的服务器从服务器端收到的cookie,我想知道您的服务器收到了哪些cookie,因为cookie 路径和域似乎没有问题。另外我发现 preflight 请求不发送 cookie,所以 laravel 会设置一个新的 cookie,有什么特殊原因需要请求令牌部分,为什么不跳过它?
    • 我需要 CSRF 的请求令牌,因为我需要对 laravel 域进行跨源 POST 请求。不幸的是,我无法找出这些 cookie 的设置位置,结果证明是其他问题,我没有时间跟踪这些 cookie 碎片的来源。
    【解决方案2】:

    额外的 cookie(laravel_session 和 XSRF-TOKEN)未在 /token 请求中发送。这表明他们没有/ 的路径。

    此外,额外的值不会出现在任何 Set-Cookie 标头中。
    一些可能性/需要调查的事情:

    1. 您的浏览器可能通过直接浏览 laravel.domain.com 获取了 cookie。
    2. cookie 是由您未捕获的请求设置的。
      我可以根据经验告诉你,使用 Chrome 的内置工具并不能告诉你全部情况。 尝试 Fiddler(或等效的客户端代理)以确保捕获所有请求和响应。
      如果您可以访问两个站点的私钥,您还可以使用 WireShark 来捕获和解密正在交换的原始数据。
    3. cookie 是由之前的会话创建的。

    您显示的所有Set-Cookie 标头都设置了expires 和Max-Age。
    这意味着它们会保存到 Chrome 的 cookie 存储中。
    您可以通过转到 Chrome 的Settings、单击Show advanced settings、单击Privacy > Content Settings、单击All cookies and site data...来检查存储的cookie。
    单击一个域,它将为每个 cookie 显示一个“按钮”。
    单击这些可查看path、expires 等,可能更重要的是何时设置了 cookie。

    【讨论】:

    • 使用 chrome://net-internals 代替 F12 devtools 也是一个不错的选择。
    • 我在这里授予赏金,因为它可能最接近实际问题 - 身份验证失败是由于单独的 CORS 问题,不幸的是我没有时间追查这两个 cookie 的确切设置位置。谢谢你的建议!
    猜你喜欢
    • 2015-02-19
    • 2021-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-10
    • 1970-01-01
    相关资源
    最近更新 更多