Nginx变更HTTP2配置过程记录

一、背景

最近,业务平台受客户反馈,登录响应很慢,达到50s左右,虽然平台带宽又1G,但是用户上传文件到平台的速率只有40Kb/s左右,业务正常使用受影响严重。

经与研发侧同事沟通,考虑采用http2,因http2再nginx中相较于http1具备较大优势:
在这里插入图片描述
2015 年 5 月 14 日 HTTP/2 协议正式版发布,截至目前已经应用广泛,HTTP 2.0即超文本传输协议 2.0,是下一代HTTP协议。是由互联网工程任务组(IETF)的Hypertext Transfer Protocol Bis (httpbis)工作小组进行开发。是自1999年http1.1发布后的首个更新,HTTP/2 协议是从 SPDY 演变而来,SPDY 已经完成了使命并很快就会退出历史舞台(例如 Chrome 将在「2016 年初结束对 SPDY 的支持」;该协议中,HTTP方法/状态码/语义都与HTTP/1.x一样。HTTP/2基于SPDY3,专注于性能,最大的一个目标是在用户和网站间只用一个连接(connection)。Nginx、Apache 也已经全面支持 HTTP/2 ,并也不再支持 SPDY), HTTP2又可简称为 h2。

HTTP/2 新特性:

1)二进制传输

HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,二进制协议解析起来更高效。HTTP / 1 的请求和响应报文,都由起始行,首部和实体正文(可选)组成,各部分之间是以文本换行符分隔。HTTP/2 将请求和响应数据分割为更小的帧,采用二进制编码,解析将更加高效。

这其中涉及几个重要的概念:

流: 流是连接中的一个虚拟信道,可以承载双向的消息;每个流都有一个唯一的整数标识符(1、2…N);
消息: 是指逻辑上的 HTTP 消息,比如请求、响应等,由一或多个帧组成;
帧: HTTP 2.0 通信的最小单位,每个帧包含帧首部,至少也会标识出当前帧所属的流,承载着特定类型的数据,如 HTTP 首部、负荷等等。

在这里插入图片描述
HTTP/2 中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。

2)多路复用

在 HTTP/2 中引入了多路复用的技术;其很好的解决了浏览器限制同一个域名下的请求数量限制的问题,也更容易实现全速传输,毕竟新开一个 TCP 连接都需要慢慢提升传输速度。 HTTP/2 中不再依赖 TCP 链接去实现多流并行了,h2中:

●同域名下所有通信都在单个连接上完成;
●单个连接可以承载任意数量的双向数据流;
●数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。

这样的好处就是:

●●同个域名只需要占用一个 TCP 连接,使用一个连接并行发送多个请求和响应,消除了因多个 TCP 连接而带来的延时和内存消耗;
●●并行交错地发送多个请求,请求之间互不影响;
●●并行交错地发送多个响应,响应之间互不干扰;
●●在HTTP/2中,每个请求都可以带一个31bit的优先值,0表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。

在这里插入图片描述
3)Header 压缩

在 HTTP/1 中,我们使用文本的形式传输 header,在 header 携带 cookie 的情况下,可能每次都需要重复传输几百到几千的字节。

为减少header资源消耗并提升性能, HTTP/2对首部采取了压缩策略:

●HTTP/2在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送;
●首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
●每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值。

下图中的两个请求,请求1发送了所有的头部字段,请求2则只需发送差异数据,从而减少冗余数据,降低了开销。

在这里插入图片描述
4)Server Push

Server Push即服务端通过push的方式将客户端需要的内容预先推送过去,又称“cache push”。例如服务端可以主动把JS和CSS文件这些静态文件提前推送给客户端,而不需要客户端解析HTML时再发送这些请求。服务端可主动推送,客户端也可选择是否接收。如服务端推送的资源已被浏览器缓存过,浏览器可通过发送RST_STREAM帧来拒收。且主动推送也遵守同源策略,即服务器不能随便将第三方资源推送给客户端,而必须是经过双方确认才行。
在这里插入图片描述

HTTP/1.x的缺陷:

1)连接无法复用: 连接无法复用会导致每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显,慢启动则对大量小文件请求影响较大(没有达到最大窗口请求就被终止)。

HTTP/1.0传输数据时,每次都需要重新建立连接,增加延迟。HTTP/1.1虽然加入keep-alive可以复用一部分连接,但域名分片等情况下仍然需要建立多个connection,耗费资源,给服务器带来性能压力。
2)Head-Of-Line Blocking(HOLB): 导致带宽无法被充分利用,以及后续健康请求被阻塞。HOLB是指一系列包(package)因为第一个包被阻塞;当页面中需要请求很多资源的时候,HOLB(队头阻塞)会导致在达到最大请求数量时,剩余的资源需要等待其他资源请求完成后才能发起请求。

HTTP 1.0: 下个请求必须在前一个请求返回后才能发出,request-response对按序发生。显然,如果某个请求长时间没有返回,那么接下来的请求就全部阻塞了。
HTTP 1.1: 尝试使用 pipeling 来解决,即浏览器可以一次性发出多个请求(同个域名,同一条 TCP 链接)。但 pipeling 要求返回是按序的,那么前一个请求如果很耗时(比如处理大图片),那么后面的请求即使服务器已经处理完,仍会等待前面的请求处理完才开始按序返回。所以,pipeling 只部分解决了 HOLB。

3)协议开销大: HTTP1.x在使用时,header里携带的内容过大,在一定程度上增加了传输的成本,并且每次请求header基本不怎么变化,尤其在移动端增加用户流量。

4)安全因素: HTTP1.x在传输数据时,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份,这在一定程度上无法保证数据的安全性。

二、环境检查

在这里插入图片描述
相关资料表明:openssl的版本必须在1.0.2e及以上、nginx的版本必须在1.9.5以上

如果没有安装的话:

#./configure --prefix=/usr/local/nginx --with-openssl=../openssl-1.0.2e --with-pcre --with-zlib=../zlib-1.2.11 --with-stream --with-stream_ssl_module --with-http_ssl_module --with-http_v2_module --with-threads 
#make
#make install

三、网站的加载过程

a) 首先浏览器请求主页面index.html,服务端响应内容;

b) 获取到主页应答,浏览器开始解析主页的html标签,发现构建DOM树还需要CSS, GIF, JS等资源;

c) 发起针对CSS,GIF,JS的内容请求;

d) 获取并解析JS和CSS等内容, 然后继续请求依赖资源。

四、Nginx HTTP2 配置

1、配置nginx证书,开启https

步骤1: 切换到需要放置证书的目录(选在nginx的conf目录下就可以),建立服务器的私钥(此过程需输入密码短语)

1)openssl genrsa -des3 -out server.key 3072 #默认为1024,可以指定秘钥长度2048字节(bits),输入密码后在步骤3里可去除;genrsa:指定了生成了算法使用RSA,-des3:表示生成的key的密码保护算法采用des3(对称算法加密),加密生产的key算法可取-des|-des3|-idea;
2)openssl dhparam -out dhparam.pem 2048 // DSA算法生成key,需要2步;openssl 生成 2048 位的密钥(DH密钥参数文件),而不是当作参数写入 nginx.conf 文件,即在nginx.conf 中勿配置ssl_dhparam /path/to/dhparam.pem;
或:

openssl dsaparam -out dsaparam.pem 2048 //第一步:使用DSA算法生成2048位的DH私钥,即DH密钥参数文件dhparam.pem,小于1024漏洞会将加密后的转化为纯文本,加密失效,注意dsaparam参数是不支持加密的;
openssl dhparam -in dhparam.pem -text  //查看DH私钥
openssl gendsa -des3 -out privkey.pem dsaparam.pem  //根据生成的参数文件--用DES3加密-生成Key
openssl genrsa -aes256 -out CAkey.pem 4096  //使用RSA算法产生私钥,-aes256——使用256位密钥的AES算法对私钥进行加密,使用PEM(Privacy Enbanced Mail)格式来保存私钥
#可直接使用下面这个
openssl genrsa -aes256 -outprivkey.pem 2048
openssl req -new -nodes -newkey rsa:3096 -keyout server.key -out server.csr 

:openSSL生成私钥过程中,常用的生成算法有RSA及DSA,RSA生成的私钥可以用来加密以及签名,而DSA生成的私钥只可以用来签名;FIPS 186-4规定了三种可用于数据保护的数字签名生成和验证技术:数字签名算法(DSA),椭圆曲线数字签名算法(ECDSA)和Rivest-Shamir Adelman算法( RSA)。OpenSSH 7.0及以上版本默认禁用了ssh-dss(DSA)公钥算法。DSA(用于数字签名算法)的签名生成速度很快,验证速度很慢,加密时更慢,但解密时速度很快,安全性与RSA密钥一般认为相等;但DSA密钥位数生成的原因,同时生成签名时随机性差,可能会泄漏私钥,且以现在机算机的算力,DSA 1024-bit已经实际上可破解,建议不再使用。另外,从商业/实际应用角度来看,RSA更广泛,其中商业RSA证书比DSA证书被更广泛地部署。DSA解密速度通常很快,但加密较慢,而RSA则相反。

Dh(Diffie-Hellman) 是著名的密钥交换协议(一般用于会话密钥),它可以保证通信双方安全地交换密钥。会话密钥就是在本次通信中使用的一次性密钥,当通信结束后密钥就失效了,等下一次建立连接时会生成不同的会话密钥,会话密钥仅在本次通信期内有效。在我们访问https协议的网址,即https://开始的网址时,我们的浏览器会和服务器之间使用SSL/TLS协议进行加密通信,用到的就是会话密钥。会话密钥是存储在客户端和服务器端的内存中的,当通信结束后,会话密钥失效,便会从内存中丢弃。DH(Diffie-Hellman)密钥协商的做法是让通信双方在通信上交换彼此的信息来共同计算出相同的会话密钥,即使中间一部分传递信息被截获,也无法根据其计算出会话密钥,因为计算会话密钥的另一部分信息在接收方处,而接收方并没有公开这部分信息,因此中间方并不会有足够的信息来得到会话密钥,进而破解之后的通信密文。在PEM密钥文件中,其中两个参数:p是一个大质数,g则是一个小整数;通常由服务器端生成DH密钥文件参数,服务器端和客户端都会根据这些参数生成各自的密钥对,然后协商出会话密钥。DH会话加密中这两个私钥是各自生成的,并不会发送出去,即使中间放拿到了客户端和服务器端的公钥以及参数p,g,也没办法计算出会话密钥。如下图所示:
在这里插入图片描述

步骤2: 创建证书签名请求csr


openssl req -new -key cakey.pem -out ca.csr  //生成对应证书请求文件
openssl req -new -key server.key -out server.csr
#更新证书,使用原先的key更新请求文件
openssl req -new -key server.key -out server.csr

步骤3:对于使用上面私钥启动具有ssl功能的nginx,有必要移除输出的密码

cp server.key server.key.org
openssl rsa -in server.key.org -out server.key

步骤4: 使用上面的私钥和CSR对证书进行签名

#自签发根证书,一般使用OpenSSL生成证书时都是v1版,-extensions v3_ca生成v3版
openssl x509 -req -days 365 -sha1 -extensions v3_ca -signkey cakey.pem -in ca.csr -out ca.cer
#自签发服务器证书
openssl x509 -req -days 365 -in server.csr -signkey server.key -out nginx-selfsigned.crt
#验证
openssl x509 -in nginx-selfsigned.crt -noout -text  //证书内容查看
curl -v --cert ./nginx-selfsigned.crt --key ../private/nginx-selfsigned.key -g https://localhost:446/
openssl s_client -quiet -connect localhost:446  //无error返回即成功

v3证书参考:v3根证书添加说明

步骤5:配置nginx

复制代码

server { 
listen 80; 
add_header Strict-Transport-Security max-age=15768000; 
return 301 https://www.yourwebsite.com$request_uri;
}
server {
    listen       443 ssl http2  default_server;  //开启http2
    server_name  localhost;
	# 全站HTTPS(SSL)重定向
    if ($scheme = http ) { 
    return 301 https://$host$request_uri; 
    }
    ssl_certificate     server.crt;
    ssl_certificate_key  server.key;
    ssl_dhparam /path/to/dhparam.pem; ##配置赫尔曼密钥
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 
    ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4'; 
    ssl_prefer_server_ciphers on;   ##使用服务器端的首选算法,缓解 BEAST 攻击
    add_header Strict-Transport-Security max-age=15768000;  ##启用 HSTS,降低中间人攻击的风险
    ssl_session_cache shared:SSL:20m;  ##缓存连接凭据
    ssl_session_timeout 60m;     ##OCSP 缝合
    ssl_stapling on; 
    ssl_stapling_verify on; 
    ssl_trusted_certificate /etc/nginx/cert/trustchain.crt;
    resolver 233.5.5.5 233.6.6.6 valid=300s;
}

保存后,先执行nginx -t检查下配置文件是否书写正确。

我的现场实际:

在这里插入图片描述
上图种第三行有错误:

在这里插入图片描述

步骤6:测试

wget https://codeload.github.com/nghttp2/nghttp2/zip/master
wget  https://curl.haxx.se/download/curl-7.53.1.tar.gz
nzip nghttp2-master.zip
cd nghttp2-master
autoreconf -i
automake
autoconf
./configure
make
sudo make install

在这里插入图片描述
安装curl

https://curl.haxx.se/download/curl-7.53.1.tar.gz
tar -zxvf curl-7.53.1.tar.gz
cd curl-7.53.1
./configure --with-nghttp2=/usr/local --with-ssl
make
验证:
curl --version
curl --http2 -v https://192.168.0.1/a.jpg -k

输入有……Using HTTP2, server supports multi-use……"说明是用了http2

浏览器测试:

在 Chrome 浏览器上可以通过,HTTP/2 and SPDY indicator 来检验,如果地址栏出现蓝色的闪电就是 h2

也可以在打开浏览器事件日志记录:chrome://net-export/
在这里插入图片描述
查看json日志:有http2相关信息

或者chrome浏览器启用插件:HTTP/2 and SPDY indicator,安装完毕后访问启用HTTP2的站点,如果地址栏出现蓝色的闪电,说明站点已启用HTTP2。
在这里插入图片描述
在这里插入图片描述
或者开发者模式,打开协议选项:
在这里插入图片描述

2、改造前后效果:

在这里插入图片描述
在这里插入图片描述

改造后:
在这里插入图片描述
在这里插入图片描述
慢的话:
在这里插入图片描述
3、安全性验证

测试网站:https://myssl.com/
在这里插入图片描述
在这里插入图片描述

五、移动云SSL证书

在这里插入图片描述

1)移动云购买SSL证书+云解析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对于OV/EV类证书,还需要盖章上传企业信息:
在这里插入图片描述

SSL证书提交申请后,您需要进行域名授权验证。按照CA中心的规范,如果您申请了数字证书,您必须配合完成域名验证来证明您对所申请绑定的域名的所有权。当您按照要求正确配置域名验证信息,待域名授权验证完成,CA系统中心审核通过后,证书审核才可以进入下一个状态。 如果不完成域名验证,您的证书将无法通过审核,且您的证书申请将会一直显示如下状态:待域名确认、待CA人工审核、待DNS验证。添加DNS记录,否则无法通过CA侧验证,无法及时下发证书:

在这里插入图片描述
对应填写以下内容:
在这里插入图片描述
在这里插入图片描述
2)证书下载和配置

如果申请证书时,“CSR生成”选择“在线生成”,证书下载后会有三个文件:可同时下载到证书、证书链、私钥3个文件。
在这里插入图片描述
使用证书格式在线转化工具将上述证书文件转换成 Nginx服务器对应的格式:
在这里插入图片描述
之后下载会得到2个文件:“server.crt”、“server.key”
在这里插入图片描述

打开nginx的证书认证文件把“server.crt”、“server.key”拷贝到“cert”目录下,然后修改nginx配置文件:

server {
        listen       443 ssl; #配置HTTPS的默认访问端口为443。如果在此处未配置HTTPS的默认访问端口,可能会导致Nginx无法启动。
        server_name  www.domain.com; #修改为您证书绑定的域名。
        ssl_certificate      cert/server.crt; #替换成您的证书文件的路径。
        ssl_certificate_key  cert/server.key; #替换成您的私钥文件的路径。
        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;
        ssl_ciphers  HIGH:!aNULL:!MD5; #加密套件。
        ssl_prefer_server_ciphers  on;
        location / {
            root   html; #站点目录。
            index  index.html index.htm; #添加属性。
                   }  
}

然后执行:nginx -s reload

3)浏览器验证域名证书效果:

在这里插入图片描述

附录:关于301跳转得说明

一.301跳转的含义

页面永久性移走,通常叫做301跳转,也叫301重定向,301转向.指的是当用户点击一个网址时,通过技术手段,跳转到指定的一个网站.

二.为何网站要做301跳转

1、当你需要更换网站域名或者多个域名指向同一网站的时候,建议使用301重定向,如果使用JS跳转、MATAREFRESH或302转向,这样很容易遭到搜索引擎的惩罚。

2、当你使用301重定向把地址指向新的域名后,搜索引擎只对新网址进行索引,同时又会把旧地址下原有的外部链接转移到新地址下,从而不会让网站的排名因为网址变更而收到影响。同样,在使用301永久性重定向命令让多个域名指向网站主域名时,也不会对网站的排名产生任何不良影响。

3、301重定向可促进搜索引擎优化效果从搜索引擎优化角度出发,301重定向是网址重定向最为可行的一种办法。当网站的域名发生变更后,搜索引擎只对新网址进行索引,同时又会把旧地址下原有的外部链接如数转移到新地址下,从而不会让网站的排名因为网址变更而收到丝毫影响。同样,在使用301永久性重定向命令让多个域名指向网站主域时,亦不会对网站的排名产生任何负面影响。

三、301跳转的优势

(1) 301转向传递权重

网页A用301重定向转到网页B,搜索引擎可以肯定网页A永久性改变地址,或者说实际上不存在了,搜索引擎就会把网页B当做唯一有效的目标。这是搜索引擎唯一推荐的不会产生怀疑的转向方法,最重要的是,网页A累积的页面权重被传到网页B。

做301转向目前Google会传递大部分网址权重,但不是百分之百权重。百度会传递所有权重。Google对301的识别、反应、完成权重传递,需要1-3个月的时间。百度对301处理则比较保守,新旧URL会同时存在于数据库很长的时间,经常看到做了301转向一年的URL还出现在百度结果中。

(2)301重定向可促进搜索引擎优化效果

从搜索引擎优化角度出发,301重定向是网址重定向最为可行的一种办法。当网站的域名发生变更后,搜索引擎只对新网址进行索引,同时又会把旧地址下原有的外部链接如数转移到新地址下,从而不会让网站的排名因为网址变更而收到丝毫影响。同样,在使用301永久性重定向命令让多个域名指向网站主域时,亦不会对网站的排名产生任何负面影响

(3)301重定向的本意就是避免原来的流量丢失

毫无疑问,完全不在乎SEO的站长做301重定向的做法其实是为了避免原来旧域名的流量丢失;赢之网络也得到过同样的“实验”,最终还让百度难以分析旧域名权重高还是新域名权重高,而且旧域名还与新域名有过一段竞争史(并不是在搜索结果中有两个排名哦,而是百度只让一个旧域名的某些关键词出现在搜索结果中,新域名真真正正在搜索结果中任何关键词都看不到排名呢!);当时给站长一种信号就是永远依赖旧域名的301重定向,结果将旧域名的301重定向取消跳转后,经过一个星期的流量丢失后,百度才恢复过来;百度一直提倡SEOer考虑排序算法的最直接的目标就是用户体验,所以,301重定向并非是权重分配或转向的SEO最佳做法,其本意就是避免原来旧域名的流量丢失。

附录2:Chrome Dev Tool 中时间线各阶段代表的意义
在这里插入图片描述
Stalled/Blocking
在请求能够被发出去前的等等时间。包含了用于处理代理的时间。另外,如果有已经建立好的连接,那么这个时间还包括等待已建立连接被复用的时间,这个遵循Chrome对同一源最大6个TCP连接的规则。

「拿我们的情况来说,上面出错所有的耗时也是算在了这部分里面。网络面板中显示的其余时间比如DNS查找,连接建立等都是属于最后那次成功请求的了」

Proxy Negotiation
处理代理的时间。

DNS Lookup
查找DNS的时间。页面上每个新的域都需要一次完整的寻路来完成DNS查找。

Initial Connection / Connecting
用于建立链接的时间,包括TCP握手及多次尝试握手,还有处理SSL。

SSL
完成SSL握手的时间。

Request Sent / Sending
发起请求的时间,通常小到可以忽略。

Waiting (TTFB)
等待响应的时间,具体来说是等待返回首个字节的时间。包含了与服务器之间一个来回响应的时间和等待首个字节被返回的时间。

Content Download / Downloading
用于下载响应的时间

附录3:HTTP3认识及与HTTP2中的比较

HTTP/2 解决了HTTP1的一些问题,但它还有一个巨大的问题是,其底层依赖 TCP 协议的支撑。HTTP/2中 使用了多路复用技术,这样同一域名下只需要使用一个 TCP 连接,但有个问题,当这个连接中出现了丢包的情况,整个 TCP 都要开始等待重传,就导致了后面的所有数据都被阻塞了。而对于老版本 HTTP/1.1 ,因其可以开启多个 TCP 连接,上述场景只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据,这样 HTTP/2 的表现反倒不如 HTTP/1 了。基于此,Google 提出了一个基于 UDP 协议的 QUIC 协议,也就是我们的HTTP/3 ,HTTP/3 原名为 HTTP-over-QUIC,其基于 UDP,不在受TCP影响。

新特性如下:

1)0-RTT:
在这里插入图片描述

如上图所示,可在两层建立连接:
●传输层 0RTT 就能建立连接。
●加密层 0RTT 就能建立加密连接
上图左侧是 HTTPS 的一次完全握手的建连过程,需要 3 个 RTT,就算是会话复用也需要至少 2 个 RTT。右侧的 QUIC ,由于建立在 UDP 的基础上,同时又实现了 0RTT 的安全握手,正常只需要 0 个 RTT 就能实现数据发送,使用类似 TCP 快速打开的技术,缓存当前会话的上下文,在下次恢复会话的时候,只需要将之前的缓存传递给服务端验证通过就可以进行传输了。0RTT 建连可认为是 QUIC 相比 HTTP2 最大的性能优势。
2)多路复用
虽 HTTP/2 中支持了多路复用,但是其依赖的底层TCP 协议不支持多路复用,但QUIC 原生支持这个功能,这样传输的单个数据流可以保证有序交付且不会影响其他的数据流,

同HTTP2.0一样,一条 QUIC连接上也可以创建多个stream,来发送多个HTTP请求,但QUIC是基于UDP的,一个连接上的多个stream之间没有依赖。如下图中stream2丢了一个UDP包,不会影响后面跟着 Stream3 和 Stream4,不存在 TCP 队头阻塞。虽然stream2的那个包需要重新传,但是stream3、stream4的包无需等待,就可以发给用户。另外QUIC 在移动端的表现也会比 TCP 好。因为TCP 是基于 IP 和端口去识别连接的,这种方式在多变的移动端网络环境下是很脆弱的。但 QUIC 是通过 ID 的方式去识别一个连接,无论你网络环境如何变化,只要 ID 不变,就能迅速重连。
在这里插入图片描述
3)加密认证的报文
TCP 协议头部没有经过任何加密和认证,所以在传输过程中很容易被中间网络设备篡改,注入和窃听。比如修改序列号、滑动窗口。这些行为有可能是出于性能优化,也有可能是主动攻击。但QUIC 的 packet 除个别报文比如 PUBLIC_RESET 和 CHLO,所有报文头部都是经过认证的,报文 Body 都是经过加密的。这样只要对 QUIC 报文任何修改,接收端都能够及时发现,有效地降低了安全风险。

下图中是Quic帧的封装示意,红色部分是 Stream Frame 的报文头部,有认证。绿色部分是报文内容,全部经过加密。

在这里插入图片描述
4)向前纠错机制
QUIC使用了FEC,即向前纠错 (Forward Error Correction,FEC),每个数据包除了它本身的内容之外,还包括了部分其他数据包的数据,这样少量的丢包可通过其他包的冗余数据进行直接组装而无需重传。向前纠错牺牲了每个数据包可以发送数据的上限,但是减少了因为丢包导致的数据重传,因为数据重传将会消耗更多的时间(包括确认数据包丢失、请求重传、等待新数据包等步骤的时间消耗)。

假如说这次我要发送三个包,那么协议会算出这三个包的异或值并单独发出一个校验包,也就是总共发出了四个包。当出现其中的非校验包丢包的情况时,可以通过另外三个包计算出丢失的数据包的内容。当然这种技术只能使用在丢失一个包的情况下,如果出现丢失多个包就不能使用纠错机制了,只能使用重传的方式了。

六、web服务其他优化

HTTP2 Server Push简单来说,就是webserver不需要用户请求,直接推送文件到浏览器,由于推送没有暂停功能,需要利用cookie防止重复推送;服务推送是HTTP2协议的优点之一。

配置示例:

 header("Link: </css/styles.css>; rel=preload; as=style", false);  //php代码
Header set Link "</css/styles.css>; rel=preload; as=style"  //apache配置
add_header Link "<//lib/Peafowl/js/scripts.min.js>; rel=preload; as=script";  //nginx配置
## 以下是Nginx的配置示例
//http段添加
http2_push_preload on; ##开启主动推送
add_header Set-Cookie "http2push=1";
add_header Link $resources;
//server段添加
http2_recv_buffer_size 512k;   ##超过缓存会出错, 建议加大缓存,或者只加载css/js
map $http_cookie $resources {
    "~*http2push=1" "";
    default "</lib/Peafowl/peafowl.min.css>; rel=preload; as=style, </app/themes/Peafowl/style.min.css>; rel=preload; as=style, </lib/Peafowl/js/scripts.min.js>; rel=preload; as=script, </lib/Peafowl/peafowl.min.js>; rel=preload; as=script, </app/lib/main.min.js>; rel=preload; as=script";
}

1)HTTP/2之服务器推送(Server Push)最佳实践https://blog.csdn.net/wetest_tencent/article/details/80133278
如果服务端接收到客户端主请求,能够“预测”主请求的依赖资源,在响应主请求的同时,主动并发推送依赖资源至客户端。客户端解析主请求响应后,可以”无延时”从本地缓存获取依赖资源, 减少访问延时, 提高访问体验,也加大了链路的并发能力。Server Push正是基于此原理来提高网络体验。

相关实例表明:若采用服务端推送的功能,则JS/CSS资源基本可以和HTML资源同步到达,浏览器可以“无延时”获取JS/CSS资源,客户端的延时最多可以减少一个RTT。

七、附录

7.1、DSA和RSA加密算法的区别

DSA和RSA都是需要公钥和私钥的加密算法。

1)密钥分为两种:对称密钥与非对称密钥;

对称密钥加密:又称私钥加密,即信息的发送方和接收方用一个密钥去加密和解密数据。它的最大优势是加/解密速度快,适合于对大数据量进行加密,但密钥管理困难。

非对称密钥加密系统:又称公钥密钥加密。它需要使用一对密钥来分别完成加密和解密操作,一个公开发布,即公开密钥,另一个由用户自己秘密保存,即私用密钥。信息发送者用公开密钥去加密,而信息接收者则用私用密钥去解密。公钥机制灵活,但加密和解密速度却比对称密钥加密慢得多。

2)加密算法:

加密算法可以分为对称加密、非对称加密和不可逆加密三类算法。

对称加密: 采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密。也称为单密钥加密。
非对称加密: 采用双钥密码系统的加密方法,在一个过程中使用两个密钥,一个用于加密,另一个用于解密。也称为公钥加密,因为其中一个密钥是公开的(另一个则需要保密)。

3)常用的对称加密有:

DES、 IDEA、 RC2、 RC4、 SKIPJACK、 RC5、 AES 算法等。

DSA是对称加密算法,是基于整数有限域离散对数难题的,其安全性与RSA相比差不多 。

RSA是非对称加密算法,在网络容易实现密钥管理,便进行数字签名,算法复杂,加/解速度慢。比起 DES 和其它对称算法来说,速度一直是 RSA 的缺陷。一般来说只用于少量数据加密(比如网页登录)。RSA 的速度是对应同样安全级别的对称密码算法的1/1000左右。

DSA只能用于签名,而RSA可以用于签名/加密/解密。

秘钥名称密钥长度运行速度安全性资源消耗
DES56位较快
3DES112位或168位
AES128、192、256位
名称成熟度安全性运算速度资源消耗
RSA
ECC
算法类型密钥管理安全性加密速度
对称算法比较难,不适合互联网,一般用于内部系统快好 几个数量级 (软件加解密速度至少快 100 倍,每秒可以加解密数 M 比特 数据),适合大数据量的加解密处理
非对称算法密钥容易管理比较慢,适合 小数据量 加解密或数据签名

4)椭圆加密算法(ECC):
它是一种公钥加密算法,最初由 Koblitz 和 Miller 两人于1985年提出,其数学基础是利用椭圆曲线上的有理点构成 Abel 加法群上椭圆离散对数的计算困难性。公钥密码体制根据其所依据的难题一般分为三类:大整数分解问题类、离散对数问题类、椭圆曲线类。有时也把椭圆曲线类归为离散对数类。

ECC 的主要优势是在某些情况下它比其他的方法使用更小的密钥 (比如 RSA),提供相当的或更高等级的安全,有研究表示160位的椭圆密钥与1024位的 RSA 密钥安全性相同。ECC 的另一个优势是可以定义群之间的双线性映射,基于 Weil 对或是 Tate 对;双线性映射已经在密码学中发现了大量的应用,例如基于身份的加密。不过一个缺点是加密和解密操作的实现比其他机制花费的时间长。但在私钥的加密解密速度上,ECC 算法比 RSA、DSA 速度更快,存储空间占用小,带宽要求低。

ECC 被广泛认为是在给定密钥长度的情况下,最强大的非对称算法,因此在对带宽要求十分紧的连接中会十分有用。

Java 中 Chipher、Signature、KeyPairGenerator、KeyAgreement、SecretKey 均不支持 ECC 算法。

5)DH算法:

DH,全称为"Diffie-Hellman(迪菲-赫尔曼)",它是一种确保共享 KEY 安全穿越不安全网络的方法,也就是常说的密钥一致协议。由公开密钥密码体制的奠基人 Diffie 和 Hellman 所提出的一种思想。简单的说就是允许两名用户在公开媒体上交换信息以生成"一致"的、可以共享的密钥。也就是由甲方产出一对密钥 (公钥、私钥),乙方依照甲方公钥产生乙方密钥对 (公钥、私钥)。

以此为基线,作为数据传输保密基础,同时双方使用同一种对称加密算法构建本地密钥 (SecretKey) 对数据加密。这样,在互通了本地密钥 (SecretKey) 算法后,甲乙双方公开自己的公钥,使用对方的公钥和刚才产生的私钥加密数据,同时可以使用对方的公钥和自己的私钥对数据解密。不单单是甲乙双方两方,可以扩展为多方共享数据通讯,这样就完成了网络交互数据的安全通讯。

7.2、加密和数字证书相关概念

1) 信息加密

收信者是唯一能够解开加密信息的人,因此收信者手里的必须是私钥。发信者手里的是公钥,其它人知道公钥没有关系,因为其它人发来的信息对收信者没有意义。

2) 登录认证

客户端需要将认证标识传送给服务器,此认证标识 (可能是一个随机数) 其它客户端可以知道,因此需要用私钥加密,客户端保存的是私钥。服务器端保存的是公钥,其它服务器知道公钥没有关系,因为客户端不需要登录其它服务器。

3) 数字签名

数字签名是为了表明信息没有受到伪造,确实是信息拥有者发出来的,附在信息原文的后面。就像手写的签名一样,具有不可抵赖性和简洁性。

简洁性:对信息原文做哈希运算,得到消息摘要,信息越短加密的耗时越少。

不可抵赖性:信息拥有者要保证签名的唯一性,必须是唯一能够加密消息摘要的人,因此必须用私钥加密 (就像字迹他人无法学会一样),得到签名。如果用公钥,那每个人都可以伪造签名了。

4) 数字证书:可以简单认为就是公钥

问题起源:对1和3,发信者怎么知道从网上获取的公钥就是真的?没有遭受中间人攻击?

这样就需要第三方机构来保证公钥的合法性,这个第三方机构就是 CA (Certificate Authority),证书中心。CA 用自己的私钥对信息原文所有者发布的公钥和相关信息进行加密,得出的内容就是数字证书。

信息原文的所有者以后发布信息时,除了带上自己的签名,还带上数字证书,就可以保证信息不被篡改了。信息的接收者先用 CA给的公钥解出信息所有者的公钥,这样可以保证信息所有者的公钥是真正的公钥,然后就能通过该公钥证明数字签名是否真实了。

7.3、RSA算法的工作流程

比如对称加密场景中,首先由 server 随机确定一个 KEY,称之为私钥,将这个 KEY 始终保存在server中而不发出来;然后,由这个 KEY 计算出另一个 KEY,称之为公钥。但这个公钥的特性是几乎不可能通过它自身再反推计算生成与server一样的私钥的。之后server上服务就可通过网络把这个公钥传给 client,client 收到公钥后,利用公钥对信息加密,并把密文通过网络发送到 server,最后 server 利用本地的私钥,就能对密文进行解码了。

7.4、禁用不安全的 HTTP 方法

仅保留 GET、POST 方法,可以在nginx配置文件 server 下进行全局设置,也可以在某个location下进行设置。

全局设置方式:

if ($request_method ~ ^(PUT|DELETE)$) {      ##或者!~ ^(GET|POST)$)
            return 403;
        }

局部设置方式:


location /review {
        include /usr/local/nginx/allow_ip_list.conf;
        if ($request_method = PUT ) {
                return 403;
        }
 
        if ($request_method = DELETE ) {
                return 403;
        }
        if ($request_method = OPTIONS ) {
                return 403;
        }
        if ($request_method = TRACE ) {
                return 403;
        }
        proxy_pass http://review;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

7.5、Https请求过程

要解决http带来的问题,就要引入加密以及身份验证机制。服务器把数据加密后,客户端如何读懂这些数据呢?

这时服务器必须要把加密的密钥(对称密钥,后面会详细说明)告诉客户端,客户端才能利用对称密钥解开密文的内容。服务器如果将这个对称密钥以明文的方式给客户端,还是会被中间人截获,中间人也会知道对称密钥,依然无法保证通信的保密性。但是,如果服务器以密文的方式将对称密钥发给客户端,客户端又如何解开这个密文,得到其中的对称密钥呢?

这里的密钥,指的是非对称加解密的密钥,是用于TLS握手阶段的; 对称密钥,指的是对称加解密的密钥,是用于后续传输数据加解密的。

在非对称加解密算法里,公钥加密的数据,有且只有唯一的私钥才能够解密,所以服务器只要把公钥发给客户端,客户端就可以用这个公钥来加密进行数据传输的对称密钥。客户端利用公钥将对称密钥发给服务器时,即使中间人截取了信息,也无法解密,因为私钥只部署在服务器,其他任何人都没有私钥,因此,只有服务器才能够解密。服务器拿到客户端的信息并用私钥解密之后,就可以拿到加解密数据用的对称密钥,通过这个对称密钥来进行后续通信数据加解密

非对称加密可以很好的管理对称密钥,保证每次数据加密的对称密钥都是不相同的,这样子的话,即使客户端病毒拉取到通信缓存信息,也无法窃取正常通信内容。
在这里插入图片描述
在这里插入图片描述

为防止中间人(伪造公钥)获取对称密钥,引入了数字证书的概念。服务器首先生成公私钥,将公钥提供给相关机构(CA),CA将公钥放入数字证书并将数字证书颁布给服务器,此时服务器就不是简单的把公钥给客户端,而是给客户端一个数字证书,数字证书中加入了一些数字签名的机制,保证了数字证书一定是服务器给客户端的。中间人发送的伪造证书,不能够获得CA的认证,此时,客户端和服务器就知道通信被劫持了。加入了CA数字签名认证的SSL会话过程如下所示:
在这里插入图片描述
故,HTTPS的安全实现:非对称加密算法(公钥和私钥)交换对称密钥+数字证书验证身份(验证公钥是否是伪造的)+利用对称密钥加解密后续传输的数据=安全
在这里插入图片描述
https协议中身份认证的部分是由CA数字证书完成的,证书由公钥、证书主体、数字签名等内容组成。在客户端发起SSL请求后,服务端会将数字证书发给客户端,客户端会对证书进行验证(验证这张证书是否是伪造的?也就是公钥是否是伪造的),如果证书不是伪造的,客户端就获取用于对称密钥交换的非对称密钥(获取公钥)。

数字证书有三个作用:

1)身份授权。确保浏览器访问的网站是经过CA验证的可信任的网站。
2)分发公钥。每个数字证书都包含了注册者生成的公钥(验证确保是合法的,非伪造的公钥)。在SSL握手时会通过certificate消息传输给客户端。
3)验证证书合法性。客户端接收到数字证书后,会对证书合法性进行验证。只有验证通过后的证书,才能够进行后续通信过程。

申请一个受信任的CA数字证书通常有如下流程:

1)公司(实体)的服务器生成公钥和私钥,以及CA数字证书请求。
2)RA(证书注册及审核机构)检查实体的合法性(在注册系统里面是否注册过的正规公司)。

3)CA(证书签发机构)签发证书,发送给申请者实体。

4)证书更新到repository(负责数字证书及CRL内容存储和分发),实体终端后续从repository更新证书,查询证书状态等。

申请者拿到CA的证书并部署在网站服务器端,那浏览器发起握手并接收到证书后,如何确认这个证书就是CA签发的呢?怎样避免第三方伪造这个证书?答案就是数字签名(digital signature)。数字签名是证书的防伪标签,目前使用最广泛的SHA-RSA(SHA用于哈希算法,RSA用于非对称加密算法)。数字签名的制作和验证过程如下:

1)首先是使用哈希函数对待签名内容进行安全哈希,生成消息摘要,然后使用CA自己的私钥对消息摘要进行加密。
2)使用CA的公钥解密签名,然后使用相同的签名函数对签名证书内容进行签名,并和服务端数字签名里的签名内容进行比较,如果相同就认为校验成功。
在这里插入图片描述
更多详情参见: HTTPS 连接建立全过程
在这里插入图片描述

1、客户端发送请求https连接。
2、服务器返回加密公钥,通常是SSL证书。
3、客户端从这个SSL证书解析出公钥,并随机生成一个key,通过公钥加密这个key发送给服务器(这一步是安全的因为只有服务器才有私钥能读出这个key)。
4、服务器通过私钥解密出key。
5、客户端使用这个key来加密需要传输的数据。
6、服务器使用key来解析数据。

简单的来说SSL加密的方式是使用一个密钥来加密另一个密钥(key),在使用被加密的密钥来加密数据。这样的做法固然保证了安全性,但每次连接时都需要使用密钥加密,导致请求会需要额外的开销,同时服务器第一次返回的公钥的可靠性需要第三方来保证,通常是购买SSL证书。这也会造成额外的经济开销。

7.6、SSL转换工具

sslTools:https://47.100.74.77:8443/#/
在这里插入图片描述

7.7、RSA与ECC加密算法的区别

我们已知,RSA加密算法和ECC加密算法是目前主要流行的两种SSL证书公钥加密算法;那这2种算法的区别:

1、RSA加密算法:是一种国际通用的加密算法,应用比较早,基于公钥和私钥对通过互联网发送的信息进行加密和解密,兼容性更好,一般采用2048位加密长度,服务器性能消耗较高。据最新行业标准要求从2021年6月1日起,公开可信代码签名和时间戳证书的最低密钥要求是3072位RSA。知名CA机构DigiCert从上个月27号开始便对重新颁发、续订的代码签名证书采用至少3072位RSA密钥,提高对签名代码的信任。

2、ECC加密算法:ECC(椭圆曲线密码术)是一种公共密钥密码系统,在代数中采用了椭圆曲线理论,旨在在数字签名,伪随机生成器,加密等领域提供有效的安全性。一般采用256位加密长度(相当于RSA 3072位加密强度)更安全,抗攻击型更强,同比RSA算法加密速度快,效率更高,服务器资源消耗更低。ECC加密算法作为新一代算法主流,其加密速度快、效率高、抗攻击能力强,可以用较少的计算能力提供比RSA加密算法更高的安全强度,但兼容性方面还没有RSA算法广泛。
在这里插入图片描述
如果您既想要有RSA加密算法的广泛兼容性,又想要ECC加密算法的高效快捷和安全性,那么可选择部署支持双算法的SSL证书。

7.8、对称加密和非对称加密

在对称加密中,信息的加解密使用同一秘钥key,其可简化加解密的过程,较为简单,但不足之处在于由于加解密使用同一个key,信息传送双方都要接触这个key,密钥key更容易泄露。

在公开密钥加密即非对称加密中,密钥分为公钥PK(发送方通过PK对数据加密,然后发送给接收方,PK可公开),私钥SK(SK解密方保存,接收方通过SK对密文解密,SK不公开)。RSA公钥密码体制是最具代表性的非对称加密方式。

7.9、 http 强制跳转 https

编辑机nginx配置文件,可看到一半http配置的 server如下:

server {
	listen       80;
	server_name  www.blue.com.cn;

跳转到https可如下这样操作,在这两行的下面添加:

方法一:(这是最古老的写法,不推荐)

rewrite ^(.*)$  https://$host$1 permanent;

方法二: (推荐)

return  301 https://$server_name$request_uri; #页面永久性移走,即使用301重定向

方法三: 如果你有多个域名绑定在一起,可只设定某些域名访问时才强制跳转

if ($host = “1.dyseo.com.cn”) {

rewrite ^/(.*)$ https://1.dyseo.com.cn permanent;

}

方法四: 配置监听 https的 443 端口的 server,注意不同于分2段server来监听,如下

listen 80;

listen 443 ssl http2;

server_name dyseo.com.cn www.dyseo.com.cn;

if ($server_port !~ 443){

rewrite ^(/.*)$ https://$host$1 permanent;

7.10、配置服务器减轻被非法域名恶意解析

思路:

web端服务以非80端口启动(无法直接通过IP地址访问到),Nginx配置一层正向代理,将域名转发到域名+端口。
这样,解析后使用自己的域名可以直接访问,即可成功转发到了ip地址+端口。而其他域名没有配置端口转发,所以会被拦截下来。

1)Apache
在httpd.conf主配置文件里里添加以下配置并重启Apache服务即可

#apache2.2.x版本:
     <VirtualHost _default_:80>
        ServerName *
        ServerAlias *
       RewriteEngine on
RewriteRule ^(.*)$ sttp://127.0.0.1/ [R,L]
    </VirtualHost>
#apache2.4.x版本:
   <VirtualHost  _default_:80>
      RewriteEngine on
      RewriteRule ^(.*) sttp://127.0.0.1 [L]
   </VirtualHost>

2)Nginx
在nginx.conf中添加以下内容并重启Nginx服务即可

server{
listen *:80 default;
server_name _;
access_log  off;
rewrite ^(.*) sttp://127.0.0.1 permanent;
return    444;
}

八、脚本创建证书

1)生成CA证书

#!/bin/sh

# 生成私钥 key 文件
openssl genrsa -aes 256 -out private/cakey.pem 4096

# 生成证书请求 csr 文件
openssl req -new -key private/cakey.pem -out private/ca.csr -extensions v3_req -config "./conf/openssl.cnf"

# 生成证书 crt 文件
openssl x509 -req -days 3650 -in private/ca.csr -signkey private/cakey.pem -out private/ca.crt

# 为CA key 设置起始序列号和创建 CA 键库
echo '01' > serial   # 可以是任意四个字符
touch index.txt

# 为 "用户证书" 的移除创建一个证书撤销列表
openssl ca -gencrl -out ./private/ca.crl -crldays 7 -config "./conf/openssl.conf"

2)创建服务侧证书

#!/bin/sh

# 查看KEY信息
# openssl rsa -noout -text -in users/client.key
# 查看CSR信息
# openssl req -noout -text -in users/client.csr
# 查看证书信息
# openssl x509 -noout -text -in users/client.crt


########## CA证书 ##########

# 生成私钥 key 文件
openssl genrsa -out private/ca.key 2048

# 生成证书请求 csr 文件
openssl req -new -key private/ca.key -out private/ca.csr -extensions v3_req -config "./conf/openssl.cnf"

# 生成凭证 crt 文件
openssl x509 -req -days 365 -extensions v3_req -in private/ca.csr -signkey private/ca.key -out private/ca.crt

# 为我们的 key 设置起始序列号和创建 CA 键库
echo FACE > serial   # 可以是任意四个字符
touch index.txt

# 为 "用户证书" 的移除创建一个证书撤销列表
openssl ca -gencrl -out ./private/ca.crl -crldays 7 -config "./conf/openssl.conf"

########## 服务器证书 ##########

# 创建一个 key
openssl genrsa -aes256 -out server/server.key 2048

# 为我们的 key 创建一个证书签名请求 csr 文件
openssl req -new -key server/server.key -out server/server.csr -extensions v3_req -config "./conf/openssl.cnf"

# 使用我们私有的 CA key 为刚才的 key 签名
openssl ca -extensions v3_req -in server/server.csr -cert private/ca.crt -keyfile private/ca.key -out server/server.crt -config "./conf/openssl.conf"

########## 客户端证书 ##########

# 为用户创建一个 key
openssl genrsa -des3 -out ./users/client.key 2048

# 为 key 创建一个证书签名请求 csr 文件
openssl req -new -key ./users/client.key -out ./users/client.csr -extensions v3_req -config "./conf/openssl.conf"

# 使用我们私有的 CA key 为刚才的 key 签名
openssl ca -extensions v3_req -in ./users/client.csr -cert ./private/ca.crt -keyfile ./private/ca.key -out ./users/client.crt -config "./conf/openssl.conf"

# 将证书转换为大多数浏览器都能识别的 PKCS12 文件
openssl pkcs12 -export -clcerts -in ./users/client.crt -inkey ./users/client.key -out ./users/client.p12

3)客户端证书

#!/bin/sh

# 为用户创建一个 key
openssl genrsa -des3 -out ./users/client.key 2048

# 为 key 创建一个证书签名请求 csr 文件
openssl req -new -key ./users/client.key -out ./users/client.csr -extensions v3_req -config "./conf/openssl.onf"

# 使用我们私有的 CA key 为刚才的 key 签名
openssl ca -extensions v3_req -in ./users/client.csr -cert ./private/ca.crt -keyfile ./private/ca.key -out ./users/client.crt -config "./conf/openssl.cnf"

# 将证书转换为大多数浏览器都能识别的 PKCS12 文件
openssl pkcs12 -export -clcerts -in ./users/client.crt -inkey ./users/client.key -out ./users/client.p12
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

羌俊恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值