V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
FaiChou
V2EX  ›  前端开发

前后端分离的项目中(跨域请求 api), 如何正确使用 cookie 作为验证?

  •  1
     
  •   FaiChou ·
    FaiChou · 2018-12-25 08:47:57 +08:00 · 8405 次点击
    这是一个创建于 2162 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题相关: fetch api 在浏览器内无法保存和发送 cookie

    昨天碰到浏览器无法发送 cookie 的问题, 最后才发现是浏览器默认禁止第三方 cookie.

    Chrome / Safari / iOS Safari 都是默认禁止三方 cookie 的.

    好久之前做项目都是用 token 作为验证方式, 现在这个小项目后端使用 php5.6 seesion 形式记录用户会话.

    那么问题来了, 现在浏览器禁止了三方 cookie 还有用 cookie 作为验证的可能吗? 不可能引导用户去手动开启 cookie 权限吧?

    有啥好的替代方案? auth2?

    ps. 小项目是 react 写的界面, 放到微信里的页面.

    36 条回复    2018-12-25 12:52:29 +08:00
    lhx2008
        1
    lhx2008  
       2018-12-25 08:52:35 +08:00 via Android
    可能你对第三方 cookies 有什么误解,credientails 在跨域时是合法的,他只是把 cookies 时间弄错了。
    FaiChou
        2
    FaiChou  
    OP
       2018-12-25 08:54:35 +08:00
    @lhx2008 cookie 时间是没错的, "GMT", 我手动开启了三方 cookie 权限 是可以正常请求的.
    shijianit
        3
    shijianit  
       2018-12-25 08:55:01 +08:00
    localStore
    lqw3030
        4
    lqw3030  
       2018-12-25 08:57:54 +08:00 via iPhone
    我用 jwt,证明“我是我”就可以了
    FaiChou
        5
    FaiChou  
    OP
       2018-12-25 08:58:05 +08:00
    @lhx2008

    前后端能做的我都做过:

    前端 credentials: 'include',
    后端 Access-Control-Allow-Credentials: true + Access-Control-Allow-Origin: http://localhost:3000

    为了复现这个问题, 我在 GCP 上写了个简单的 php



    验证就是不通过..

    当我把 cookie 权限打开 就正常了.
    lhx2008
        6
    lhx2008  
       2018-12-25 08:59:04 +08:00 via Android
    @FaiChou 那就不太清楚了,我的 chrome71 和 firefox 都没问题
    ytmsdy
        7
    ytmsdy  
       2018-12-25 08:59:14 +08:00
    Http 里面的 Authorization 了解一下?
    lhx2008
        8
    lhx2008  
       2018-12-25 09:00:56 +08:00 via Android
    你可以访问下我博客 luan.ma 看看 v2.jinrishici.com 那个请求有没带 cookies 上去
    Desiree
        9
    Desiree  
       2018-12-25 09:03:02 +08:00
    @lhx2008 好奇问下,大哥你这个博客是用什么搭的,挺好看的
    Marstin
        10
    Marstin  
       2018-12-25 09:03:54 +08:00
    跨域请求的目的是干嘛呢,为什么要带 cookie,你这里既然都已经跨域了,cookie 带过去了,也能识别吗?
    lhx2008
        11
    lhx2008  
       2018-12-25 09:08:19 +08:00 via Android
    @Desiree 博客底下有,hexo 和 aircloud 主题
    FaiChou
        12
    FaiChou  
    OP
       2018-12-25 09:09:10 +08:00
    @lhx2008 好的 等我验证下.


    @Marstin 「既然都已经跨域了,cookie 带过去了,也能识别吗」没明白这句话. 我认为浏览器会自动处理某域下的 cookie
    FaiChou
        13
    FaiChou  
    OP
       2018-12-25 09:14:38 +08:00
    @lhx2008 很奇怪..



    这是 chrome 里的, 我的跨域请求的 header 都会显示 *Provisional headers are shown*. 看不到 request header 里信息. 搜过网上的方案, 都解决不了 *Provisional headers are shown* 问题.



    这是 Safari 里的, 请求会带上 cookie, 但所以请求都看过, 没有 set-cookie, 这个 request 里的 cookie 哪里来的呢?
    lhx2008
        14
    lhx2008  
       2018-12-25 09:20:04 +08:00   ❤️ 1
    @FaiChou 确实是我错了,如果 chrome 设置了阻止第三方 cookies,确实是发不上的。但是我用过的浏览器好像默认都不阻止。
    Provisional headers are shown 是 Chrome 的祖传 Bug,对于部分 HTTP2 的连接故意不显示,其实抓包你就发现挺正常的。
    没有 cookies 访问的时候有 set-cookies,你可以清空那个域下面的 cookies,再访问一次可能可以看到。
    所以,好一点解决方法可能是用 localstorage 了,我当初也是为这个事情绞尽脑汁。
    不过好像有些统计 js 是用浏览器指纹的技术,甚至跨浏览器都可以跟踪用户,具体我也没研究出来
    wuhuaji
        15
    wuhuaji  
       2018-12-25 09:20:11 +08:00   ❤️ 1
    你的 one.json 请求,返回的 cookie 没有设置 domain 属性,应该置为当前域名,也就是 luan.ma

    部分响应头如下:
    server: nginx/1.15.5
    date: Tue, 25 Dec 2018 01:17:17 GMT
    content-type: application/json;charset=UTF-8
    set-cookie: X-User-Token=YAEAnG+2hPllOHE5Uwuxz8ZAzHqG7Pf/; Max-Age=7776000; Expires=Mon, 25 Mar 2019 01:17:17 GMT
    access-control-allow-origin: https://luan.ma
    access-control-allow-credentials: true
    lhx2008
        16
    lhx2008  
       2018-12-25 09:22:58 +08:00
    @wuhuaji 我想要做跨站保持同一个 cookies,以为这个是一个公开的 API,这个方法好像大多数时候是凑效的
    FaiChou
        17
    FaiChou  
    OP
       2018-12-25 09:28:34 +08:00
    @lhx2008 谢谢, 我的浏览器默认都是禁止, 在网上看到过好像因为隐私问题被欧盟一直追究, 所以很多浏览器都是默认禁止的

    在 Safari 中是 prevent cross-site tracking



    @wuhuaji 请问你是在 chrome 中看到这些信息的吗? 我的跨域请求在 chrome 中都看不到 set-cookie 字段. 我用 Charles 抓包关掉代理 luan.ma 就访问不了了

    lhx2008
        18
    lhx2008  
       2018-12-25 09:34:34 +08:00
    @FaiChou 是的,自从我升了 HTTP2 之后就不显示了,我开发的时候用 HTTP/1.1 啥事没有。但是如果不开阻止第三方的话,cookies 还是 set 到了
    lhx2008
        19
    lhx2008  
       2018-12-25 09:35:17 +08:00
    @wuhuaji domain 好像完全跨域是不能用的,我也不太清楚
    lhx2008
        20
    lhx2008  
       2018-12-25 09:39:40 +08:00
    MDN 其实也有写,我当初看到中文版没翻译到。
    https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Requests_with_credentials
    Third-party cookies
    Note that cookies set in CORS responses are subject to normal third-party cookie policies. In the example above, the page is loaded from foo.example, but the cookie on line 22 is sent by bar.other, and would thus not be saved if the user has configured their browser to reject all third-party cookies.
    lhx2008
        21
    lhx2008  
       2018-12-25 09:42:33 +08:00
    不过你可以研究下我网站上面那个 mta.qq.com 的请求,即使关闭了第三方 cookies,照样可以保持跟踪
    wu67
        22
    wu67  
       2018-12-25 09:44:54 +08:00
    额, 所以在 api 后面加?token=***不行吗
    wuhuaji
        23
    wuhuaji  
       2018-12-25 09:45:03 +08:00   ❤️ 1
    @lhx2008 没明白你说的 domain 跨域完全不能用什么意思? cookie 是要设置 domain 的。

    如前面有人所说,Provisional headers are shown 是 Chrome 的特色问题,不可尽信。你可用 Firefox 或者 Safire 看下。这里我看到响应头,是从请求中复制请求 [右键-copy-copy as curl ] ,然后拿到命令行中请求的。
    FaiChou
        24
    FaiChou  
    OP
       2018-12-25 09:49:07 +08:00
    @wuhuaji 好的 谢谢 我也试过 可以拿到

    lhx2008
        25
    lhx2008  
       2018-12-25 09:55:03 +08:00
    pingjs.qq.com 那个,很神奇,不知道有没大佬破解一下,关 cookies 重启浏览器依然可以保持不变

    lhx2008
        26
    lhx2008  
       2018-12-25 10:10:29 +08:00
    js 在 pingjsqq.com
    然后,核心代码是
    a = "pvi";
    window.localStorage ? localStorage.getItem(a) || sessionStorage.getItem(a) : (a = document.cookie.match(new RegExp("(?:^|;\\s)" + a + "=(.*?)(?:;\\s|$)"))) ? a[1] : "";
    先获取当前域下面的 localStorage,如果没有,获取 pingjsqq.com 域下面的 cookies 里面的 id,然后 set 到当前域的 localstorage,下次再读取当前域的 localstorage
    pubby
        27
    pubby  
       2018-12-25 10:22:02 +08:00 via Android
    请求时发送 cookie 是没问题的。

    只是无法保存跨域 api 发来的 cookie

    所以如果 api 域名是 abc.com 的话,你得想办法先跳转到 abc.com 去接收 cookie
    FaiChou
        28
    FaiChou  
    OP
       2018-12-25 10:24:28 +08:00
    @lhx2008 是的 在 local storage 里是有个 pgv_pvi 字段.
    FaiChou
        29
    FaiChou  
    OP
       2018-12-25 10:26:11 +08:00
    @pubby 是的, 这也是个解决方案, 但如果自己写的话内容有点多, 在这个小项目中不值得.
    lhx2008
        30
    lhx2008  
       2018-12-25 10:32:31 +08:00
    @FaiChou 他妙在用 js 域的 cookies 来存 token,兼容了浏览器不支持 localstorage 的情况,而且实现了跨域名追踪
    pubby
        31
    pubby  
       2018-12-25 10:37:42 +08:00 via Android
    @FaiChou 和项目大小无关,用 cookie 只能这么搞
    lhx2008
        32
    lhx2008  
       2018-12-25 11:00:56 +08:00
    我在 Github 上面看到一个更骚的操作,挂载一个 iframe,然后用 HTML5 的 postMessage 进行跨域通信
    lhx2008
        33
    lhx2008  
       2018-12-25 11:01:06 +08:00
    FaiChou
        34
    FaiChou  
    OP
       2018-12-25 11:09:30 +08:00
    @pubby @lhx2008

    谢谢.

    在 SO 上看到过一个~~答案~~问题 https://stackoverflow.com/questions/3342140/cross-domain-cookies
    lhx2008
        35
    lhx2008  
       2018-12-25 11:51:51 +08:00
    我总结了一下,发了个帖子
    https://www.v2ex.com/t/520756
    EvilCult
        36
    EvilCult  
       2018-12-25 12:52:29 +08:00
    jwt 了解一下
    header 里加 Authorization
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5702 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 08:59 · PVG 16:59 · LAX 00:59 · JFK 03:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.