2021-08-20
- 如何保证公钥不被篡改?将公钥放在数字证书中,只要证书是可信的,公钥就是可信的。
握手过程
#
1. 客户端发送请求(ClientHello)。
#
客户端向服务器提供以下信息:
- 支持的协议版本,如TLS1.0版本。
- 客户端生成的随机数,是之后生成会话密钥的一部分。
- 支持的加密算法,如RSA。
- 支持的压缩算法。
2. 服务器收到请求后,向客户端发出回应(ServerHello)。
#
服务器向客户端发出回应包含以下内容(如果服务器需要确认客户端的身份,就需要再包含一项请求,要求和护短提供证书文件):
- 确认使用的协议版本。
- 服务器生成的随机数,是之后生成会话密钥的一部分。
- 确认使用的加密算法。
- 服务器证书。
3. 客户端回应
#
客户端收到回应后,先验证服务器的证书,如果证书不是可信机构颁发、证书中的域名与实际域名不一致、证书已经过期,就会显示一个警告询问是否继续。如果继续或者证书没有问题,客户端向服务端发送以下内容:
- 一个随机数(pre-master key),该随机数用服务器的公钥加密。
- 编码改变通知,表示随后的信息都用协商的加密算法和密钥发送。
- 客户端的握手结束通知,包含前面发送所有内容的hash值,供服务器校验。
4. 服务器回应
#
服务器收到第三个随机数后,计算会话使用的“会话密钥”,向客户端发送以下信息:
- 编码改变通知,表面之后的信息都用协商的加密算法和密钥发送。
- 服务器握手状态结束通知,包含签名发送的所有内容的hash值。
- 中间人攻击:如果中间人在客户端与服务端开始建立连接的时候,拦截客户端的请求,让客户端与自己通信,自己再和服务端通信,出现了:客户端请求->中间人->服务端,服务端响应->中间人->客户端,中间人能获取到客户端请求的所有数据和服务端响应的所有数据。所以当出现证书不安全的时候要注意。
参考链接:
SSL/TLS协议运行机制的概述 - 阮一峰的网络日志 (ruanyifeng.com)
2021-08-20
- 全称是JSON Web Token。
- jwt由下面三个部分组成,格式类似
aaa.bbb.ccc
- Header(头部)
- Payload(负载)
- Signature(签名)
- Header部分是一个JSON对象,由签名算法和token类型组成,会使用用Base64URL加密,加密后的数据组成jwt的第一部分。原始数据如下(例):
{
"alg":"HS256",
"typ":"JWT"
}
- Payload也是一个JSON对象,会用Base64URL加密,加密后的数据组成jwt的第二部分。默认定义了一些参数 iss(ssuer):签发人,exp(expiration):过期时间,sub(subject):主题,aud(audience):受众,nbf(not before):生效时间,iat(issued at):签发时间,jti(jwi id):编号。原始数据如下(例):
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
- Signature会根据服务端的密钥和Header中给的算法,对加密后的Header和加密后的Payload再次进行加密,将加密的结果组成jwt的第三部分。加密的逻辑如下:
HMACSHA256( base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret)
- 可以在HTTP的headers中的使用,这样就不会有跨域问题了(因为没有使用cookie):
Authorization:Bearer <token>
参考链接:
JSON Web Token Introduction - jwt.io
参考链接:
JSON Web Token 入门教程 - 阮一峰的网络日志 (ruanyifeng.com)
解密jwt:
JSON Web Tokens - jwt.io
2021-08-19

CAS协议
#
- central authentication service(中央认证服务),TGT(Ticket Grangting Ticket)。TGC(ticket-granting cookie)、ST(service ticket)
- 流程如下(所有的过程都是重定向):
- 用户通过浏览器访问业务系统(就是CAS client,可能是某个微服务)。
- 业务系统重定向到CAS server。
- server对用户进行认证,如用户提供了正确的认证信息,server就会创建对应的session(似乎就是TGT),TGC(cookie)是该session的key,server把TGT和生成的ST发给浏览器。
- 浏览器重新请求该业务系统,同时url上带上了ST=xxx访问业务系统。
- 业务系统拿到ST后,向Server发起校验,校验成功后生成session和cookie,将cookie发送给浏览器。
- 浏览器带上该cookie,不带ST向业务系统发出请求。
- 业务系统验证cookie成功,系统登录成功。
参考链接:
CAS - CAS Protocol (apereo.github.io)
2021-08-17
消息响应
#
101 Switching Protocol
表示正在切换协议。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
成功响应
#
200 OK
请求成功。
201 CREATED
请求已成功,通常是POST、PUT请求后返回的响应。
重定向
#
301 MOVED PERMENENTLY
请求的资源已经被永久移动到新位置。
302 FOUND
重定向是临时的。
304 Not Modified
当文档内容没有修改,服务器会返回这个状态码,304响应禁止包含消息体。
客户端响应
#
400 BAD REQUEST
请求参数有误。
401 UNAUTHORIZED
当前请求需要用户验证。
403 FORBIDDEN
服务器已经理解请求,但是拒绝执行。
404 NOT FOUND
请求资源未找到。
405 Method Not Allowed
请求方法不能被用于请求相应的资源。该响应必须返回一个Allow头用以表述当前资源能够接受的请求方法的列表。
414 URI Too Long
请求的URI长度超过了服务器能够解释的长度,因此服务器拒绝对该请求提供服务。通常是因为超过了GET方法传输数据的上限,可以改为POST方法。
服务端响应
#
500 INTERNAL SERVER ERROR
服务器内部错误。
502 BAD GATEWAY
服务器作为网关需要得到处理该请求的响应,但得到了一个错误的响应。
503 SERVICE UNAVILABLE
服务器没有准备好处理请求。
参考链接:
HTTP 响应代码 - HTTP | MDN (mozilla.org)
2021-08-13
- 支持string、list、set、有序set、hash等数据类型
- 通过
./redis-server [redis.conf]
启动服务。
- 通过
./redis-cli [-h hostname] [-p port]
连接redis,登录后通过AUTH password
来输入密码。
命令
#
keys *
查看当前库中的所有key。
exists key
判断某个key是否存在
rename key newkey
键重命名
- type key 查看key是什么类型
del key
删除指定的key数据
expire key 10
给key设定10秒的过期时间
ttl key
查看还有多少秒过期,-1表示永不过期,-2表示已过期
- select index 切换数据库,默认有16个库
- dbsize 查看当前库key的数量
set key value
设置字符串类型的键值对
get key
获取值
数据类型
#
string
#
set key value
设置值
get key
获取key对应的值
strlen key
获取值的长度。
- mset key1 value1 key2 value2 同时设置多个键值对。
- mget key1 key2 同时获取多个键值对。
- append key value 将给定的value追加到原值的末尾。
- setnx key value 只有当key不存在的时候才设置key的值。
- incr key key的值加一。
- decr key key的值减一。
- incrby key 步长 key的值加步长。
- decrby key 步长 key的值减步长。
- msetnx key1 value1 key2 value2 同时设置多个键值对,当有一个key存在的时候,所有的设置都会失败。
setex key seconds value
设置键值对的同时设置过期时间,单位是秒。
- String内部采用类似arraylist的机制,字符串实际分配的空间一般高于字符串的长度,当字符串长度小于1M时,扩容都是加倍的,超过1M时,每次扩容都是只增加1M。最大为512M。
链表
#
节点的结构
#
//adlist.h/listNode
//结构
typedef struct listNode {
//前置节点
struct listNode *prev;
//后置节点
struct listNode *next;
//节点的值
void *value;
}
- 双端链表,获取节点的前置节点和后置节点的复杂度都是O(1)。
- 无环链表,表头指针的prev和表尾指针的next都是指向NULL。
- list结构的head指针和tail指针能快速获取表头结点和表尾节点,复杂度是O(1)。
- 可以通过list结构的len属性来获取链表中节点的数量,复杂度是O(1)。
命令
#
lpush/rpush k1 v1 v2 v3
从左/右边插入
lpop/rpop k1
从左/又边吐出一个值
lindex key index
按照索引下标获取元素
len key
获得列表的长度
lset key index value
将key的下标为index设置为value
lrange key start stop
按照下标索引获得元素,0表示左边第一个,-1表示右边第一个。
lrem key n value
删除n个value
hash
#
命令
#
hset key field value
设置值
hget key field
获取值
hdel key field[field...]
删除一个或多个键值对
hlen key
计算field的个数
hmget key field [field...]
批量获取
hmset key field value [field value ...]
批量设置
hexists key field
判断field是否存在
hkeys key
获取所有field
hvals key
获取所有value
hstrlen key field
获取value字符串长度
2021-08-12
-
nginx默认的配置文件名是nginx.conf,位置在/usr/local/nginx/conf
、/etc/niginx
、或/usr/local/etc/nginx
。通过nginx -c xxx.conf
来指定配置文件。
-
当nginx启动后,可以通过nginx -s signal
来控制nginx,signal可以是:
- stop:快速关闭;quit:正常关闭;reload:重新加载配置文件;reopen:重新打开配置文件。
-
配置文件可以包含多个server
块,他们之间通过监听的端口和服务名来区分。一旦nginx决定使用哪个服server来处理请求,他就会根据server块内location的指令来匹配请求头中的url,①精确匹配优先级最高,遇到就返回结果;②普通匹配会选择location中前缀最长的那个,和顺序无关;③当location中有正则表达式时,会优先匹配正则表达式(正则级别比普通匹配优先级高,但比精确匹配优先级低),正则表达式的匹配顺序按照文件中的物理顺序匹配,只要匹配到一条正则,就会返回结果;如果没有匹配,就会取普通匹配中最匹配的那个。
-
nginx的错误日志文件在usr/local/nginx/logs
、/var/log/nginx
常用配置
#
proxy_pass
#
- 使用
proxy_pass
来配置代理服务。代理服务的流程:server接收request->把request传给代理服务->获取代理服务的response->把response返回给客户端。
例:
#
server {
listen 80;
#不带 / 结尾:保留 location 匹配的路径,追加到代理地址后
location /api/ {
proxy_pass http://backend; # 请求 /api/test → http://backend/api/test
}
#带 / 结尾:proxy_pass 的 URL 若以 / 结尾,Nginx 会替换 location 匹配的部分。
location /api/ {
proxy_pass http://backend/; # 请求 /api/test → http://backend/test
}
#将会映射到/html/tool这个路径下
location /tool {
root html;
}
#正则表达式以~开始,这里是匹配图片
location ~ \.(gif|jpg|png)$ {
root /data/images;
}
}
参考链接:
Beginner’s Guide (nginx.org)
nginx配置代理yum源和apt源
#
- nginx配置文件中加入如下配置,启动nginx
server {
listen 8803;
#必须要有DNS解析的配置
resolver 114.114.114.114;
location / {
proxy_pass http://$http_host$request_uri;
}
}
- ubuntu中创建/etc/apt/apt.conf文件,填入如下内容
/etc/apt/apt.conf
随后执行apt update
即可完成代理。
Acquire::http::Proxy "http://131.110.99.99:8803/";
- centos或者rocky中,编辑文件
/etc/yum.conf
,加入proxy=http://131.110.99.99:8803
(完整文件如下所示),同时还需要将源配置文件中的https改成httpsed -i 's/https/http/g' /etc/yum.repos.d/*.repo
,随后执行yum makecache
即可。
[main]
proxy=http://131.110.99.99:8803
gpgcheck=1
installonly_limit=3
clean_requirements_on_remove=True
best=True
skip_if_unavailable=False
nginx内嵌的变量
#
#等于在proxy_pass指令中指定的被代理服务的主机名和端口
$proxy_host
#等于在proxy_pass中指定的服务的端口,或者是其服务的默认端口
$proxy_port
#如果X-Forwarded-For属性未在请求头中,$proxy_add_x_forwarded_for的值就等于$remote_addr;
#如果X-Forwarded-For在请求头中,那$proxy_add_x_forwarded_for的值就等于上一个$proxy_add_x_forwarded_for加上",$remote_addr"。
#例:proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
$proxy_add_x_forwarded_for
nginx指令
#
rewrite
#
语法: rewrite regex replacement [flag];
context: server,location,if
rewrite指令按照它出现的顺序来执行,可以通过flag来终止执行,如果replacement以"http://,https://或者$scheme"开始,就会直接返回客户端。
flag可以是last、break、redirect、permanent。
redirect是暂时重定向302,permanent是永久重定向301。
rewrite ^(.*)$ https://localhost$1 permanent;
if
#
语法: if(condition) {...}
context: server, localtion
condition包括:
1. 变量名,当变量为空或者为"0"时是false;
2. 变量和字符串通过"="或者"!="来比较;
3. 变量和正则表达式比较【比较符号: ~(大小写敏感)、~*(大小写)不敏感、!~、!~*】,可以通过()来捕获数据。
4. 使用-f 或!-f检测文件书否存在;
5. 使用-d 或!-d检测目录是否存在;
6. 使用-e 或!-e 检测文件、目录、符号连接是否存在;
7. 使用-x 或!-x 检测是否是可执行文件。
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
}
if ($request_method = POST) {
return 405;
}
return
#
语法: return code [text];
return code URL;
return URL;
context: server,location,if
返回特定的状态码,返回444会不发送响应头就关闭连接。
可以指定一个重定向的URL(301,302,303,307,308),或者响应体text(其他的code)。
set
#
语法: set $variable value;
context: server,location,if
给变量赋值,值可以是变量、字符串或者变量和字符串的组合。