关于nginx的搭建配置具体参考笔者之前的一篇文章:实时流媒体服务器搭建试验(nginx+rtmp)_如何在线测试流媒体rtmp搭建成功了吗-CSDN博客中的前半部分;唯一变化的是编译参数(添加stream模块并添加其对应ssl模块):
./configure --prefix=/usr/local/nginx --with-http_stub_status_module \
--with-http_ssl_module --with-stream --with-stream_ssl_module \
--with-stream_realip_module --with-openssl=../openssl-1.0.1f --without-http_gzip_module
在配置文件nginx.conf中增加stream模块的配置,具体如下:
# lijd add 2023-11-4
stream {
upstream backend {
server 192.168.97.50:54321;
}
server {
listen 12345 ssl;
proxy_connect_timeout 60s;
proxy_timeout 60s;
proxy_pass backend;
}
}
# lijd add end
说明:真是的tcp服务器为:192.168.97.50,端口:54321;nginx代理服务器地址为:192.168.97.51,端口:12345。实验结果截图如下:
当本地客户端(192.168.80.67)连接代理服务器192.168.97.51的12345端口时,nginx的代理进程会与真实的后台服务器(192.168.97.50)的54321端口创建一个tcp连接,如下图:
客户端与服务器之间的通信成功连接并发送数据,演示如下图:
首先通过系统自带的openssl生成一套自己的CA跟服务器证书、客户端证书,具体命令如下:
==============================生成CA相关内容===============================
# 为CA生成私钥
openssl genrsa -out private/ca.prikey 2048
# 为CA机构生成公钥
openssl rsa -in ca.prikey -pubout -out ca.pubkey
# 为CA生成自签名证书
openssl req -new -x509 -days 3650 -key private/ca.prikey -out ca.cert
===========================生成服务器证书相关内容============================
# 生成服务器私钥
openssl genrsa -out server/ser.prikey 2048
# 生成服务器证书申请文件
openssl req -new -key server/ser.prikey -out server/ser.csr
# 生成由CA签名过的服务器证书
openssl x509 -req -days 365 -in server/ser.csr -CA ca.cert -CAkey private/ca.prikey -CAcreateserial -out server/ser.cert
===========================生成客户端证书相关内容============================
# 生成客户端私钥
openssl genrsa -out client/cli.prikey 2048
# 生成客户端证书申请文件
openssl req -new -key client/cli.prikey -out client/cli.csr
# 生成由CA签名过的客户端证书
openssl x509 -req -days 365 -in client/cli.csr -CA ca.cert -CAkey private/ca.prikey -CAcreateserial -out client/cli.cert
# 生成客户端集成证书,包括公钥和私钥,用于浏览器访问场景
openssl pkcs12 -export -in client/cli.cert -inkey client/cli.prikey -out client/certificate.p12
生成的所有证书如下:
实验的环境跟上面的tcp代理配置实验相同,nginx.conf的配置文件添加SSL的一些基本配置,具体如下:
# lijd add 2023-11-4
stream {
upstream backend {
server 192.168.97.50:54321;
}
server {
listen 12345;
proxy_connect_timeout 60s;
proxy_timeout 60s;
proxy_pass backend;
# 设置nginx代理与真实服务器连接是否为SSL协议加密
proxy_ssl off;
# 设置使用的SSL协议版本
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 SSLv2;
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
# 设置服务端使用的密码套件
ssl_certificate /lijd/CA/server/ser.cert;
ssl_certificate_key /lijd/CA/server/ser.prikey;
ssl_session_cache shared:SSL:10m; # SSL TCP会话缓存设置共享内存区域名为
# SSL,区域大小为10MB
ssl_session_timeout 10m; # SSL TCP会话缓存超时时间为10分钟
# 开启客户端认证
#ssl_verify_client on;
#ssl_client_certificate /lijd/CA/ca.cert;
}
}
# lijd add end
注意:proxy_ssl参数开关表示:nginx代理与后台真是的tcp服务器直接是否需要SSL加密。
由于实验需要tcp客户端通道加密,支持tcp客户端TLS加密工具比较难找到,因此用单纯的tcp协议认证测试相对麻烦。笔者在这里想了一个办法:由于http、https协议是基于tcp协议之上的协议,利用浏览器的https的请求特性,模拟一个tcp加密客户端;此时后台的真实服务器用系统自带的IIS服务(http服务器)充当一个tcp服务端。后台的真实服务器如下:
通过nginx代理的tcp服务去访问后台服务器浏览器页面如下:
可以看到浏览器能通过nginx代理访问到真实的后台服务器并收到网页回复数据。通过抓两条链路的数据包分析如下:
1、浏览器(充当tcp客户端)与nginx代理之间的加密链路抓包分析如下:
2、nginx与后台真实服务器之间的纯tcp链路抓包分析如下:
双向认证需要nginx代理配置开启客户端认证。nginx.conf的配置将下面两行注释放开:
ssl_verify_client on;
ssl_client_certificate /lijd/CA/ca.cert;
重启nginx代理后,再通过浏览器访问页面就打不开了,如下图:
双向认证服务端需要认证客户端的证书信息,此时浏览器需要导入客户端集成证书certificate.p12,导入时需要密码,导入成功后如下图:
再次通过浏览器访问页面如下图:
点击确认之后成功访问到页面。由于客户端与nginx直接变成双向认证,nginx与真实服务器之间连接还是纯裸的tcp连接与单向认证时的情况相同,这里就抓一下客户端与nginx之间的数据包,如下图:
至此,通过nginx代理TLS加密通道实验已经完结。本章主要讨论的是如下图结构:
有兴趣的同学可以研究一下nginx代理与客户端、服务器双向都为TLS加密通道。此时nginx的配置中proxy_ssl参数需要设置成on(默认为on,实验时在这卡了半天),这时就需要后台TCP服务器支持TLS加密。