浏览器知识

基础知识

线程和进程

进程(process)和线程(thread)是操作系统的基本概念

进程是 CPU 资源分配的最小单位(是能拥有资源和独立运行的最小单位)
线程是 CPU 调度的最小单位(是建立在进程基础上的一次程序运行单位)

一个进程就是一个程序的运行实例:启动一个程序时,操作系统会为该程序创建一块内存,用来存放代码、运行中的数据和一个执行任务的主线程,我们把这样的一个运行环境叫进程

线程是进程内的一个执行单元:线程是不能单独存在的,是依附于进程并由进程来启动和管理的

进程和线程的关系特点

  • 进程是拥有资源的基本单位;线程是调度和分配的基本单位(是进程内的一个执行单元,也是进程内的可调度实体)
  • 进程之间相互隔离,互不干扰
  • 一个进程中可以并发执行多个线程
  • 一个线程只能隶属于一个进程,而一个进程是可以拥有多个线程的(但至少有一个主线程)
  • 同一进程的所有线程共享该进程的所有数据
  • 进程中的任意一线程执行出错,都会导致整个进程的崩溃
  • 当一个进程关闭之后,操作系统会回收进程所占用的内存

Chrome 打开一个页面会有几个进程?

最新的 Chrome 多进程架构图

Chrome 多进程架构图

  • 浏览器主进程:负责界面显示、用户交互、子进程管理,同时提供存储等功能

  • 渲染进程

    :负责将

    1
    HTML
    1
    CSS

    和

    1
    JavaScript

    转换为用户可以与之交互的网页

    • 排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中
    • 默认情况下 Chrome 会为每个 Tab 标签创建一个渲染进程
    • 出于安全考虑渲染进程都是运行在沙箱模式下
  • GPU 进程:负责网页、Chrome 的 UI 界面的绘制

  • 网络进程:负责页面的网络资源加载(之前是作为一个模块运行在浏览器进程)

  • 插件进程:负责插件的运行(因为插件易崩溃所以需要通过插件进程来隔离,以保证插件崩溃不会对浏览器和页面造成影响)

Chrome 架构:仅仅打开了 1 个页面,为什么有 4 个进程?—— 浏览器工作原理与实践

跨域

跨域的原因 —— 浏览器的同源策略

同源策略是浏览器一个重要的安全策略,它用于限制一个 origin 的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介

同源的定义是两个 URL 的 协议、域名(子域名 + 主域名)、端口号 都相同,否则就会出现跨域

同源策略的限制范围

  1. 限制跨源网络访问: AJAX 请求不能发送
  2. 限制跨源脚本 API 访问: DOM 无法获得
  3. 限制跨源数据存储访问: Cookie LocalStorage 和 IndexDB 无法读取

一般常说的跨域指网络跨域

常用的跨域解决方案

常用的跨域解决方案

  1. CORS
  2. JSONP
  3. Nginx 反向代理
  4. WebSocket
  5. postMessage
  6. document.domain

CORS 跨源资源共享

CORS (跨源资源共享) 是 HTTP 的一部分,它允许浏览器向跨源服务器发出 XMLHttpRequest 请求,从而解决了 AJAX 只能同源使用的限制。

CORS 需要浏览器和服务器同时支持,目前所有浏览器均已支持,只需服务器配置即可使用

浏览器将 CORS 请求分成两类: 简单请求和非简单请求

简单请求

简单请求必须同时满足以下条件

日常开发只会关注前两点

  • 请求方法是以下三种方法之一

    • HEAD
    • GET
    • POST
  • 只使用了如下的安全首部字段,不得人为设置其他首部字段

    • Accept

    • Accept-Language

    • Content-Language

    • Content-Type
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17

      仅限以下三种

      - `application/x-www-form-urlencoded`
      - `multipart/form-data`
      - `text/plain`

      - 请求中的任意 `XMLHttpRequestUpload` 对象均没有注册任何事件监听器(使用 `XMLHttpRequest.upload` 属性访问`XMLHttpRequestUpload` 对象)

      - 请求中没有使用 `ReadableStream` 对象

      ##### 简单请求基本流程

      1. 浏览器会直接发出 `CORS` 请求并在请求头信息之中增加一个 `Origin` 字段(用来说明本次请求来自哪个源(协议 + 域名 + 端口))

      2. 服务器判断

      Origin
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91

      字段决定是否同意这次请求

      1. 通过请求会在响应头增加 `CORS` 相关的字段(以`Access-Control-`开头)
      2. 拒绝请求时不会增加 `CORS` 相关的字段,浏览器会抛出异常

      简单请求响应头中的 CORS 字段

      - `Access-Control-Allow-Origin`: 只能是 `*`(接受任意域名的请求)或者是请求时 `Origin` 字段的值
      - `Access-Control-Allow-Credentials`(可选): 是一个布尔值,表示是否允许发送 `Cookie`
      - `Access-Control-Expose-Headers`(可选): `CORS` 请求时 `XMLHttpRequest` 对象的 `getResponseHeader()` 方法只能拿到 6 个基本字段:`Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma`。如果想拿到其他字段就必须在 `Access-Control-Expose-Headers` 里面指定

      CORS 中的 Cookie 设置

      `CORS` 请求默认不发送 `Cookie`,如果需要发送需要满足如下条件

      - 服务器必须设置 `Access-Control-Allow-Credentials: true`
      - `Access-Control-Allow-Origin` 字段不能为 `*`
      - `AJAX` 请求的配置项需设置 `withCredentials = true`

      #### 非简单请求

      非简单请求是那种对服务器有特殊要求的请求,如请求方法是 `PUT` 或 `DELETE`,或者 `Content-Type` 字段的类型是 `application/json`。
      非简单请求会在正式通信之前增加一次 `HTTP` 查询请求,称为**预检请求**,用于获取服务器是否允许该实际请求,同时避免跨域请求对服务器的用户数据产生预期之外的影响

      预检请求

      预检请求用的请求方法是 `OPTIONS` 表示这个请求是用来询问的

      - 在预检请求请求头信息里会包含如下字段
      - `Origin`: 表示本次请求来自哪个源
      - `Access-Control-Request-Method`: 用于列出浏览器的 `CORS` 请求会用到哪些 `HTTP` 方法
      - `Access-Control-Request-Headers`(可选): 指定浏览器 `CORS` 请求会额外发送的头信息字段
      - 服务器通过后会在预检请求响应头中设置如下字段
      - `Access-Control-Allow-Origin`
      - `Access-Control-Allow-Credentials`(可选)
      - `Access-Control-Allow-Methods`: 表示服务器支持的所有跨域请求的方法(为了避免多次预检请求)
      - `Access-Control-Allow-Headers`: 表示服务器支持的所有头信息字段,不限于浏览器在预检中请求的字段
      - `Access-Control-Max-Age`(可选): 用来指定本次预检请求的有效期单位为秒,在有效期内将不发出另一条预检请求

      一旦服务器通过了预检请求,以后每次浏览器正常的 `CORS` 请求,就都跟简单请求一样会有一个 `Origin` 头信息字段。服务器的回应也都会有一个 `Access-Control-Allow-Origin` 头信息字段

      <details class="details custom-block" style="box-sizing: border-box; border-width: 1px; border-style: solid; border-color: var(--vp-custom-block-details-border); border-image: initial; border-radius: 8px; padding: 16px 16px 8px; line-height: 24px; font-size: var(--vp-custom-block-font-size); color: var(--vp-custom-block-details-text); background-color: var(--vp-custom-block-details-bg); margin: 16px 0px;"><summary style="box-sizing: border-box; touch-action: manipulation; margin: 0px 0px 8px; font-weight: 700; cursor: pointer;">CORS 请求过程</summary><p style="box-sizing: border-box; margin: 8px 0px; overflow-wrap: break-word; line-height: 24px;"><img src="https://cdn.jsdelivr.net/gh/dont-sleep-so-late/CDN/images/20230913230220.png" alt="CORS 请求过程" class="medium-zoom-image" style="box-sizing: border-box; display: block; max-width: 100%; height: auto; cursor: zoom-in; transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) 0s !important;"></p></details>

      ------

      相关资料

      [跨域资源共享 CORS 详解](http://www.ruanyifeng.com/blog/2016/04/cors.html)

      ### JSONP

      `JSONP` 是利用 `<script>` 标签没有跨域限制的漏洞,当前源可以得到从其他来源动态产生的 `JSON` 数据

      **`JSONP` 请求过程流程**

      1. 前端定义一个解析的回调函数
      2. 创建 `script` 标签,其 `src` 指向接口地址并拼接好参数和回调函数名
      3. 后端处理数据并将其拼接到前端传入的回调函数中(拼接好的数据必须是一个合法的 `JavaScript` 脚本 )
      4. 浏览器执行后端返回的 `JavaScript` 脚本代码(调用定义好的回调函数)并删除刚创建的 `script` 标签

      ```js
      function normalizeParams(params) {
      if (!params) {
      return ''
      }
      return Object.keys(params)
      .map((key) => `${key}=${params[key]}`)
      .join('&')
      }

      function jsonp(url, params) {
      return new Promise((resolve) => {
      const callback = `jsonp_${Date.now()}`
      window[callback] = function (data) {
      resolve(data)
      document.body.removeChild(scriptEle)
      }
      params.cb = callback
      const scriptEle = document.createElement('script')
      scriptEle.src = `${url}${url.includes('?') ? '&' : '?'}${normalizeParams(params)}`
      document.body.appendChild(scriptEle)
      })
      }

      jsonp('https://www.baidu.com/sugrec', {
      prod: 'pc',
      wd: '跨域'
      }).then((res) => {
      console.log(res)
      })

JSONP 跨域优缺点

  • 优点: 实现简单,兼容性好
  • 缺点
    • 只支持 GET 请求
    • 容易遭受 XSS 攻击

了解更多跨域解决方案请点击 —— 10 种跨域解决方案

浏览器缓存机制

    1. 浏览器在发送请求前先判断是否命中强缓存
    • 命中则不发送请求直接使用缓存,否则进行下一步
    1. 浏览器发送请求后会由服务器判断是否命中协商缓存
    • 命中则从缓存获取资源,否则进行下一步
    1. 浏览器直接使用服务器返回的资源并更新缓存

强缓存(200 OK)

  • Expires
    
    1
    2
    3
    4
    5
    6
    7



    是服务器告诉浏览器的缓存过期时间(值为



    GMT
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11



    时间,即格林尼治时间)

    - `HTTP1.0` 的产物
    - 受本地时间影响
    - 设置的值为 `max-age=xxx`(xxx 是 秒)

    - ```
    Cache-Control
    用于控制缓存的行为 - 是 `HTTP1.1` 的产物 - 取值 - `public`:允许被客户端和代理服务器缓存 - `private`:只允许被客户端缓存(默认值) - `no-cache`:允许被客户端和代理服务器缓存,但在使用缓存时需要经过协商缓存来验证决定 - `no-store`:所有内容都不会被缓存,即不使用强制缓存也不使用协商缓存每次请求都会下载完整的资源 - `maxage=xxx`:设置客户端和代理服务器的缓存时间,表示缓存内容将在 xxx 秒后失效 - `s-maxage=xxx`:设置代理服务器的缓存时间(优先级比 `max-age` 高)

Cache-Control 注意点

no-cache 名字存在误导,其并不是不缓存数据,只是在使用缓存时需要经过协商缓存来验证决定
max-age=0 和 no-cache 效果一致

缓存位置

  • 内存缓存(memory cache)
    • 快速读取(内存缓存将编译解析后的文件,直接存入该进程的内存中,占据该进程一定的内存资源,以方便下次运行使用时的快速读取)
    • 进程关闭时数据会被清除
    • 不请求网络资源,资源存在内存中一般 JS 和图片文件会存入内存
    • 状态码:200(from memory cache)
  • 硬盘缓存(disk cache)
    • 写入硬盘文件进行 I/O 操作
    • 进程关闭时数据不会被清除
    • 速度比 memory cache 慢
    • 不请求网络资源,资源存在磁盘中一般非脚本会存在磁盘中,如 css
    • 状态码:200(from disk cache)
  • 代理服务器缓存(server worker)
    • 可以拦截处理页面的所有网络请求
    • 仅 HTTPS 下可用、存在兼容问题
    • 状态码:200(from service worker)

协商缓存(304 Not Modified)

Last-Modified 和 If-Modified-Since

Last-Modified 表示资源的最后修改时间,值为 GMT 格式时间字符串,精确到秒

  • 浏览器第一次请求时,服务器会在响应头中返回请求资源的上次更新时间 Last-Modified

  • 当浏览器再次请求时,会在请求头中携带 If-Modified-Since 值为上次请求返回的 Last-Modified

  • 服务器收到请求后,会根据请求头中的

    1
    If-Modified-Since

    和该资源在服务器的最后被修改时间做对比

    • 大于 If-Modified-Since 重新返回资源文件,状态码为 200
    • 小于 If-Modified-Since 资源无更新继续使用缓存文件,状态码为 304

Last-Modified 存在的问题

  • 时间精度为秒级会出现误差情况,对文件修改精度有严格要求的场景不能满足
  • 在集群服务器上各个服务器上的文件时间可能不同
  • 如果用旧文件覆盖新文件,因为时间更前浏览器不会请求旧文件
  • 编辑了文件但未修改,会导致缓存失效

ETag 和 If-None-Match

ETag 是服务器通过算法对资源内容计算出的一个唯一标识(文件 hash)其有强弱之分

  • 强

    1
    Etag
    • ETag: "<etag_value>"
    • 资源发生任何改变都会立刻更新
    • 难生成,利于比较
  • 弱

    1
    Etag

    (使用

    1
    W/

    标识)

    • ETag: W/"<etag_value>"
    • 只在资源发生本质变化时更新
    • 易生成,不利于比较
过程
  • 浏览器第一次请求时,服务器会在响应头中返回当前资源文件的一个唯一标识 ETag

  • 当浏览器再次请求时,会在请求头中携带 If-None-Match 值为上次请求返回的 ETag

  • 通过接收的

    1
    ETag

    和服务器重新生成的

    1
    ETag

    进行对比

    • 不一致 重新返回资源文件,状态码为 200
    • 一致 资源无更新继续使用缓存文件,状态码为 304

Last-Modified 和 Etag 对比

  • 精确度上:Etag 优于 Last-Modified
  • 性能上:Etag < Last-Modified 每次生成 ETag 都需要进行读写操作,而 Last-Modified 只需要读取操作
  • 优先级:服务器校验优先考虑 Etag(先判断 Etag 是否变化,如果 Etag 没有变化再判断 Last-Modified)

应用场景

强缓存 协商缓存
不常变化的文件 带 hash 值的 css js 图片 频繁变动的文件 html 文件

用户行为对缓存的影响

  • 地址栏输入
    • 查找 disk cache(磁盘缓存)中是否有匹配,有则使用缓存,没有则发送网络请求
  • 普通刷新(F5)
    • 因为浏览器 tab 标签并没有关闭,因此 memory cache (内存缓存)是可用的,会被优先使用,其次使用 disk cache(磁盘缓存)
    • 跳过强缓存规则,直接走协商缓存
  • 强制刷新(Ctrl + F5)
    • 浏览器不使用缓存,因此发送的请求头部均带有 Cache-control: no-cache (为了兼容还带了 Pragma: no-cache)服务器直接返回 200 和最新内容。
    • 跳过所有缓存规则

浏览器存储

Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能,Cookie 在存储时是以键值对的形式存在的

Cookie 主要用于以下三个方面:

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)

Cookie 的本职工作并非本地存储,而是“维持状态”,因当时并没有其它合适的存储办法而作为唯一的存储手段,所以会用其进行本地存储

  • 服务器生成,通过 http response header 中的 set-cookie
  • 在 JavaScript 中使用 document.cookie 进行读写
1
2
3
4
5
/* 读取 */
document.cookie

/* 写入 */
document.cookie = 'name=maomao'

Cookie 的缺点

  • Cookie 最大只能有 4KB 同时大多数浏览器对一个站点的 Cookie 个数也是有限制的
  • 同一个域名下的所有请求都会携带 Cookie 从而带来不必要的开销和安全问题

Web Storage

Web Storage是 HTML5 专门为浏览器存储而提供的数据存储机制,其大小限制为 5MB ~ 10MB (去查看当前浏览器下 Web Storage 的容量限制),数据仅保存在客户端不与服务器进行通信

Web Storage 提供了两种机制供我们使用

  • Local Storage(本地存储)
  • Session Storage(会话存储)

LocalStorage

  • 保存的数据长期存在
  • 在同源的所有标签页和窗口之间共享数据

SessionStorage

  • 数据只存在于当前浏览器的标签页
  • 在新标签或窗口打开一个页面时会复制顶级浏览会话的上下文作为新会话的上下文
    • 在当前标签中打开一个同域下的页面时会复制当前标签页中的 SessionStorage 数据
    • 复制的 SessionStorage 数据是独立的,不会相互影响(类似深拷贝)
  • 重新加载或恢复页面仍会保持原来的数据
  • 关闭对应浏览器标签或窗口后数据会被清除

API 使用

以 localStorage 为例

1
2
3
4
5
6
7
8
9
10
11
/* 存储数据 setItem() */
localStorage.setItem('name', 'maomao')

/* 读取数据 getItem() */
localStorage.getItem('name')

/* 删除指定数据 removeItem() */
localStorage.removeItem('name')

/* 清空数据 clear() */
localStorage.clear()

sessionStorage localStorage 和 cookie 的区别

  • 相同点
    • 都是在客户端保存数据
    • 存储数据的类型都是字符串
  • 不同点
    • 生命周期
      • Cookie: 可以设置失效时间(默认是关闭浏览器后失效)
      • localStorage: 除非被手动清除否则将会永久保存
      • sessionStorage: 仅在当前浏览器的标签页下有效,关闭标签或窗口后就会被清除
    • 数据大小
      • Cookie: 4KB
      • localStorage 和 sessionStorage: 5MB ~ 10MB
    • http 请求
      • Cookie: 每次都会携带在 HTTP 请求头中
      • localStorage 和 sessionStorage: 仅在客户储保存不会与服务器通信

IndexedDB

IndexedDB 是一个运行在浏览器上的非关系型数据库,用于在客户端存储大量结构化数据

IndexedDB 的特点

  • 存储空间大(一般来说不少于 250MB 甚至没有上限)
  • 支持存储二进制数据(ArrayBuffer 和 Blob)
  • 键值对储存
  • 同源限制
  • 执行的操作是异步执行,以免阻塞应用程序
  • 是一个事务型数据库系统

API 使用

打开/创建一个 IndexedDB 数据库,并指定数据库的版本号 (版本号只能为整数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const request = window.indexedDB.open('myDatabase', 1)
let db

// 成功回调
request.onsuccess = function (event) {
// 获取 indexedDB 实例
db = event.target.result
// 也可以使用 request.result 获取 indexedDB 实例
console.log('连接 IndexedDB 成功')
}

// 失败回调
request.onerror = function () {
console.log('连接 IndexedDB 失败')
}

创建一个对象仓库(类似于数据库中的表)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// upgradeneeded 事件会在初始化数据库或版本发生更新时被调用
request.onupgradeneeded = function (event) {
const db = event.target.result
// 创建对象仓库并指定主键
const objectStore = db.createObjectStore('userInfo', {
keyPath: 'id',
autoIncrement: false
})
console.log('创建对象仓库成功')

/**
* 定义存储对象的数据项
* 第一个参数是创建的索引名称,可以为空
* 第二个参数是索引使用的关键名称,可以为空
* 第三个参数是可选配置参数,可以不传,常用参数之一就是 unique ,表示该字段是否唯一,不能重复
*/
objectStore.createIndex('id', 'id', {
unique: true
})
objectStore.createIndex('name', 'name')
}

添加数据

1
2
3
4
5
6
7
// 创建事务指并定表格名称和读写权限
const transaction = db.transaction(['userInfo'], 'readwrite')
// 获取 Object Store 对象
const objectStore = transaction.objectStore('userInfo')

/* 添加数据 */
objectStore.add({ id: 1, name: 'test' })

获取数据

1
2
3
4
5
6
7
const transaction = db.transaction(['userInfo'], 'readonly')
const objectStore = transaction.objectStore('userInfo')

const objectStoreRequest = objectStore.get(1)
objectStoreRequest.onsuccess = function () {
console.log('获取数据', objectStoreRequest.result)
}

修改数据

1
2
3
4
5
6
7
8
9
const transaction = db.transaction(['userInfo'], 'readwrite')
const objectStore = transaction.objectStore('userInfo')

const objectStoreRequest = objectStore.get(1)
objectStoreRequest.onsuccess = function () {
const data = objectStoreRequest.result
data.name = 'maomao'
objectStore.put(data)
}

删除数据

1
2
3
4
5
6
7
const transaction = db.transaction(['userInfo'], 'readwrite')
const objectStore = transaction.objectStore('userInfo')

const objectStoreRequest = objectStore.delete(1)
objectStoreRequest.onsuccess = function () {
console.log('删除成功')
}

在日常开发中可以使用如下类库简化代码量

  • localForage 一个提供 name:value 的简单语法的客户端数据存储垫片,基于 IndexedDB 实现,并在不持支 IndexedDB 的浏览器中自动回退到 WebSQL 和 localStorage
  • Dexie.js 对 IndexedDB 的封装,通过提供更友好和简单语法进行快速的编码开发
  • PouchDB 对 IndexedDB 的封装,通过提供更友好和简单语法进行快速的编码开发

面试官:为什么说HTTPS比HTTP安全? HTTPS是如何保证安全的?

一、安全特性

在上篇文章中,我们了解到HTTP在通信过程中,存在以下问题:

  • 通信使用明文(不加密),内容可能被窃听
  • 不验证通信方的身份,因此有可能遭遇伪装

而HTTPS的出现正是解决这些问题,HTTPS是建立在SSL之上,其安全性由SSL来保证

在采用SSL后,HTTP就拥有了HTTPS的加密、证书和完整性保护这些功能

SSL(Secure Sockets Layer 安全套接字协议),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议

img

二、如何做

SSL 的实现这些功能主要依赖于三种手段:

  • 对称加密:采用协商的密钥对数据加密
  • 非对称加密:实现身份认证和密钥协商
  • 摘要算法:验证信息的完整性
  • 数字签名:身份验证

对称加密

对称加密指的是加密和解密使用的秘钥都是同一个,是对称的。只要保证了密钥的安全,那整个通信过程就可以说具有了机密性

img

非对称加密

非对称加密,存在两个秘钥,一个叫公钥,一个叫私钥。两个秘钥是不同的,公钥可以公开给任何人使用,私钥则需要保密

公钥和私钥都可以用来加密解密,但公钥加密后只能用私钥解 密,反过来,私钥加密后也只能用公钥解密

img

混合加密

在HTTPS通信过程中,采用的是对称加密+非对称加密,也就是混合加密

在对称加密中讲到,如果能够保证了密钥的安全,那整个通信过程就可以说具有了机密性

而HTTPS采用非对称加密解决秘钥交换的问题

具体做法是发送密文的一方使用对方的公钥进行加密处理“对称的密钥”,然后对方用自己的私钥解密拿到“对称的密钥”

img

这样可以确保交换的密钥是安全的前提下,使用对称加密方式进行通信

举个例子:

网站秘密保管私钥,在网上任意分发公钥,你想要登录网站只要用公钥加密就行了,密文只能由私钥持有者才能解密。而黑客因为没有私钥,所以就无法破解密文

上述的方法解决了数据加密,在网络传输过程中,数据有可能被篡改,并且黑客可以伪造身份发布公钥,如果你获取到假的公钥,那么混合加密也并无多大用处,你的数据扔被黑客解决

因此,在上述加密的基础上仍需加上完整性、身份验证的特性,来实现真正的安全,实现这一功能则是摘要算法

摘要算法

实现完整性的手段主要是摘要算法,也就是常说的散列函数、哈希函数

可以理解成一种特殊的压缩算法,它能够把任意长度的数据“压缩”成固定长度、而且独一无二的“摘要”字符串,就好像是给这段数据生成了一个数字“指纹”

img

摘要算法保证了“数字摘要”和原文是完全等价的。所以,我们只要在原文后附上它的摘要,就能够保证数据的完整性

比如,你发了条消息:“转账 1000 元”,然后再加上一个 SHA-2 的摘要。网站收到后也计算一下消息的摘要,把这两份“指纹”做个对比,如果一致,就说明消息是完整可信的,没有被修改

img

数字签名

数字签名能确定消息确实是由发送方签名并发出来的,因为别人假冒不了发送方的签名

原理其实很简单,就是用私钥加密,公钥解密

签名和公钥一样完全公开,任何人都可以获取。但这个签名只有用私钥对应的公钥才能解开,拿到摘要后,再比对原文验证完整性,就可以像签署文件一样证明消息确实是你发的

img

和消息本身一样,因为谁都可以发布公钥,我们还缺少防止黑客伪造公钥的手段,也就是说,怎么判断这个公钥就是你的公钥

这时候就需要一个第三方,就是证书验证机构

CA验证机构

数字证书认证机构处于客户端与服务器双方都可信赖的第三方机构的立场

CA 对公钥的签名认证要求包括序列号、用途、颁发者、有效时间等等,把这些打成一个包再签名,完整地证明公钥关联的各种信息,形成“数字证书”

流程如下图:

img

  • 服务器的运营人员向数字证书认证机构提出公开密钥的申请
  • 数字证书认证机构在判明提出申请者的身份之后,会对已申请的公开密钥做数字签名
  • 然后分配这个已签名的公开密钥,并将该公开密钥放入公钥证书后绑定在一起
  • 服务器会将这份由数字证书认证机构颁发的数字证书发送给客户端,以进行非对称加密方式通信

接到证书的客户端可使用数字证书认证机构的公开密钥,对那张证书上的数字签名进行验证,一旦验证通过,则证明:

  • 认证服务器的公开密钥的是真实有效的数字证书认证机构
  • 服务器的公开密钥是值得信赖的

三、总结

可以看到,HTTPS与HTTP虽然只差一个SSL,但是通信安全得到了大大的保障,通信的四大特性都以解决,解决方式如下:

  • 机密性:混合算法
  • 完整性:摘要算法
  • 身份认证:数字签名
  • 不可否定:数字签名

同时引入第三方证书机构,确保公开秘钥的安全性

参考文献

面试官:什么是HTTP? HTTP 和 HTTPS 的区别?

一、HTTP

HTTP (HyperText Transfer Protocol),即超文本运输协议,是实现网络通信的一种规范

在计算机和网络世界有,存在不同的协议,如广播协议、寻址协议、路由协议等等……

而HTTP是一个传输协议,即将数据由A传到B或将B传输到A,并且 A 与 B 之间能够存放很多第三方,如: A<=>X<=>Y<=>Z<=>B

传输的数据并不是计算机底层中的二进制包,而是完整的、有意义的数据,如HTML 文件, 图片文件, 查询结果等超文本,能够被上层应用识别

在实际应用中,HTTP常被用于在Web浏览器和网站服务器之间传递信息,以明文方式发送内容,不提供任何方式的数据加密

特点如下:

  • 支持客户/服务器模式

  • 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快

  • 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记

  • 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间

  • 无状态:HTTP协议无法根据之前的状态进行本次的请求处理

二、HTTPS

在上述介绍HTTP中,了解到HTTP传递信息是以明文的形式发送内容,这并不安全。而HTTPS出现正是为了解决HTTP不安全的特性

为了保证这些隐私数据能加密传输,让HTTP运行安全的SSL/TLS协议上,即 HTTPS = HTTP + SSL/TLS,通过 SSL证书来验证服务器的身份,并为浏览器和服务器之间的通信进行加密

SSL 协议位于 TCP/IP 协议与各种应用层协议之间,浏览器和服务器在使用 SSL 建立连接时需要选择一组恰当的加密算法来实现安全通信,为数据通讯提供安全支持

流程图如下所示:

  • 首先客户端通过URL访问服务器建立SSL连接
  • 服务端收到客户端请求后,会将网站支持的证书信息(证书中包含公钥)传送一份给客户端
  • 客户端的服务器开始协商SSL连接的安全等级,也就是信息加密的等级
  • 客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站
  • 服务器利用自己的私钥解密出会话密钥
  • 服务器利用会话密钥加密与客户端之间的通信

三、区别

  • HTTPS是HTTP协议的安全版本,HTTP协议的数据传输是明文的,是不安全的,HTTPS使用了SSL/TLS协议进行了加密处理,相对更安全
  • HTTP 和 HTTPS 使用连接方式不同,默认端口也不一样,HTTP是80,HTTPS是443
  • HTTPS 由于需要设计加密以及多次握手,性能方面不如 HTTP
  • HTTPS需要SSL,SSL 证书需要钱,功能越强大的证书费用越高

参考文献

面试官:如何理解TCP/IP协议?

一、是什么

TCP/IP,传输控制协议/网际协议,是指能够在多个不同网络间实现信息传输的协议簇

  • TCP(传输控制协议)

一种面向连接的、可靠的、基于字节流的传输层通信协议

  • IP(网际协议)

用于封包交换数据网络的协议

TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇,

只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以通称为TCP/IP协议族(英语:TCP/IP Protocol Suite,或TCP/IP Protocols)

二、划分

TCP/IP协议族按层次分别了五层体系或者四层体系

五层体系的协议结构是综合了 OSI 和 TCP/IP 优点的一种协议,包括应用层、传输层、网络层、数据链路层和物理层

五层协议的体系结构只是为介绍网络原理而设计的,实际应用还是 TCP/IP 四层体系结构,包括应用层、传输层、网络层(网际互联层)、网络接口层

如下图所示:

五层体系

应用层

TCP/IP 模型将 OSI 参考模型中的会话层、表示层和应用层的功能合并到一个应用层实现,通过不同的应用层协议为不同的应用提供服务

如:FTP、Telnet、DNS、SMTP 等

传输层

该层对应于 OSI 参考模型的传输层,为上层实体提供源端到对端主机的通信功能

传输层定义了两个主要协议:传输控制协议(TCP)和用户数据报协议(UDP)

其中面向连接的 TCP 协议保证了数据的传输可靠性,面向无连接的 UDP 协议能够实现数据包简单、快速地传输

网络层

负责为分组网络中的不同主机提供通信服务,并通过选择合适的路由将数据传递到目标主机

在发送数据时,网络层把运输层产生的报文段或用户数据封装成分组或包进行传送

数据链路层

数据链路层在两个相邻节点传输数据时,将网络层交下来的IP数据报组装成帧,在两个相邻节点之间的链路上传送帧

物理层

保数据可以在各种物理媒介上进行传输,为数据的传输提供可靠的环境

四层体系

TCP/IP 的四层结构则如下表所示:

层次名称 单位 功 能 协 议
网络接口层 帧 负责实际数据的传输,对应OSI参考模型的下两层 HDLC(高级链路控制协议)PPP(点对点协议) SLIP(串行线路接口协议)
网络层 数据报 负责网络间的寻址数据传输,对应OSI参考模型的第三层 IP(网际协议) ICMP(网际控制消息协议)ARP(地址解析协议) RARP(反向地址解析协议)
传输层 报文段 负责提供可靠的传输服务,对应OSI参考模型的第四层 TCP(控制传输协议) UDP(用户数据报协议)
应用层 负责实现一切与应用程序相关的功能,对应OSI参考模型的上三层 FTP(文件传输协议) HTTP(超文本传输协议) DNS(域名服务器协议)SMTP(简单邮件传输协议)NFS(网络文件系统协议)

三、总结

OSI 参考模型与 TCP/IP 参考模型区别如下:

相同点:

  • OSI 参考模型与 TCP/IP 参考模型都采用了层次结构
  • 都能够提供面向连接和无连接两种通信服务机制

不同点:

  • OSI 采用的七层模型; TCP/IP 是四层或五层结构

  • TCP/IP 参考模型没有对网络接口层进行细分,只是一些概念性的描述; OSI 参考模型对服务和协议做了明确的区分

  • OSI 参考模型虽然网络划分为七层,但实现起来较困难。TCP/IP 参考模型作为一种简化的分层结构是可以的

  • TCP/IP协议去掉表示层和会话层的原因在于会话层、表示层、应用层都是在应用程序内部实现的,最终产出的是一个应用数据包,而应用程序之间是几乎无法实现代码的抽象共享的,这也就造成 OSI 设想中的应用程序维度的分层是无法实现的

三种模型对应关系如下图所示:

参考文献

面试官:说说 HTTP1.0/1.1/2.0 的区别?

一、HTTP1.0

HTTP协议的第二个版本,第一个在通讯中指定版本号的HTTP协议版本

HTTP 1.0 浏览器与服务器只保持短暂的连接,每次请求都需要与服务器建立一个TCP连接

服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求

简单来讲,每次与服务器交互,都需要新开一个连接

例如,解析html文件,当发现文件中存在资源文件的时候,这时候又创建单独的链接

最终导致,一个html文件的访问包含了多次的请求和响应,每次请求都需要创建连接、关系连接

这种形式明显造成了性能上的缺陷

如果需要建立长连接,需要设置一个非标准的Connection字段 Connection: keep-alive

二、HTTP1.1

在HTTP1.1中,默认支持长连接(Connection: keep-alive),即在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟

建立一次连接,多次请求均由这个连接完成

这样,在加载html文件的时候,文件中多个请求和响应就可以在一个连接中传输

同时,HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间

同时,HTTP1.1在HTTP1.0的基础上,增加更多的请求头和响应头来完善的功能,如下:

  • 引入了更多的缓存控制策略,如If-Unmodified-Since, If-Match, If-None-Match等缓存头来控制缓存策略
  • 引入range,允许值请求资源某个部分
  • 引入host,实现了在一台WEB服务器上可以在同一个IP地址和端口号上使用不同的主机名来创建多个虚拟WEB站点

并且还添加了其他的请求方法:put、delete、options…

三、HTTP2.0

而HTTP2.0在相比之前版本,性能上有很大的提升,如添加了一个特性:

  • 多路复用
  • 二进制分帧
  • 首部压缩
  • 服务器推送

多路复用

HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了”队头堵塞”

上图中,可以看到第四步中css、js资源是同时发送到服务端

二进制分帧

帧是HTTP2通信中最小单位信息

HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,解析起来更高效

将请求和响应数据分割为更小的帧,并且它们采用二进制编码

HTTP2 中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流

每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装,这也是多路复用同时发送数据的实现条件

首部压缩

HTTP/2在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键值对,对于相同的数据,不再通过每次请求和响应发送

首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新

例如:下图中的两个请求, 请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销

服务器推送

HTTP2引入服务器推送,允许服务端推送资源给客户端

服务器会顺便把一些客户端需要的资源一起推送到客户端,如在响应一个页面请求中,就可以随同页面的其它资源

免得客户端再次创建连接发送请求到服务器端获取

这种方式非常合适加载静态资源

四、总结

HTTP1.0:

  • 浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接

HTTP1.1:

  • 引入了持久连接,即TCP连接默认不关闭,可以被多个请求复用
  • 在同一个TCP连接里面,客户端可以同时发送多个请求
  • 虽然允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的,服务器只有处理完一个请求,才会接着处理下一个请求。如果前面的处理特别慢,后面就会有许多请求排队等着
  • 新增了一些请求方法
  • 新增了一些请求头和响应头

HTTP2.0:

  • 采用二进制格式而非文本格式
  • 完全多路复用,而非有序并阻塞的、只需一个连接即可实现并行
  • 使用报头压缩,降低开销
  • 服务器推送

参考文献

面试官:DNS协议 是什么?说说DNS 完整的查询过程?

一、是什么

DNS(Domain Names System),域名系统,是互联网一项服务,是进行域名和与之相对应的 IP 地址进行转换的服务器

简单来讲,DNS相当于一个翻译官,负责将域名翻译成ip地址

  • IP 地址:一长串能够唯一地标记网络上的计算机的数字
  • 域名:是由一串用点分隔的名字组成的 Internet 上某一台计算机或计算机组的名称,用于在数据传输时对计算机的定位标识

二、域名

域名是一个具有层次的结构,从上到下一次为根域名、顶级域名、二级域名、三级域名…

例如www.xxx.com,www为三级域名、xxx为二级域名、com为顶级域名,系统为用户做了兼容,域名末尾的根域名.一般不需要输入

在域名的每一层都会有一个域名服务器,如下图:

除此之外,还有电脑默认的本地域名服务器

三、查询方式

DNS 查询的方式有两种:

  • 递归查询:如果 A 请求 B,那么 B 作为请求的接收者一定要给 A 想要的答案

  • 迭代查询:如果接收者 B 没有请求者 A 所需要的准确内容,接收者 B 将告诉请求者 A,如何去获得这个内容,但是自己并不去发出请求

四、域名缓存

在域名服务器解析的时候,使用缓存保存域名和IP地址的映射

计算机中DNS的记录也分成了两种缓存方式:

  • 浏览器缓存:浏览器在获取网站域名的实际 IP 地址后会对其进行缓存,减少网络请求的损耗
  • 操作系统缓存:操作系统的缓存其实是用户自己配置的 hosts 文件

五、查询过程

解析域名的过程如下:

  • 首先搜索浏览器的 DNS 缓存,缓存中维护一张域名与 IP 地址的对应表

  • 若没有命中,则继续搜索操作系统的 DNS 缓存

  • 若仍然没有命中,则操作系统将域名发送至本地域名服务器,本地域名服务器采用递归查询自己的 DNS 缓存,查找成功则返回结果

  • 若本地域名服务器的 DNS 缓存没有命中,则本地域名服务器向上级域名服务器进行迭代查询

    • 首先本地域名服务器向根域名服务器发起请求,根域名服务器返回顶级域名服务器的地址给本地服务器
    • 本地域名服务器拿到这个顶级域名服务器的地址后,就向其发起请求,获取权限域名服务器的地址
    • 本地域名服务器根据权限域名服务器的地址向其发起请求,最终得到该域名对应的 IP 地址
  • 本地域名服务器将得到的 IP 地址返回给操作系统,同时自己将 IP 地址缓存起来

  • 操作系统将 IP 地址返回给浏览器,同时自己也将 IP 地址缓存起

  • 至此,浏览器就得到了域名对应的 IP 地址,并将 IP 地址缓存起

流程如下图所示:

参考文献