一.cookie
在调用cookie时,由于可以校验cookie的有效期,以及对方发送的域,协议等信息,所以正规发送的cookie数据不会因为来自其他站点的攻击而泄漏
假设有一个名为"session_id"的Cookie,其值为"abc123",并且它附加在域名为"example.com"的网站上。我们来看看如何解释这个Cookie中的各个字段:
- 名称(Name) :Cookie的名称是"session_id",用于唯一标识这个Cookie。
- 值(Value) :与该Cookie相关联的值是"abc123",这是一个会话标识符或令牌,用于识别用户的会话或身份。
- 域(Domain) :假设Cookie的域属性设置为".example.com",这意味着该Cookie可被example.com的所有子域名(如"www.example.com"、"blog.example.com"等)访问。如果将域属性设置为特定的子域名(例如"www.example.com"),则只有该子域名可以访问该Cookie。
- 路径(Path) :默认情况下,Cookie的路径属性设置为"/",表示该Cookie对example.com网站的所有路径都是可见的。这意味着无论用户访问example.com的哪个页面,都会发送这个Cookie。
- 过期时间(Expires / Max-Age) :过期时间决定了Cookie的有效期。如果设置了过期时间,例如"Expires=Sat, 01 Jan 2023 00:00:00 GMT",则该Cookie将在指定的日期和时间后过期。如果使用Max-Age字段,例如"Max-Age=3600",则该Cookie将在3600秒(即1小时)后过期。在这两种情况下,一旦超过过期时间,浏览器将停止发送该Cookie。
- 安全标志(Secure) :如果设置了安全标志,例如"Secure",则浏览器只会在通过HTTPS连接时发送该Cookie。这有助于保护Cookie的安全性,因为它只能在加密的HTTPS连接中传输。
- HTTP Only标志(HttpOnly) :如果设置了HTTP Only标志,例如"HttpOnly",则该Cookie将无法通过客户端脚本(如JavaScript)访问。这意味着JavaScript代码无法读取或修改该Cookie,有助于防止跨站点脚本攻击(XSS)。
- cookie由服务端写入
- 在前端给后端发送请求的时候会自动携带Cookie中的数据,但是SessionStorage、 LocalStorage不会
二.localStorage
来看看localStorage的一些特点
- 生命周期:持久化的本地存储,除非手动删除,不然数据永远不会过期
- 存储在客户端
- 存储的信息在同一域中共享
- 大小:5M左右(cookie一般4K左右)
- 如果存储过多内容会消耗内存,导致页面卡顿
- 受到同源策略限制
- 前端写入
缺点
- 无法和cookie一样设置过期时间,导致在用于网站登录功能时需要配合其他的操作
- 只能传入字符串,在保存复杂类型时依赖json.stringify
三.sessionStorage
与localStorage的大部分特性相同, 不同的是:
- 页面关闭时sessionStorage会删除数据,因此localStorage适用于长期登录,sessionStorage适用于敏感账号的一次性登录 -sessionStorage限制在一个页面,如果一个浏览器同时打开两个网页,localstorage和cookie是共享的,sessionstorage是不共享的
四.登录状态保存的两种方案
因为 http 是无状态的,也就是说上一次请求和下一次请求之间没有任何关联。所以需要有东西来保存登录状态
- 服务端存储的cookie+session
- 客户端存储的jwt+token
1.cookie+session
服务端在响应客户请求时会返回一个cookie,后续客户端的请求会自动带上这个cookie(http的机制)。 然后根据 cookie 里的标记去查找的服务端对应的数据叫做 session,这个标记就是 session 的 id。
如图,请求自动带上了 cookie,那两次请求就都可以找到 id 为 1 对应的 session,自然就知道当前登录的用户是谁,也可以存储其他的状态数据。
但是这种方案是有问题的
1.CSRF跨站请求伪造
当我们在一个网站登录后cookie会在发请求时自动带上,那么如果这时我们去到另一个网站,点击了某些东西,然后请求会发到原来的网站上,而这个时候cookie也会自动携带,那么比人就能拿到我们的一些信息
解决方案:随机值:每次随机生成一个值返回, 后面客户端每次发请求都要包含这个值,然后服务端在接收cookie时也要校验这个随机值
2.session的分布式问题
session在服务端保存状态数据,如果后端是微服务的架构,把不同功能放在不同的服务器中,而登录后的session是存在一台服务器的,这样其他服务器就拿不到信息,无法完成对应功能
解决方案:通过redis+session:把 session 保存在 redis,这样每台服务器都去redis里查,只要一台服务器登录了,其他的服务器也就能查到 session。
3.跨域问题
cookie 为了安全,会做 domain 的限制的,设置 cookie 的时候会指定一个 domain,只有这个 domain 的请求才会带上这个 cookie。 ajax 请求跨域的时候也是不会带上 cookie 的
解决方案:手动设置 withCredentials 为 true 并且服务端代码设置了相对应的header,指定为当前跨域的域名
2.JWT
相较于cookie+session的把信息存在服务端,jwt把信息存在客户端,JWT 是由 header、payload、verify signature 三部分组成的,其实就是一个很长的字符串
- header部分保存的是当前的签名算法,再由base64编码得到
- payload保存的是用户的具体的信息,json格式再经过base64编码
- signature 部分是把 header 和 payload 还有 salt 做一次加密之后生成的。(salt就是一段任意的字符串,增加随机性),也是base64编码得到,signature用于验证前两部分有没被篡改
把这三个连在一起authorization: Bearer xxxxx.xxxxx.xxx放在header中
发送请求的时候把这个header 带上,服务端就可以解析出对应的 header、payload、signature 这三部分,然后根据 header 里的算法也对 header、payload 加上 salt 做一次加密,如果得出的结果和signature 一样,就接受这个 token。
但是其实JWT也是有点问题的
- jwt用base64编码放在header里,他还是一种明文,安全度不高,因此最好不要把重要的信息存在里头,或者在payload那步进行一下加密
- jwt保存在客户端,所以无法手动让他失效