域名的构成、同站、跨站以及缓存表现

445 阅读13分钟

前言

今天来了解一下什么是跨站、什么是跨域、什么是同站。在这些不同的场景下cookie、session、localStorage...缓存如何表现、如何禁止三方cookie等。那么接下来将解析一下涉及到的知识点,篇幅可能有点长,希望对你有所帮助
image.png

域名构成

首先来了解一下域名的构成。域名由多个部分组成、阅读顺序从右到左每一部分都提供特定的信息

域名构成: 协议(schema)+子域名...(subdomain)+二级域名(second-level domain)+顶级域名(Top-level domain)+目录...(subdirectory)+参数(params)

image.png

  1. 子目录(subdirectory)
    子目录可以帮助用户和网络爬虫了解到位于网站的那个特定部分
    例如: tencent公司提供了游戏AI大模型云服务等。当我访问www.tencent.com/aigc时,子目录为aigc意味着其提供了aigc相关页面,在这个页面用户就可以了解到关于AI大模型、生成模型的推广

  2. TLD (Top-Level Domain,顶级域名)
    顶级域名指定您的组织在互联网上注册为哪种类型的实体 例如: .cn表示中国的商业实体或者.com适用于美国或者全球商业实体.edu用于教育或研究机构.org用于某些组织的机构等等。 顶级域名由这里可以查看具体数据

  3. SLD (second-level domain 二级域名)
    紧挨着TLD前面标签就被称为二级域名(SLD)。一个域名可以有多个标签没有强制规定3标签(存在四级、五级...域名)。
    二级域名SLD是网站的名称,用于告诉用户当前正在访问那个品牌、公司...的网站
    例如: baidu.com就知道访问的是百度公司旗下的网站、 tencent.com就知道访问的是腾讯公司旗下的网站

  4. 子域名(subdomain)
    二级域名就像一栋大厦,那么子域名就像大厦里面的房间号 。子域名理解某个公司给你提供的具体服务
    例如: 一般情况下公司官网域名为www.baidu.com、云服务的网站域名为cloud.baidu.com、api接口服务器的域名为api.baidu.com等。通过查看子域名可以知道具体的内容服务类型

  5. 协议(schema)
    用于告诉网络服务器访问网站上的页面时所采用的是哪种协议
    例如: HTTPS(即超文本传输​​安全协议)、ws(websocket长链接协议)、mailto:// (电子邮箱协议)

同源策略(SOP)

web浏览器中,如果两个URL的协议域名端口保持一致,则这个两个URL属于同源否则属于非同源即为跨域。可以防止脚本和其他web资源跨不同源来访问和操作数据。

接下来以http://www.aklcown.com链接为例子:

  • 协议:http
  • 域名:www.aklcown.com
  • 端口:443 (https默认443,http默认80)
URL是否同源理由
http://www.aklcown.com/index.html只有路径不同
https://www.aklcown.com协议不同
http://www.aklcown.com:81端口不同(http:// 默认端口是 80)
http://www.ak.com域名不同

同源策略限制

  1. XMLHttpRequest: 禁止使用XHM发送不同源服务器HTTP请求,即不能发送跨域ajax请求(防止CSRF攻击)
  2. 本地缓存: cookie、localStorage、IndexDB受到同源策略的限制
  3. DOM操作: iframe父子窗口不是同源的话,在访问彼此的DOM读取数据收到同源显示无法访问
  4. 子域名限制:SOP将子域名视为单独的源因此除非建立跨域权限否则父子域之间是无法共享资源的(sub.aklcown.com无法访问aklcown.com的资源)

PS: 可以通过一些手段进行规避。例如iframe的postmessage、跨域权限设置document.domain、服务端配置Access-Control-Allow-Origin..

为什么需要同源策略

同源策略是 Web 浏览器实施的重要安全机制,用于保护用户数据并防止未经授权的访问

接下来看一下前端经典面试最常见的CSRFXSS安全问题

  1. 跨站点请求防伪(CSRF): CSRF攻击诱导用户在web程序上执行非预期的操作。

案例: 一个小破站有一个弹窗,你不小心点击了弹窗,弹窗可能会执行招商银行转账的请求。在这之前你使用web浏览器登录过招商银行那么此时你本地的浏览器保存了招商身份认证信息的cookie。那么当cookie不受限制与同源策略的话,弹窗执行网络请求也将携带身份认证信息的cookie从而导致招商系统认定为你是本人操作
image.png

  1. 跨站点脚本攻击(XSS): 当黑客将恶意脚本注入到受信任的网站时就会发生XSS攻击,从而窃取用户信息或者篡改网页内容。(iframe就存在同源限制,对于非同源父子窗口是没有办法捕获到彼此的dom事件...。可以通过postmessage来通信)
    image.png

跨域

同源即为跨域

跨域常见的场景有如下两种:

  1. http网络请求跨域
    浏览器会默认检测请求是否跨域,具体跨域原理这里不再阐述可以看这篇文章CORS跨域原理解析
    image.png image.png 当我在NestJs服务开启app.enableCors();运行跨域时,响应体存在Access-Control-Allow-Origin浏览器判定允许跨域请求 image.png
  2. iframe跨域
    创建3个html文件分别为1.html2.html3.html1.html3.html不是同源情况、2.html3.html属于同源情况
<iframe src="http://127.0.0.1:5500/3.html" frameborder="0"></iframe>
<script>
  (function () {
    const iframe = document.getElementsByTagName("iframe")[0];
    iframe.onload = function () {
      console.log(iframe.contentWindow.document.getElementById("ak"));
    };
  })();
</script>

1.html是不允许获取到3.htmldom元素浏览器会报错异常。 我们可以通过postmessage来进行1 <=> 3之间的通信来实现我们需要的操作 image.png 2.html是允许获取到3.htmldom元素 image.png
PS: 不同源的iframe也无法监听iframe的事件机制,最近在做weboffice其使用了iframe做了沙箱导致我在外层没办法监听里层的keypress事件...

同站

同站需要满足如下条件

  1. 域名之间具有相同的 SLD(二级域名)+TLD(有效顶级域名)
  2. 有效顶级域名顶级域名是不一样的概念,例如 github.io 是一个有效顶级域名,如果将 .io 视为有效顶级域名,那么 https://ziyi2.github.iohttps://xxholly32.github.io 将被浏览器视为同站,但显然它们是两个不同的开发者创建的博客站点。有效顶级域名有一个维护列表,具体可以查看 publicsuffix/list

举个例子: http://www.aklcown.com/aigc

URL描述是否同站是否同源
http://www.aklcown.comSLD+TLD相同
http://www.aklcown.com:81SLD+TLD相同
http://sub.aklcown.comSLD+TLD相同
https://www.aklcown.comSLD+TLD相同
http://www.aklcown.topTLD不同相同
http://www.aklcown1.comSLD不同相同

跨站

同站即为跨站。也就是两个域名之间SLD(二级域名)+TLD(顶级域名)不一致

本地模拟环境

因为要查看缓存不同域名情况下的表现,因此我们需要在本地模拟一个多域名的测试环境。

那么如何在本地搭建多域名环境呢?

  1. 首先下载SwitchHosts用于改变本地的host文件。
    当我们在浏览器输入域名时会先经过本地的host文件来查看是否存在域名和ip地址映射,因此当我们输入www.ak.com实际访问的ip地址为127.0.0.1。具体可以自行查找浏览器从输入到渲染所要经过的过程 image.png
  2. 分别创建ak.htmlakclown.htmlsub.ak.html对应不同域名访问
    快速启动本地静态文件服务,可以采用Vscode默认的go live。你也可以使用http-server image.png

完成如上两步骤我们就完成了模拟多域名环境搭建,接下来就来看看web相关缓存的具体表现

缓存的表现

HTTP是属于无状态的因此我们需要通过缓存的手段保持一些用户状态。以下涉及到到的服务端采用NestJS构建

cookie

HTTP Cookie: (也叫 Web Cookie 或浏览器 Cookie)是服务器发送用户浏览器并保存在本地的一小块数据。浏览器会存储 cookie 并在下次向同一服务器再发起请求时携带并发送到服务器上

这里我使用NestJs构建后端服务器,通过Nest服务来设置cookie

前后端部署在同源下:

当点击设置cookie按钮之后/set-cookie响应头会携带set-cookie字段并且在浏览器上设置cookie的键值对
/set-cookie的响应头
image.png
浏览器的cookie区域
image.png /get-cookie的请求头,会自动携带cookie到后端
image.png
通过NEST设置基础的cookie,在同源下运行一切正常。 image.png

前后端域名在同站跨站下:

一般情况下前后端服务不可能部署到同一个域名、端口、协议下的,毕竟前后端分离。如果还是按照上面基础的cookie设置是没有办法给浏览器端设置到同站跨站的cookie,

  1. 跨域是如何如何设置cookie image.png 跨域cookie通过如下两步骤设置:
    1. 前端: 如果是axios请求添加withCredentials: true参数,如何是fetch请求诶添加credentials:include参数
    2. 后端: 配置Access-Control-Allow-Origin需要具体的域名不能是*。配置access-control-allow-credentials为true
app.enableCors({
    origin: [
      'http://www.ak.com:5500',
      'http://sub.ak.com:5500',
      'http://www.akclown.com:5500',
      'http://api.ak.com:3000',
    ],
    credentials: true,
});
  1. 知道了如何设置跨域的cookie之后,先来了解一下cookie相关的domainsameSite关键字

    1. domain: 指定cookie可以送达的主机(提供API服务的主机域名,不是客户端域名)。其值只能设置当前域名或者更高级别的域名。设置域名将会使 cookie 指定的域名及其所有子域名可用

      ps: 即使 sameSite: 'strict' 限制了 cookie 的发送范围,设置了 domain 属性后,子域名仍然可以访问这个 cookie

    2. sameSite: 控制cookie是否同站(一方cookie)跨站(三方cookie)请求一起发送

描述一方cookie(同站)三方cookie(跨站)
Strict浏览器仅对同一站点发送cookie,即请求来自设置 cookie 的站点
Lax (默认值)浏览器对符合同站域名发送cookie部分会携带cookie
None浏览器在跨站同站请求中均会发送cookie,必须设置 Secure

domain的设置是针对服务器API地址的、而sameSite的设置是针对同站(一方cookie)跨站(三方cookie)

  1. 下面来看看同站的情况,先新增一个api.ak.com域名作为后端服务的域名 image.png
    • 首先来看一下如下: 设置domain的五种情况 image.pnghttp://www.ak.com/域名下调用set-cookie请求, 可以从response header看出cookiedomain只能设置为当前域名更高级别的域名 image.png image.png 接下来看看当前api域名当前api的子域名携带cookie的情况
    1. http://www.ak.com/发送api.ak.com/get-cookie请求,可以看到username\age\id都会携带上
    2. http://www.ak.com/发送sub.api.ak.com/hello请求,可以看到age\id会携带上,而username没有被携带上,这就很好的证明了设置了domian对指定的域名及其所有子域名可用
    3. http://sub.ak.com/发送api.ak.com/get-cookie请求,可以看到username\age\id都会携带上(浏览器默认行为,也许同站是被共享cookie作用域的 目前没查到相关资料,有了解的大佬指点一下,thanks) image.png
    • 设置sameSite三种情况
      因为sameSite值为node时需要同步设置secure为true,而secure只在https中才能生效。因此我们先来使用NestJs模拟一个HTTPS环境
生成SSL证书
    1. 生成私钥:
    openssl genrsa -out key.pem 2048
    2. 生成证书签名请求(CSR):
    openssl req -new -key key.pem -out csr.pem
    3. 生成自签名证书:
    openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out cert.pem
    
Nest服务中:
  const httpsOptions = {
    key: fs.readFileSync(path.join(__dirname, '../certificate/key.pem')),
    cert: fs.readFileSync(path.join(__dirname, '../certificate/cert.pem')),
  };
  
  const app = await NestFactory.create<NestExpressApplication>(AppModule, {
    httpsOptions,
  });

通过如上配置,然后在浏览器中访问https://api.ak.com:3000/hello 浏览器会警告你这是一个不受信任的自签名证书,选择忽略警告即可。

接口set-same-site-cookiehttps://www.ak.com:5500/触发设置cookie。接口set-other-cookiehttps://www.akclown.com:5500/触发设置cookie image.png 经过上述配置,可以在控制面板下看到如下cookie: image.png 当我在https://www.akclown.com:5500域名下请求https://api.ak.com:3000接口(跨站了)。可以看到设置cookie属性为{sameSite: 'none', secure: true}的id会被携带上,其余usernameage不会被携带到www.akclown.com服务上 image.png 浏览器需要开启三方cookie image.png
总结: domain作用于同站(接口域名与客户端域名相同的SLD+TLD+schema)的情况下, sameSite作用于跨站(接口域名与客户端域名SLD+TLD+schema有一个不满足)的情况下。

session

使用Nest搭建session环境,可以从如下配置看到session可以配置cookie属性。session的具体在客户端是否携带对应的session cookie取决于这个cookie配置,表现跟cookie章节一样 image.png image.png 客户端设置与获取 image.png image.png

总结: session在同站跨站如何表现,取决于NestJS在设置的session时传入的cookie参数。其值的表现跟cookie章节一致

补充: 当接口域名前端域名跨站时,只有samesite:none才能设置成功 image.png

localStorage

如下图可以看出localStorage受到同源策略的限制的,即使是(同站)子域名也不可以访问 image.png

sessionStorage

sessionStoragelocalStorage一样都是受到同源策略的限制。只能同源才可以访问数据

三方cookie

有时候我们会很好奇,为什么在抖音、小红书看了某些商品之后打开京东、淘宝就会给你推荐对应的商品?

原因就是三方cookie搞的鬼, 那么什么是一方cookie什么是三方cookie呢?

举个例子:
以淘宝为例, 当我们访问https://www.taobao.com/网站时会请求大量https://h5api.m.taobao.com/...接口其通过set-cookie设置大量的cookie。因为请求域当前网站域名同站的,所以这种cookie属于一方cookie image.png 但网站不一定只是调用同站的域名。例如www.taobao.com网站就调用了很多www.tmall.com域名下的接口,这些跨站的域名接口也通过set-cookie设置大量的cookie。因为请求域当前网站域名是跨站的,所以这种cookie属于三方cookie image.png 上面只是涉及到如何写入三方cookie, 那么具体是如何通过三方cookie进行用户信息采集呢? 这里有所解释,不再阐述

关于三方cookie的更多内容点击这里查阅

跨域共享实现SSO

TODO:施工中...

总结

本文涉及的Demo源码

参考文献:

CORS跨域原理解析
跨域是如何如何设置cookie
HTTP Cookie 的运行机制
Analyzing Impact of WWW Subdomain on Cookie Security
附带身份凭证的请求
CORS protocol and credentials
Cookie策略真是越来越复杂了
什么是域名
HTTP cookie
浏览器专题系列 - 跨域与跨站
Parts of a URL: A Short Guide
Understanding SameSite cookies
快速了解第三方 Cookie 是如何跟踪你的行为