0%

0.0.1. 安装

1
2
3
4
5
6
7
8
# 查看架构
dpkg --print-architecture
# 添加 i386
sudo dpkg --add-architecture i386 && sudo apt update
# 安装
sudo apt install wine wine32 wine64 libwine libwine:i386 fonts-wine
sudo apt install wine-development wine32-development wine64-development libwine-development libwine-development:i386 fonts-wine
sudo apt install winetrick

0.0.2. 使用

0.0.2.0.1. 选择版本

选择稳定版or开发版

1
sudo update-alternatives --config wine
0.0.2.0.2. 配置wine
1
2
3
4
# 配置窗口
winecfg
# 配置注册表
regedit
0.0.2.0.3. 安装软件
1
wine setup.exe
0.0.2.0.4. 卸载软件
1
2
# uninstaller 不能完全删除菜单和桌面图标, 必须手动删除
wine uninstaller

0.0.3. Resource

0.0.1. 常用命令选项

-c 断点续传
-t 重试次数, 0 表示不限次数
-T 等待超时时间
-o 保存到目录

1. 常用命令选项

-f 连接失败时不显示http错误
-s 静音模式.不输出任何东西
-I 显示 Header 信息, 但是不能和 -F (上传文件) 一起使用
-S 显示错误
-L 当页面有跳转的时候, 输出跳转到的页面
-d POST方式传送数据
-A user-agent
-H header key:value
-X method
-k 不效验 https 证书
-c cookie.txt 将 cookie 保存到 cookie.txt
-b cookie.txt 使用 cookie.txt 的内容做为 cookie
-o 指定输出路径, - 表示输出到控制台

2. 获取IP

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
# curl ipinfo.io
{
"ip": "114.110.1.38",
"hostname": "No Hostname",
"city": "Beijing",
"region": "Beijing Shi",
"country": "CN",
"loc": "39.9289, 116.3883",
"org": "AS4808 CNCGROUP IP network China169 Beijing Province Network"
}

# curl ip.cn
当前 IP: 114.110.1.38 来自: 北京市 广东恒敦通信技术北京分公司

# curl cip.cc
IP : 114.110.1.38
地址 : 中国 北京市
数据二 : 北京市 | 广东恒敦通信技术北京分公司
URL : http://www.cip.cc/114.110.1.38

# curl myip.ipip.net
当前 IP: 114.110.1.38 来自于: 中国 北京 北京 联通/电信

# curl ifconfig.me
114.110.1.38

# curl http://members.3322.org/dyndns/getip
114.110.1.38

3. 样例

1
curl -x socks5://127.0.0.1:1080 http://www.baidu.com

4. Resource

1. 安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 删除老版本
sudo apt-get remove docker docker-engine docker.io

# 安装
sudo apt install apt-transport-https ca-certificates curl gnupg2 software-properties-common
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
sudo apt update
sudo apt install docker-ce

# 添加docker组
# sudo groupadd docker
# sudo gpasswd -a ${USER} docker
# sudo systemctl restart docker
# 切换当前会话到新 group 或者重启 X 会话

# 查看当前用户所在的所有用户组
groups
# 将用户添加到 docker 用户组
sudo usermod -a -G docker <username>
# 刷新
newgrp - docker

2. 镜像

通过修改镜像源地址, 加快镜像下载速度.
镜像源配置文件是: /etc/docker/daemon.json

  1. 使用daoCloud的镜像加速器
2.0.0.0.1. 修改方法

不同环境可查看 https://www.daocloud.io/mirror#accelerator-doc

在linux下使用如下命令配置:

1
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://85ad13ff.m.daocloud.io
  1. 阿里云镜像加速器

注册 https://cr.console.aliyun.com/
之后访问 https://cr.console.aliyun.com/#/accelerator
获得专属加速器
/etc/docker/daemon.json

1
2
3
{
"registry-mirrors": ["https://61mj61jz.mirror.aliyuncs.com"]
}
1
2
sudo systemctl daemon-reload
sudo systemctl restart docker

3. 网络

1
docker run --net=bridge

4. 修改Docker的默认镜像存储位置

可能会需要镜像太多, 或者磁盘分配太小, 之后导致无法再下载镜像,或者容器无法启动.
我们可能需要将镜像存储位置移动到其他文件目录下.

默认镜像存储位置是 /var/lib/docker

1
2
# 通过该命令查看默认镜像存储位置
docker info | grep 'Docker Root Dir'

4.1. 方式 1: 修改Docker的默认镜像存储位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 停止服务
systemctl stop docker

# 对之前的数据做个文件备份, 如果有把握可以跳过
tar -zcC /var/lib/docker >/mnt/var_lib_docker-backup-$(date + %s).tar.gz

# 迁移整个/var/lib/docker目录到目的路径
mv /var/lib/docker /home/raven/Package/docker

# 建立symlink软链接
ln -s /data/tools/docke /var/lib/docker

# 确认文件夹类型为symlink 类型
ls -al /var/lib/docker

# 重启服务
sudo systemctl start docker

4.2. 方式 2: 修改镜像和容器的默认存放路径

/etc/default/docker 中修改

DOCKER_OPTS="-g /home/raven/Package/docker"

之后重启服务

或者 修改 /etc/docker/daemon.json

{“registry-mirrors”: [“http://***.***.com”],“graph”:"/home/raven/Packages/docker"}

修改后立即生效

5. 容器管理工具

以下 3 个工具都能通过文件配置管理与发布 Docker 容器.

5.1. Docker Compose

Docker Compose 只能管理当前主机上的容器

5.2. Docker Swarm

Docker Swarm 能管理多主机上的容器, 是由 Docker 公司开发的

5.3. Kubernates

Kubernates 也能管理多主机上的容器, 是有谷歌开发的.
Kubernates 比 Docker Swarm 更主流有点, 目前很多大公司使用它作为默认容器管理工具.

6. Problem

6.1. 1. 动态设置 容器最大内存

在部署docker应用, 应用编排时都需要指定一个内存的最大使用上限.
如果应用使用的内存超过了配额, 镜像会被kill掉.
所以java微服务应用, 有必要设置应用自己的最大内存.

docker镜像服务的内存不能全部给 -Xmx , 因为JVM消耗的内存不仅仅是Heap.

JVM = Heap + Method Area +Constant Pool + Thread Stack * num of thread .

Xmx的值可设置为镜像上限减去150m或200m.
当然还需要考虑应用自身的特点, 比如class数目, 并发线程数等.

通过 cgroups 动态获取容器资源配置

1
2
3
4
5
6
7
8
9
10
11
12
13
# git memory limit size
limit_in_bytes=$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)

# If not default limit_in_bytes in cgroup
if [ "$limit_in_bytes" -ne "9223372036854771712" ]
then
limit_in_megabytes=$(expr $limit_in_bytes \/ 1048576)
heap_size=$(expr $limit_in_megabytes - $RESERVED_MEGABYTES)
export JAVA_OPTS="-Xmx${heap_size}m $JAVA_OPTS"
echo JAVA_OPTS=$JAVA_OPTS
fi

# start tomcat

7. 常见问题

7.1. docker 杀死容器

解决办法, 调整容器分配的内存到 1280m , 调整jvm分配的内存, 大致参数如下:

-Xms512m -Xmx512m -XX:ReservedCodeCacheSize=128m -XX:+UseCodeCacheFlushing -XX:MetaspaceSize=192m -XX:MaxMetaspaceSize=192m -XX:MaxDirectMemorySize=64m

明确已知内存 512m + 128m + 192m + 64m 共 896m,

另外线程预留 128m (预留 200线程, 每线程 512k)

剩余 256m 作为余量

8. Resource

1. 安装

1
2
3
npm install -g hexo-cli
cd your-blog
hexo init

2. 常用命令选项

1
2
3
4
5
6
7
8
9
10
11
12
13
d, deploy    Deploy your website.
g, generate Generate static files.
n, new Create a new post.
s, server Start the server.
clean Remove generated files and cache.
config Get or set configurations.
help Get help on a command.
init Create a new Hexo folder.
list List the information of the site
migrate Migrate your site from other system to Hexo.
publish Moves a draft post from \_drafts to \_posts folder.
render Render files with renderer plugins.
version Display version information.

3. 常用插件

  • hexo-abbrlink 链接地址优化
  • hexo-pdf 支持pdf
  • hexo-deployer-git 用git发布
  • hexo-generator-searchdb 支持本地搜索
  • hexo-footnotes 支持脚注 (脚注非 markdown 原生语法, 需要插件支持)
  • hexo-tag-plantuml 画UML图
  • hexo-tag-echarts3 支持EChart
  • hexo-heading-index 标题自动添加序号
1
cnpm i -S hexo-abbrlink hexo-pdf hexo-deployer-git hexo-generator-searchdb hexo-footnotes hexo-tag-plantuml hexo-tag-echarts3 hexo-heading-index

4. 最好用的主题

next-Pisces 主题简洁大方, 功能丰富, 翻了多个主题, 就这个最方便了.
自带 mathjax.

1
2
3
4
5
6
7
cd $blog_dir
git clone -b master --depth=1 https://github.com/theme-next/hexo-theme-next themes/next


git clone -b master --depth=1 https://github.com/theme-next/hexo-theme-next next
ln -sf next $blog_dir/themes/next
ln -sf $DOCS_DIR/next $DOCS_DIR/blog/themes/next

之后添加 ${your-blog}/source/_posts/_data/next.yml, 用于覆盖 theme/next/_config.yml

5. 常见问题

5.1. 数据表达式支持

  1. ${your-blog}/source/_posts/_data/next.yml 文件中打开数据表达式支持
1
2
3
math:
katex:
enable: true
  1. 把 hexo-renderer-marked 卸载
1
2
cnpm un -S hexo-renderer-marked
cnpm i -S hexo-renderer-markdown-it-plus
  1. 在博客文件头中添加标识 mathjax: true

之后在博客文件正文就可以写数学表达式了, 如:

1
2
3
4
5
6
7
8
9
10
11
单行数学表达式:
$a \ne 0$

多行数学表达式:
$$
\begin{aligned}
a &= b + c \\
&= d + e + f + g \\
&= h + i
\end{aligned}
$$

5.2. 特殊字符转义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
! &#33; — 惊叹号 Exclamation mark
” &#34; " 双引号 Quotation mark
# &#35; — 数字标志 Number sign
$ &#36; — 美元标志 Dollar sign
% &#37; — 百分号 Percent sign
& &#38; & Ampersand
‘ ' — 单引号 Apostrophe
( &#40; — 小括号左边部分 Left parenthesis
) &#41; — 小括号右边部分 Right parenthesis
* &#42; — 星号 Asterisk
+ &#43; — 加号 Plus sign
< &#60; < 小于号 Less than
= &#61; — 等于符号 Equals sign
- &#45; &minus; — 减号
> &#62; > 大于号 Greater than
? &#63; — 问号 Question mark
@ &#64; — Commercial at
[ &#91; --- 中括号左边部分 Left square bracket
\ &#92; --- 反斜杠 Reverse solidus (backslash)
] &#93; — 中括号右边部分 Right square bracket
{ &#123; — 大括号左边部分 Left curly brace
| &#124; — 竖线Vertical bar
} &#125; — 大括号右边部分 Right curly brace

6. Resource

1. 安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# nvm 安装
# https://github.com/nvm-sh/nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash

# 由于 nvm 启动比较慢, 所以使用手工方式加载
# 先清理 .bashrc .zshrc 中的 nvm 环境信息
# 在环境配置中添加:
snvm(){
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
}

# 下载安装 nodejs
nvm ls-remote
nvm install [lastest-version]
nvm install --lts

# npm 配置 taobao registry
npm config set registry https://registry.npm.taobao.org --global
npm config set disturl https://npm.taobao.org/dist --global
npm install cnpm -g --registry=http://registry.npm.taobao.org

2. Resource

NVM Guides CNPM

1. 类

类封装了信息和行为, 是面向对象的重要组成部分, 它是具有相同属性, 操作, 关系对象集合的总称.
在系统中, 每个类都应该具有一定的职责, 职责是指类锁担任的任务. 一个类可以有多个职责, 但设计得好的类一般只有一种职责.
在定义类时, 当类的职责分解为类的属性和操作, 其中属性用于封装数据, 操作用于封装行为.
设计类时面向对象设计中最重要的组成部分, 也是最复杂和最耗时的部分.

在软件系统运行时, 类将被实例化成对象, 对象对应于某个具体的事物. 类是对一组具有相同属性, 表现相同行为的抽象, 对象是类的实例.

2. 类之间的关系

按关系的强弱程度依次为: 泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖

2.1. 泛化 Generalization

is-a
是一种继承关系, 表示一般与特殊的关系.它指定了子类如何特例化父类的所有特征和行为.
代码体现: extends

实线, 空心三角箭头指向父类

2.2. 实现 Realization

is-a
接口的实现, 是类与接口的关系, 表示接口所有特征和行为的实现.
代码体现: implements

虚线, 空心三角箭头指向接口

2.3. 聚合 Aggregation

has-a
拥有关系, 是关联关系的一种特例, 整体与部分的关系, 且部分可以离开整体而单独存在.
代码体现: 成员变量

实线, 空心菱形箭头指向整体, 普通箭头指向部分

2.4. 组合 Composition

contains-a
拥有关系, 也是关联关系的一种特例, 整体与部分的关系, 但部分不能离开整体而单独存在.它具有比聚合更强的拥有关系, 强调整体与部分的生命周期是一致的.
代码体现: 成员变量

实线, 实心菱形箭头指向整体, 普通箭头指向部分

2.5. 关联 Association

拥有关系, 它使一个类知道另一个类的属性和方法.
代码体现: 成员变量

实线, 普通箭头指向被拥有者, 可以是单向的, 也可以是双向的, 甚至是自关联.

2.6. 依赖 Dependency

use-a
是一种使用的关系, 即一个类的实现需要另一个类的协助, 所以要尽量不使用双向的互相依赖.
代码体现: 局部变量, 方法的参数或者对静态方法的调用

虚线, 普通箭头指向被使用者

3. 画图工具

4. Resource

5. 趣闻

UML 官方文档 中嘲讽维基百科: 搞不懂你们是从哪里听来的

UML specification categorizes association as semantic relationship. Some other UML sources also categorize association as a structural relationship.
Wikipedia states that association is instance level relationship and that associations can only be shown on class diagrams.
Not sure where they got that information from but it is not based on UML specification. Association could be used on different types of UML structure diagrams

加密算法可分: 可逆算法和不可逆算法, 其中可逆算法又可分: 对称加密和非对称加密.

对称加密
指加密和解密使用相同密钥的加密算法.对称加密算法的优点在于加解密的高速度和使用长密钥时的难破解性.假设两个用户需要使用对称加密方法加密然后交换数据, 则用户最少需要2个密钥并交换使用, 如果企业内用户有n个, 则整个企业共需要n×(n-1) 个密钥, 密钥的生成和分发将成为企业信息部门的恶梦.对称加密算法的安全性取决于加密密钥的保存情况, 但要求企业中每一个持有密钥的人都保守秘密是不可能的, 他们通常会有意无意的把密钥泄漏出去——如果一个用户使用的密钥被入侵者所获得, 入侵者便可以读取该用户密钥加密的所有文档, 如果整个企业共用一个加密密钥, 那整个企业文档的保密性便无从谈起.
常见的对称加密算法: DES, 3DES, DESX, Blowfish, IDEA, RC4, RC5, RC6和AES

非对称加密
指加密和解密使用不同密钥的加密算法, 也称为公私钥加密.假设两个用户要加密交换数据, 双方交换公钥, 使用时一方用对方的公钥加密, 另一方即可用自己的私钥解密.如果企业中有n个用户, 企业需要生成n对密钥, 并分发n个公钥.由于公钥是可以公开的, 用户只要保管好自己的私钥即可, 因此加密密钥的分发将变得十分简单.同时, 由于每个用户的私钥是唯一的, 其他用户除了可以可以通过信息发送者的公钥来验证信息的来源是否真实, 还可以确保发送者无法否认曾发送过该信息.非对称加密的缺点是加解密速度要远远慢于对称加密, 在某些极端情况下, 甚至能比非对称加密慢上1000倍.
常见的非对称加密算法: RSA, ECC(移动设备用), Diffie-Hellman, El Gamal, DSA(数字签名用)

Hash算法
Hash算法特别的地方在于它是一种单向算法, 用户可以通过Hash算法对目标信息生成一段特定长度的唯一的Hash值, 却不能通过这个Hash值重新获得目标信息.因此Hash算法常用在不可还原的密码存储, 信息完整性校验等.
常见的Hash算法: MD2, MD4, MD5, HAVAL, SHA, SHA-1, HMAC, HMAC-MD5, HMAC-SHA1

加密算法的效能通常可以按照算法本身的复杂程度, 密钥长度(密钥越长越安全), 加解密速度等来衡量.上述的算法中, 除了DES密钥长度不够, MD2速度较慢已逐渐被淘汰外, 其他算法仍在目前的加密系统产品中使用.

加密算法的选择
前面的章节已经介绍了对称解密算法和非对称加密算法, 有很多人疑惑: 那我们在实际使用的过程中究竟该使用哪一种比较好呢?
我们应该根据自己的使用特点来确定, 由于非对称加密算法的运行速度比对称加密算法的速度慢很多, 当我们需要加密大量的数据时, 建议采用对称加密算法, 提高加解密速度.
对称加密算法不能实现签名, 因此签名只能非对称算法.
由于对称加密算法的密钥管理是一个复杂的过程, 密钥的管理直接决定着他的安全性, 因此当数据量很小时, 我们可以考虑采用非对称加密算法.
在实际的操作过程中, 我们通常采用的方式是: 采用非对称加密算法管理对称算法的密钥, 然后用对称加密算法加密数据, 这样我们就集成了两类加密算法的优点, 既实现了加密速度快的优点, 又实现了安全方便管理密钥的优点.
如果在选定了加密算法后, 那采用多少位的密钥呢?一般来说, 密钥越长, 运行的速度就越慢, 应该根据的我们实际需要的安全级别来选择, 一般来说, RSA建议采用1024位的数字, ECC建议采用160位, AES采用128为即可.

算法选择(从性能和安全性综合)
对称加密: AES(128位),
非对称加密: ECC(160位)或RSA(1024),
消息摘要: MD5
数字签名:DSA

1. 常见加密算法

// todo
crc16 crc32

1.0.1. Resource

1. HTTPS

Secure Hypertext Transfer Protocol, 安全超文本传输协议.
是使用 TLS/SSL 加密的 HTTP 协议, 是 HTTP 的安全版.

2. TLS/SSL

TLS/SSL 协议, 即安全传输层协议, 是介于 TCP 和 HTTP 之间的一层安全协议, 不影响原有的 TCP 协议和 HTTP 协议.

TLS/SSL 协议提供服务的主要有:

  • 身份验证, 防止劫持
  • 信息加密, 防止窃听
  • 完整性效验, 防止篡改

TLS/SSL 可分为2层:

  • Record Protocol, 记录协议
    它建立在可靠的传输协议之上, 如 TCP 协议, 为高层协议提供数据封装, 压缩, 加密等基本功能的支持.
    主要用来定义传输的格式.
  • Handshake Protocol, 握手协议
    它建立在SSL记录协议之上, 用于在实际的传输开始前, 通信双方进行身份认证, 协商加密算法, 交换加密密钥等.
    主要用来协商出一份密钥.

2.1. TLS/SSL 工作原理

TLS/SSL的功能实现主要依赖于三类基本算法: 散列函数 Hash, 对称加密和非对称加密, 其利用非对称加密实现身份认证和密钥协商, 对称加密算法采用协商的密钥对数据加密, 基于散列函数验证信息的完整性.

2.1.1. 非对称加密

即常见的 RSA 算法, 还包括 ECC, DH 等算法.
算法特点是, 密钥成对出现, 一般称为公钥(公开)和私钥(保密), 公钥加密的信息只能私钥解开, 私钥加密的信息只能公钥解开.
因此掌握公钥的不同客户端之间不能互相解密信息, 只能和掌握私钥的服务器进行加密通信, 服务器可以实现1对多的通信, 客户端也可以用来验证掌握私钥的服务器身份.
非对称加密的特点是信息传输1对多, 服务器只需要维持一个私钥就能够和多个客户端进行加密通信, 但服务器发出的信息能够被所有的客户端解密, 且该算法的计算复杂, 加密速度慢.

2.1.2. 对称加密

常见的有 AES-CBC, DES, 3DES, AES-GCM等, 相同的密钥可以用于信息的加密和解密, 掌握密钥才能获取信息, 能够防止信息窃听, 通信方式是1对1.
对称加密的优势是信息传输1对1, 需要共享相同的密码, 密码的安全是保证信息安全的基础, 服务器和 N 个客户端通信, 需要维持 N 个密码记录, 且缺少修改密码的机制.

2.1.3. 散列函数 Hash

常见的有 MD5, SHA1, SHA256, 该类函数特点是函数单向不可逆, 对输入非常敏感, 输出长度固定, 针对数据的任何修改都会改变散列函数的结果, 用于防止信息篡改并验证数据的完整性.
在信息传输过程中, 散列函数不能单独实现信息防篡改, 因为明文传输, 中间人可以修改信息之后重新计算信息摘要, 因此需要对传输的信息以及信息摘要进行加密.

结合三类算法的特点, TLS的基本工作方式是, 客户端使用非对称加密与服务器进行通信, 实现身份验证并协商对称加密使用的密钥, 然后对称加密算法采用协商密钥对信息以及信息摘要进行加密通信, 不同的节点之间采用的对称密钥不同, 从而可以保证信息只能通信双方获取.

2.2. TLS/SSL 握手过程

2.2.1. 客户端发起请求

Client Hello
客户端发起请求, 以明文传输请求信息, 包含信息有:

  • version: 当前支持的最后TLS协议版本
  • cipher suites: 客户端支持的加密套件列表
    每个加密条件对应4个功能组合:
    • Au, 认证算法, 用于身份认证
    • Key Exchange, 密钥交换算法, 用于密钥协商
    • Enc, 对称加密算法, 用于信息加密
    • Mac, 信息摘要算法, 用于完整性效验
  • compression methods: 支持的压缩算法列表, 用于后续的信息压缩传输
  • random_client: 用于后续的密钥生成
  • extensions: 扩展字段, 支持协议与算法的相关参数及其他辅助信息等, 如常见的SNI

2.2.2. 服务器端回应

2.2.2.1. Server Hello

服务端返回协商的结果, 包含信息有:

  • version: 使用的协议版本
  • cipher suite: 选择的加密套件
  • compression method: 选择的压缩算法
  • random_server: 用于后续的密钥生成

2.2.2.2. Server Certificate

服务端配置对应的证书链发送给客户端, 用于身份效验与密钥交换.

2.2.2.3. Server Hello Done

服务端通知客户端 Server Hello 发送结束.

2.2.2.4. Client Certificate Request

对于非常重要的信息, 服务端需要对客户端进行验证, 保证数据传送给了安全合法的客户端.
服务端发送 client_certificate_request 标识, 请求验证客户端证书.

2.2.3. 客户端验证证书

Certificate Verify
客户端验证证书合法性.
如果验证通过才会进行后续通信, 否则根据错误情况不同做出提示和操作.

  • 证书链的可信性 trusted certificate path
  • 证书是否被吊销 revocation
  • 有效期 expiry date
  • 域名 domain

2.2.4. 客户端回应

2.2.4.1. Client Certificate

如果服务端需要验证客户端证书, 即双向认证.
认证方式基本相同, 客户端发送 client_certificate 与 certificate_verify_message.
certificate_verify_message 是采用client的私钥加密以及协商的通信信息得到数据, 服务端采用对应的公钥解密并验证.

2.2.4.2. Client Key Exchange

客户端计算产生随机数 pre_master_secret, 并用证书公钥加密, 发送给服务端.
此时客户端已经获得计算协商密钥的全部信息:两个明文随机数 random_client 与 random_server, 以及自己计算产生的 pre_master_secret
计算得到协商密钥: session_secret = encrypt(random_client, random_server, pre_master_secret)

2.2.4.3. Change Cipher Spec

发送 change_cipher_spec 标识, 用于通知服务端后续的通信采用协商的通信密钥和加密算法进行.

2.2.4.4. Encrypt Handshake Message

客户端结合之前所有通信参数的 hash 值与其他相关信息生成一段数据, 采用协商密钥 session_secret 与算法进行加密, 然后发送给服务器用于数据与握手验证.

2.2.5. 服务端最后回应

服务端用证书私钥解密加密的 pre_master_secret, 并计算出 session_secret.

服务端计算之前所有接收信息的hash值, 然后解密客户端发送的 encrypt_handshake_message, 验证数据和密钥正确性.

2.2.5.1. Change Cipher Spec

服务端验证通过后, 统一发送 change_cipher_spec, 通知客户端后续的通信采用协商的通信密钥和加密算法进行.

2.2.5.2. Encrypt Handshake Message

服务端也结合之前所有通信参数的 hash 值与其他相关信息生成一段数据, 采用协商密钥 session_secret 与算法进行加密, 然后发送给客户端.

2.2.6. 握手结束

客户端同样计算并验证 encrypt_handshake_message, 验证通过则握手完成.

2.2.7. 加密通信

开始使用协商密钥和算法进行通信.

2.3. 密钥

2.3.1. 密钥计算

密钥计算流程如下:

  • 客户端使用 RSA 或 DH 等加密算法生成 pre_master_secret
  • pre_master_secret 结合 random_client 和 random_server 两个随机数通过 PseudeRandomFunction (PRF)计算得到 master_secret
  • master_secret 结合 random_client 和 random_server 两个随机数通过迭代计算得到 Key-Material

2.3.2. 密钥使用

密钥经过12轮迭代计算会获得12个hash值, 分组成为6个元素, 列表如下:

  • Client Mac Key
  • Server Mac Key
  • Client Encryption Key
  • Server Encryption Key
  • Client IV
  • Server IV

其中, Mac Key 用于完整性效验, Encryption Key 用于对称加密, IV 作为加密算法的初始化向量.
用法如下:

  • Mac Key, Encryption Key和IV是一组加密元素, 分别被客户端和服务端使用, 但是则两组元素都被两边同时获取.
  • 客户端使用 client 组元素加密数据, 服务端使用 client 组元素解密; 服务端使用 server 组元素加密数据, 客户使用 server 组元素解密.
  • 双向通信的不同方向使用的密钥不同, 破解通信至少需要破解2次.
  • MAC 值的计算包括2个 Hash 值: Mac Key 和 Hash(编号, 包类型, 长度, 压缩数据)

2.4. 其他要点

  • pre_master_secret 前2个字节是TLS版本号
    这是一个比较重要的用来核对握手数据的版本号.
    因为在 Client Hello 阶段, 客户端会发送一份加密套件列表和定钱支持的 TLS/SSL 的版本号给服务端, 而且是使用明文传送的, 如果握手的数据包被破解后, 攻击者恒可能串改数据包, 选择一个安全性较低的加密太监和版本给服务端, 从而对数据进行破坏.
    所以, 服务端需要对密文中解密出来的 pre_master_secret 版本号跟之前 Client Hello 阶段的版本号进行比对, 如果版本号变低, 则立即停止发送任何消息.

  • 不管客户端还是服务端, 都需要随机数, 这样生成的密钥才不会每次都一样.
    由于 TLS/SSL 协议中证书是静态的, 因此十分有必要引入一种随机因素来保证协商出来的密钥的随机性.

    对于 RSA 密钥交换算法来说, pre_master_secret 本身就是一个随机数, 再加上 hello 消息中的随机, 三个随机数通过一个密钥导出器最终导出一个对称密钥.

    pre_master_secret 的存在在于 SSL 协议不信任每个主机都能产生完全随机的随机数, 如果随机数不随机, 那么 pre_master_secret 就有可能被猜出来, 那么仅适用 pre_master_secret 作为密钥就不合适了, 因此必须引入新的随机因素, 那么客户端和服务器加上 pre_master_secret 三个随机数一同生成的密钥就不容易被猜出了, 一个伪随机可能完全不随机, 可是三个伪随机就十分接近随机了, 每增加一个自由度, 随机性增加的可不是一.

  • 对应用层数据进行分片成合适的block
    为分片数据编号, 防止重放攻击

3. HTTPS 性能与优化

HTTPS的优点在于:

  • 身份认证, 信息加密和完整性效验, 提高了通信安全性
  • 未对 TCP 和 HTTP 协议做任何改动

HTTPS付出代价便是增加了性能损耗, 主要体现在:

  • 增加延时
    一次完整的握手至少需要两端来回2次通信, 即至少增加延时 2 * RTT; 即使利用会话缓存从而复用连接, 延时也至少增加 1 * RTT.

  • CPU资源消耗更多
    非对称算法 RSA 解密能力是当前困扰HTTPS接入的主要难题.

3.1. HTTPS 接入优化

  • CDN接入
    HTTPS 增加的延时主要是传输延时 RTT, RTT 的特点是节点越近延时越小, CDN 天然离用户最近, 因此选择使用 CDN 作为 HTTPS 接入的入口, 将能够极大减少接入延时.
    CDN 节点通过和业务服务器维持长连接, 会话复用和链路质量优化等可控方法, 极大减少 HTTPS 带来的延时.

  • 会话缓存
    虽然前文提到 HTTPS 即使采用会话缓存也要至少1*RTT的延时, 但是至少延时已经减少为原来的一半, 明显的延时优化;
    同时, 基于会话缓存建立的 HTTPS 连接不需要服务器使用 RSA 私钥解密获取 pre_master_secret 信息, 可以省去 CPU 的消耗.
    如果业务访问连接集中, 缓存命中率高, 则HTTPS的接入能力讲明显提升.
    当前 TRP 平台的缓存命中率高峰时期大于 30%, 10k/s 的接入资源实际可以承载13k/s 的接入, 收效非常可观.

  • 硬件加速
    为接入服务器安装专用的SSL硬件加速卡, 作用类似 GPU, 释放 CPU, 能够具有更高的 HTTPS 接入能力且不影响业务程序的.
    测试某硬件加速卡单卡可以提供35k的解密能力, 相当于175核 CPU, 至少相当于7台24核的服务器, 考虑到接入服务器其它程序的开销, 一张硬件卡可以实现接近10台服务器的接入能力.

  • 远程解密
    本地接入消耗过多的 CPU 资源, 浪费了网卡和硬盘等资源, 考虑将最消耗 CPU 资源的 RSA 解密计算任务转移到其它服务器, 如此则可以充分发挥服务器的接入能力, 充分利用带宽与网卡资源.
    远程解密服务器可以选择 CPU 负载较低的机器充当, 实现机器资源复用, 也可以是专门优化的高计算性能的服务器.
    当前也是 CDN 用于大规模HTTPS接入的解决方案之一.

  • SPDY/HTTP2
    前面的方法分别从减少传输延时和单机负载的方法提高 HTTPS 接入性能, 但是方法都基于不改变 HTTP 协议的基础上提出的优化方法, SPDY/HTTP2 利用 TLS/SSL 带来的优势, 通过修改协议的方法来提升 HTTPS 的性能, 提高下载速度等.

4. Resource