从cookie开始的登录知识--cookie

295 阅读6分钟

前言

这一切的起因又是一场面试,在被面试官骂了二十分钟之后认识到自己很多东西都没有认真的学会搞懂。虽然面试可能凉了,但是能学到些东西总归是不亏的(说实话前端学到现在真是和我最初的预想差了很多)

cookie是什么

其实在说这个问题之前,还有另一个小问题需要先明白,那就是域名以及其结构。

域名

域名说白了就是给152.134.53.15这样的ip地址起一个名字,域名与ip地址的对应关系并不是一对一的,具体DNS的解析过程可以看这篇文章,在这里并不重要。在这里我们只需要知道域名的层级问题就可以了。

对于域名test.tx.com.来说,它的完整写法是test.tx.com.root。其中.root是根域名,com.root是二级,tx.com.root是三级。当然这其实并没有什么用,域名比较反直觉的地方就在于它是从右向左看的。对于test1.tx.com.test2.tx.com.这样两个域名你只需要知道这样两件事。

  1. tx.com是test1.tx.com和test2.tx.com的父域名。
  2. test1.tx.com是tx.com的子域名。

好的让我们回到cookie,cookie是因为http无状态的特性被创造出来的东西,它的形式是一个个键值对,属于浏览器存储的一种。并且它有以下这些可以设置的属性

Domain/Path

这两个属性规定了cookie的作用域,大白话就是哪些请求可以带上我这个cookie。

domain指定了哪些主机可以接受cookie。如果没指定,默认为set-cookie的origin,不包含子域名。如果指定了domain,则一般包含子域名。例如,如果设置 Domain=tx.com,则 Cookie 也包含在子域名中(如test1.tx.com)。

Path标识指定了主机下的哪些路径可以接受 Cookie(该 URL 路径必须存在于请求 URL 中)。以字符 %x2F ("/") 作为路径分隔符,子路径也会被匹配。

例如,设置 Path=/docs,则以下地址都会匹配:

  • /docs
  • /docs/Web/
  • /docs/Web/HTTP

在我的了解里,path这个路径大部分时候都是默认值'/'

Expires/maxAge

这两个属性用来设置cookie的存在时间,maxAge单位为秒,Expires为一个具体时间,过了这个时间就失效。

不设置的话会话结束就会清除(这里会话结束并不是关闭页面这么简单)。

SameSite

这是一个非常重要的属性, SameSite Cookie 允许服务器要求某个 cookie 在跨站请求时不会被发送,(其中 Site (en-US) 由可注册域定义),从而可以阻止跨站请求伪造攻击(CSRF)。

SameSite 可以有下面三种值:

  • Strict 最为严格。如果 SameSite 的值是 Strict,那么浏览器会完全禁止第三方 Cookie。简言之,如果你从百度的页面中访问掘金的资源,而 掘金的某些 Cookie 设置了 SameSite = Strict 的话,那么这些 Cookie 是不会被发送到 掘金的服务器上的。只有你从 掘金的站点去请求 掘金 的资源时,才会带上这些 Cookie。

  • Lax 相对宽松一点。在跨站点的情况下,从第三方站点的链接打开和从第三方站点提交 Get 方式的表单这两种方式都会携带 Cookie。但如果在第三方站点中使用 Post 方法,或者通过 img、iframe 等标签加载的 URL,这些场景都不会携带 Cookie。(Chrome 将 Lax 变为默认设置。这时,网站可以选择显式关闭 SameSite 属性,将其设为 None 。不过,前提是必须同时设置 Secure 属性(Cookie 只能通过 HTTPS 协议发送),否则无效。)

  • 而如果使用 None 的话,在任何情况下都会发送 Cookie 数据。

httponly

设置httponly为true可以防止前端使用js修改cookie,一定程度上可以防止XSS攻击。

但是我这里其实有个问题,即使设置了httponly,我也可以通过控制台直接看到cookie,这样的话我直接把这些cookie添加到自己电脑里不就行了吗?

经过我的测试,把一个网站的cookie从一个浏览器直接搬运到另一个浏览器确实可以保持登录态,所以cookie不管怎么说,都是不安全的!!!

cookie携带

cookie最大的特点在于,你在向特定服务器发送请求时,会自动带上对应的cookie,但是带的规则以及它带来的安全问题也不是一件小事。

查看规则

我们都知道,你按F12就可以看到当前域名下可以查看的所有cookie。但是你在aa.bb.cc域名下无法访问dd.ee.ff下的cookie,因为cookie是跨域的。

当然了前文提到写在某域名的cookie是可以被其子域名获取到的,即:

  • cookie在 aaa.com 域名下,aaa.com 和 bbb.aaa.com 和 ccc.bbb.aaa.com 域名下都能读取

  • cookie在 bbb.aaa.com 域名下,bbb.aaa.com 和 ccc.bbb.aaa.com 域名下能读取,aaa.com 域名下不能读取

  • cookie在 ccc.bbb.aaa.com 域名下,ccc.bbb.aaa.com 域名下能读取,aaa.com 和 bbb.aaa.com 域名下不能读取

携带规则

携带和查看完全不是一个意思,举个栗子。你在aaa.com下有一个cookie,那么你在bbb.com是无法直接获取或者修改这个cookie的。但是,你在bbb.com向aaa.com发送一个请求,这个请求会携带你在aaa.com下的cookie。

我想看到这里你应该会想,这不对啊,那我在bbb.com里发一些不好的请求怎么办?这其实CSRF攻击的相关内容了,下一篇文章再讲。

如果你不想发生这种事,那就参照上面对SameSite进行设置。

跨域

对于前后端分离项目来说跨域是绕不开的话题,当然我一般都会采用cors的方法来进行跨域处理。但是跨域是无法携带cookie的,在不设置SameSite的情况下,进行以下配置即可解决

  • 前端请求时在request对象中配置"withCredentials": true

  • 服务端在responseheader中配置"Access-Control-Allow-Origin", "http://xxx:${port}";

  • 服务端在responseheader中配置"Access-Control-Allow-Credentials", "true"

但是!新版chrome默认设置了SameSite为Lax,这种方法也就不行了,当然你可以通过手动吧SameSite设置为none,但是也必须在https环境下才能生效,也就是说开发环境中无法正常携带cookie。(我还没找到很好的解决方法)

除了这种方式以外,我常用的还有Nginx反向代理,只需要简单配置一下就可以了。

结语

感觉才刚刚开始...接下来还有CSRF攻击等等...啊~~~~