点赞
评论
收藏
分享
举报
Nginx支持SNI证书的一种实现方式
发表于2022-10-12 20:58

浏览 1.1k

文章标签

什么是SNI?

    传统的应用场景中,一台服务器对应一个IP地址,一个域名,使用一张包含了域名信息的证书。随着云计算技术的普及,在云中的虚拟机有了一个IP,对应多个域名,使用多张证书的应用场景,SNI技术应运而生。SNI(Server Name Indication),即实现了一个服务器使用多个域名证书的TLS扩展,支持用户配置多个域名证书。

SNI请求特点

    HTTP请求的Host字段在请求的Header中。发起HTTPS请求时,在TLS握手阶段,还无法进行HTTP数据的解析,此时TLS协议的Client Hello字段新增了一个Server Name字段,请求的客户端可以通过这个字段填充请求的Host信息,而服务端在TLS握手阶段就可以选择请求处理的证书,实现SNI的功能。

Nginx支持的配置

    Nginx支持SNI,允许在同一个TLS服务端口下,配置不同的域名,用户通过请求不同的证书域名,可返回相应的upstream响应结果。

    本示例配置了一个证书域名为“lwl.test.com”的单向认证代理服务,一个证书域名为“lwl.default.com”的双向认证代理服务,使用相同的443端口,具体配置如下:

# Settings for a TLS enabled server.
upstream lwl.test.com {
server 192.168.58.196;
}

upstream default {
server 192.168.58.195;
}

server {
listen 443 ssl;
listen [::]:443 ssl;
server_name lwl.test.com;
root /usr/share/nginx/html;

ssl_certificate /etc/nginx/ssl_sni/server/lwl.test.com/server.crt;
ssl_certificate_key /etc/nginx/ssl_sni/server/lwl.test.com/server.key;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_pass http://lwl.test.com;
}

error_page 404 /404.html;
location = /40x.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

server {
listen 443 ssl;
listen [::]:443 ssl;
server_name lwl.default.com;
root /usr/share/nginx/html;

ssl_certificate /etc/nginx/ssl_sni/server/lwl.default.com/server.crt;
ssl_certificate_key /etc/nginx/ssl_sni/server/lwl.default.com/server.key;
ssl_client_certificate /etc/nginx/ssl_sni/private/ca.crt;
ssl_verify_client on;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_pass http://default;
}

error_page 404 /404.html;
location = /40x.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

单向认证测试

    基于以上配置,使用域名为“lwl.test.com”的证书进行单向认证的HTTPS访问,请求如下:
# curl https://lwl.test.com:443 --cacert /etc/nginx/ssl_sni/private/ca.crt

返回的响应为:

同时对当前的HTTPS请求进行抓包,可以看到,请求TLS握手阶段Client Hello请求中,包含了Server Name为lwl.test.com的字段:

双向认证测试

    基于以上配置,使用域名为“lwl.default.com”的证书进行双向认证的HTTPS访问,请求如下:   

# curl --cert /etc/nginx/ssl_sni/users/client.crt:123456 --key /etc/nginx/ssl_sni/users/client.key 'https://lwl.default.com:443' --cacert /etc/nginx/ssl_sni/private/ca.crt

返回的响应为:

同时对当前的HTTPS请求进行抓包,可以看到,请求TLS握手阶段Client Hello请求中,包含了Server Name为lwl.default.com的字段:  

至此验证了Nginx可同时支持多个TLS证书的功能。

多证书配置

    为支持多个SNI证书,一种Nginx配置文件形式为,每个证书配置单独一个server段,此处以两个单向认证证书,一个双向认证证书为例,配置如下:

# Settings for a TLS enabled server.
upstream lwl.test.com {
server 192.168.58.196;
}

upstream lwl.test1.com {
server 192.168.58.194:8081;
}

upstream default {
server 192.168.58.195;
}

server {
listen 443 ssl;
listen [::]:443 ssl;
server_name lwl.test.com;
root /usr/share/nginx/html;

ssl_certificate /etc/nginx/ssl_sni/server/lwl.test.com/server.crt;
ssl_certificate_key /etc/nginx/ssl_sni/server/lwl.test.com/server.key;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_pass http://lwl.test.com;
}

error_page 404 /404.html;
location = /40x.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

server {
listen 443 ssl;
listen [::]:443 ssl;
server_name lwl.test1.com;
root /usr/share/nginx/html;

ssl_certificate /etc/nginx/ssl_sni/server/lwl.test1.com/server.crt;
ssl_certificate_key /etc/nginx/ssl_sni/server/lwl.test1.com/server.key;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_pass http://lwl.test1.com;
}

error_page 404 /404.html;
location = /40x.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

server {
listen 443 ssl;
listen [::]:443 ssl;
server_name lwl.default.com;
root /usr/share/nginx/html;

ssl_certificate /etc/nginx/ssl_sni/server/lwl.default.com/server.crt;
ssl_certificate_key /etc/nginx/ssl_sni/server/lwl.default.com/server.key;
ssl_client_certificate /etc/nginx/ssl_sni/private/ca.crt;
ssl_verify_client on;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_pass http://default;
}

error_page 404 /404.html;
location = /40x.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

可以看到,随着加载证书个数的增加,Nginx配置篇幅增长较大,不利于配置维护。

优化的配置方式

    在1.7.0版本开始,Nginx支持通过$ssl_server_name 变量获取TLS中的Server Name,我们可以据此结合map映射指令,提升配置的重用度,一种优化后的配置方式如下:

# Settings for a TLS enabled server.
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

map $ssl_server_name $ssl_string {
lwl.test.com lwl.test.com;
lwl.test1.com lwl.test1.com;
default lwl.default.com;
}

upstream lwl.test.com {
server 192.168.58.196;
}

upstream lwl.test1.com {
server 192.168.58.194:8081;
}

upstream lwl.default.com {
server 192.168.58.195;
}

server {
listen 443 ssl;
listen [::]:443 ssl;
server_name $ssl_string;
root /usr/share/nginx/html;

ssl_certificate /etc/nginx/ssl_sni/server/$ssl_string/server.crt;
ssl_certificate_key /etc/nginx/ssl_sni/server/$ssl_string/server.key;

include /etc/nginx/default.d/*.conf;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_pass http://$ssl_string;
}

error_page 404 /404.html;
location = /40x.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

结束语

    本文通过结合Nginx的 $ssl_server_name 变量与map指令,提供了一种支持多个SNI证书配置的实现方式,提高了配置维护的重用度。

       


已修改于2023-03-09 02:19
本作品系原创
创作不易,留下一份鼓励
lwl

暂无个人介绍

关注



写下您的评论
发表评论
全部评论(0)

按点赞数排序

按时间排序

关于作者
lwl
这家伙很懒还未留下介绍~
3
文章
0
问答
4
粉丝
相关文章
Netcraft公司最近公布了他们检测SSL/TLS网站的研究,并指出只有仅仅5%的用户正确执行了HTTP严格传输安全HSTS。本文介绍nginx如何配置HSTS。什么是HSTSHTTPS(SSL和TLS)确保用户和网站通讯过程中安全,使攻击者难于拦截、修改和假冒。当用户手动输入域名或http://链接,该网站的第一个请求是未加密的,使用普通的http。最安全的网站立即发送回一个重定向使用户引向到https连接,然而,中间人攻击者可能会攻击拦截初始的http请求,从而控制用户后续的回话。自然而然HSTS应运而生为了解决这一潜在的安全问题。即时用户输入域名或http连接,浏览器将严格的升级到https连接。HSTS如何工作的HSTS策略是从安全的HTTPS站点发送的HTTP响应头部发布的。1Strict-Transport-Security:max-age=31536000当浏览器从HTTPS站点看到这个头部,就知道该域名只能通过HTTPS(SSL或者TLS)访问了。并将此信息缓存到31536000,也就是1年。可选的参数includeSubDomains告诉浏览器该策略适用于当前
点赞 0
浏览 752
点赞 0
浏览 1.9k
原文作者:LiamCrillyofF5原文链接:将NGINX部署为API网关,第3部分:发布gRPC服务转载来源:NGINX官方网站本文是“将NGINX开源版和NGINXPlus部署为API网关”系列博文的第三篇。第1部分详细说明了NGINX开源版和NGINXPlus作为基于HTTP的RESTfulAPI的API网关的一些用例。第2部分对这些用例进行了扩展,探讨了一系列可用于保护生产环境中后端API服务的安全措施。本文解释了如何将NGINX开源版和NGINXPlus部署为gRPC服务的API网关。文章最初发布于2018年,随着 NGINXPlusRelease23 中引入了对原生gRPC健康检查协议的支持,特此更新,以方便大家充分利用NGINX开源版和NGINXPlus。更新详情请参阅下文“实施健康检查”一节。注:除非另有说明,否则本文中的所有信息都适用于NGINXPlus和NGINX开源版。为了便于阅读,当讨论内容同时适用于两个版本时,下文将
点赞 1
浏览 525