前言

最近使用next.js来开发前端网站,在登录环节发现cookie的存储和跨域存在问题,一直没弄懂cookie的原理,看了网上好多大佬的文章,大有收获分享给大家。

Cookie介绍

HTTP cookie(Web cookie,浏览器 cookie)是服务器发送到用户 Web 浏览器的一小段数据。浏览器可能会存储 cookie 并将其与稍后的请求一起发送回同一服务器。通常,HTTP cookie 用于判断两个请求是否来自同一个浏览器——例如,让用户保持登录状态。它为无状态HTTP 协议 记住有状态信息。

Cookies主要用于三个目的:

1、会话管理:如登录、购物车、游戏分数或服务器应记住的任何其他内容
2、个性化:如用户偏好、主题和其他设置
3、追踪:如记录和分析用户行为

1、创建 cookie
接收到 HTTP 请求后,服务器可以发送一个或多个Set-Cookie响应头。浏览器通常存储 cookie 并将其与Cookie HTTP 标头内的同一服务器的请求一起发送。您可以指定不应发送 cookie 的过期日期或时间段。您还可以对特定域和路径设置附加限制,以限制 cookie 的发送位置。

Set-Cookie和Header Cookie

HTTP 响应(Response)标头(Header)的Set-Cookie作用:从服务器发送cookie到用户代理。
一个简单的 cookie 设置如下:

Set-Cookie: <cookie-name>=<cookie-value>

这指示服务器发送标头告诉客户端存储一对cookie:

HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

然后,对于服务器的每个后续请求,浏览器都会使用标头将所有先前存储的 cookie 带回服务器Cookie。

GET /sample_page.html HTTP/2.0
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry

限制访问 Cookie

有两种方法可以确保 Cookie 被安全发送,并且不会被意外的参与者或脚本访问:Secure 属性和 HttpOnly 属性。

标记为 Secure 的 Cookie 只应通过被 HTTPS 协议加密过的请求发送给服务端。它永远不会使用不安全的 HTTP 发送(本地主机除外),这意味着中间人攻击者无法轻松访问它。不安全的站点(在 URL 中带有 http:)无法使用 Secure 属性设置 cookie。但是,Secure 不会阻止对 cookie 中敏感信息的访问。例如,有权访问客户端硬盘(或,如果未设置 HttpOnly 属性,则为 JavaScript)的人可以读取和修改它。

JavaScript Document.cookie API 无法访问带有 HttpOnly 属性的 cookie;此类 Cookie 仅作用于服务器。例如,持久化服务器端会话的 Cookie 不需要对 JavaScript 可用,而应具有 HttpOnly 属性。此预防措施有助于缓解跨站点脚本(XSS) (en-US)攻击。

2、Cookie 的生命周期

cookie 的生命周期可以通过两种方式定义:

1、当前会话结束时:会删除会话cookie。(浏览器定义“当前会话”何时结束,一些浏览器在重启时使用会话恢复。这可能会导致会话 cookie 无限期地持续)
2、永久cookie:在Expires属性指定的日期或属性指定的一段时间后删除Max-Age。

例如:

Set-Cookie: id=a3fWa; Expires=Thu, 31 Oct 2021 07:28:00 GMT;

注意:
1、当您设置Expires日期和时间时,它们与设置 cookie 的客户端相关,而不是服务器。
2、要删除Cookie,需要将Max-Age设置为0,并且将Cookie的值设置为null。不要将Max-Age指令值设置为-1负数。否则,浏览器会将其视为会话cookie。
3、如果您的站点对用户进行身份验证,它应该重新生成并重新发送会话cookie,即使是已经存在的,只要用户进行身份验证。这种方法有助于防止会话固定攻击,第三方可以重用用户的会话。

3、限制对 cookie 的访问

您可以通过以下两种方式之一确保 cookie 安全发送,并且不会被非预期方或脚本访问:
1、Secure属性
2、HttpOnly属性。

带有该Secure属性的 cookie 仅通过 HTTPS 协议通过加密请求发送到服务器。它永远不会使用不安全的 HTTP发送(本地主机(localhost)除外),这意味着中间人攻击者无法轻松访问它。不安全的站点(http:在 URL 中带有)无法使用该Secure属性设置 cookie。但是,不要假设这会Secure阻止对 cookie 中敏感信息的所有访问。例如,有权访问客户端硬盘(或 JavaScript,如果HttpOnly未设置该属性)的人可以读取和修改信息。

JavaScript API HttpOnly:无法访问具有该属性的 cookie ;
Document.cookie它只发送到服务器。
例如,持续存在于服务器端会话中的 cookie 不需要对 JavaScript 可用,并且应该具有该HttpOnly属性。这种预防措施有助于缓解跨站点脚本 ( XSS ) 攻击。

这是一个例子:

Set-Cookie: id=a3fWa; Expires=Thu, 21 Oct 2021 07:28:00 GMT; Secure; HttpOnly

4、定义 cookie 的发送位置

Domain和Path属性定义了 cookie的范围:cookie 应该发送到哪些 URL。

4.1 Domain属性

Domain属性指定哪些主机可以接收 cookie。如果未指定,则该属性默认为设置 cookie 的同一主机,不包括 subdomains。
如果指定Domain 则始终包含子域。因此,指定Domain比省略它的限制要小。但是,当子域需要共享有关用户的信息时,它会很有帮助。

例如,如果您设置Domain=mozilla.org,则 cookie 可用于子域,如developer.mozilla.org.

4.2 Path属性

Path属性指示在请求的 URL 中必须存在的 URL 路径,以便发送Cookie标头。( %x2F"/") 字符被视为目录分隔符,子目录也匹配。
例如,如果您设置Path=/docs,则这些请求路径匹配:

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

但是这些请求路径不会:

/
/docsets
/fr/docs

4.3 SameSite属性

SameSite属性允许服务器指定是否何时通过跨站点请求发送 cookie(其中站点由可注册域和方案定义:http 或 https)。这提供了一些针对跨站点请求伪造攻击 ( CSRF ) 的保护。它需要三个可能的值:Strict、Lax和None。

使用Strict时,cookie 只会发送到它的来源站点。
Lax类似,除了当用户导航到 cookie 的源站点时发送 cookie。例如,通过跟踪来自外部站点的链接。
None指定在发起请求和跨站点请求时都发送 cookie,但仅在安全上下文中(即,如果还必须设置SameSite=None该属性)。

注意:如果未设置SameSite属性,则 cookie 默认被视为Lax.

例子:如:网站a.com有cookie:name=Justin,samesite=xxx,网站b.com无cookie

  • 1、当xxx=strict,b.com访问a.com的接口时,get和post请求都不会把a.com的cookie带到a的接口
  • 2、当xxx=lax,b.com访问a.com的接口时,get会把a.com的cookie带到a的接口,post不会
  • 3、当xxx=none,b.com访问a.com的接口时,get和post请求都会把a.com的cookie带到a的接口

    Set-Cookie: mykey=myvalue; SameSite=Strict|Lax|None

注意:如果b.com是a.com的子域,如:b.com=api.a.com的话,不管samesite等于啥,都会把a.com的cookie带过去的

问题

介绍完Cookie之后,我们假设我们现在有个前后台分离的项目,前端地址是:www.baidu.com,后台api地址是:api.baidu.com和api.bilibili.com,现在我们来分析讲下面几个问题:

1、跨域前后台设置问题
2、跨域Cookie不能携带问题
3、Cookie如何如何避免XSS攻击和CSRF攻击

1、跨域前后台设置问题

如果想让前端访问后台两个api地址我们需要设置如下代码,

前端(以axios为例):

axios.defaults.withCredentials = true

后台(以spring cloud gateway为例)

spring:
  cloud:
    loadbalancer.ribbon.enabled: false
    gateway:
      globalcors:
        #add-to-simple-url-handler-mapping: true
        cors-configurations:
          '[/**]':
            allowedHeaders: "*"
            allowCredentials: true
            allowedOrigins: 
              - "https://api.baidu.com"
              - "https://api.bilibili.com"
            allowedMethods: "*"
      default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials

2、跨域Cookie不能携带问题

这里就有意思了,因为我们前端的地址是www.baidu.com,简称A,后台api有两个地址:api.baidu.com,简称B和api.bilibili.com,简称C,当我们通过A请求B的接口的时候,cookie会自动带上,因为他们是属于同源不同域,所以你在A下设置的cookie在请求B时也会带上,而当A请求C时就带不了了,明显两个不同源也不同域,所以无法带上,如果真要带的话,只有当A请求C时会把C的cookie带给C,而不能把A的cookie带给C,所以现在你知道该怎么做了吧!

3、Cookie如何避免XSS攻击和CSRF攻击

XSS介绍:
(Cross Site Script )攻击全称为跨站脚本攻击,xss攻击通常指的是利用网页开发留下的漏洞,通过巧妙的方法注入恶意的指令代码到网页上,使用户加载并执行恶意制造的网页程序。这些恶意网页程序通常是JavaScript代码

XSS解决:
使用Cookie的HttpOnly属性
严格来说,HttpOnly并非是为了对抗XSS-HttpOnly解决的是XSS后的Cookie劫持攻击。前面说了XSS可能会窃取用户的Cookie,然后就直接登录了该用户的账户,但是如果Cookie设置了HttpOnly,则这种攻击会失败,因为JavaScript读取不到Cookie的值。

CSRF介绍:
CSRF攻击的全称是跨站请求伪造( cross site request forgery),是一种对网站的恶意利用。简单点讲就是,恶意网站(攻击者)盗用了你的身份,以你的名义向信任网站发送恶意请求。 CRSF能做的事情包括利用你的身份发邮件、发短信、进行交易转账等,甚至盗取你的账号。

CSRF 攻击的三个必要条件:
目标站点一定要有 CSRF 漏洞
用户要登录过目标站点,并且在浏览器上保持有该站点的登录状态
需要用户打开一个第三方站点,可以是黑客的站点,也可以是一些论坛

CSRF 攻击不会往页面注入恶意脚本,而是找服务器的漏洞,因此黑客是无法通过 CSRF 攻击来获取用户页面数据的,对于 CSRF 攻击,主要的防护手段是提升服务器的安全性。

CSRF解决:
如果是从第三方站点发起的请求,那么需要浏览器禁止发送某些关键 Cookie 数据到服务器;
如果是同一个站点发起的请求,那么就需要保证 Cookie 数据正常发送。
而 Cookie 中的 SameSite 属性正是为了解决这个问题的。

在 HTTP 响应头中,通过 set-cookie 字段设置 Cookie 时,可以带上 SameSite 选项。

总结

1、cookie是所有前端开发人员必须要面对的知识点,大家一定要把原理弄清楚,这样在实际开发中遇到跨域还是xss、csrf攻击防范的话都能够有的放矢

引用

使用 HTTP cookie
浏览器原理 33 # CSRF攻击:为什么Cookie中有SameSite属性?
【信息安全】面试常问CSRF、cookie、session和token
浏览器跨域请求成功了,但是cookie 没有带过去,求解?


Awbeci
3.1k 声望213 粉丝

Awbeci


引用和评论

0 条评论