热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

阿里云国际版使用Nginx作为HTTPS转发代理服务器的处理方法

本文介绍了使用NGINX作为HTTPS流量转发代理的两种方法。它总结了NGINX使用HTTP CONNECT隧道和NGINX流充当HTTPS转发代理的解决方案的原则,环境构建要求,应用场景和关键问题

NGINX最初被设计为反向代理服务器。但是,随着不断发展,NGINX也可以作为实现转发代理的选项之一。转发代理本身并不复杂,它解决的关键问题是如何加密HTTPS流量。本文介绍了使用NGINX作为HTTPS流量转发代理的两种方法,以及它们的应用场景和主要问题。

今天87cloud详谈下阿里云国际如何使用NGINX作为HTTPS转发代理服务器

HTTP/HTTPS 转发代理的分类

首先,让我们仔细看看转发代理的分类。

分类依据:代理对客户是否透明

  • 通用代理:在这里,代理地址和端口是在客户端上的浏览器或系统环境变量中手动配置的。例如,当您在客户端上指定 Squid 服务器的 IP 地址和端口 3128 时。
  • 透明代理:客户端上不需要代理设置。“代理”角色对客户端是透明的。例如,企业网络上的 Web 网关设备是透明代理。

分类依据:代理是否加密HTTPS

  • 隧道代理:这是一个透明传输流量的代理。代理服务器专门通过 TCP 透明地传输 HTTPS 流量。它不会解密或感知其代理流量的特定内容。客户端与目标服务器执行直接 TLS/SSL 交互。本文介绍了与此类型相关的NGINX代理模式。
  • 中间人 (MITM) 代理:代理服务器解密 HTTPS 流量,使用自签名证书完成与客户端的 TLS/SSL 握手,并完成与目标服务器的正常 TLS 交互。在客户端-代理-服务器链接上设置了两个 TLS/SSL 会话。

注意:在这种情况下,客户端在TLS握手过程中实际获取了代理服务器的自签名证书,默认情况下证书链的验证不成功。代理自签名证书中的根 CA 证书必须在客户端上受信任。因此,客户端知道此过程中的代理。如果将自签名根 CA 证书推送到客户端(在企业的内部环境中实现),则可实现透明代理。

转发代理处理 HTTPS 流量时需要特殊处理

在充当反向代理时,代理服务器通常会终止 HTTPS 加密流量并将其转发到后端实例。HTTPS 流量的加密、解密和身份验证发生在客户端和反向代理服务器之间。

另一方面,当充当转发代理并处理客户端发送的流量时,代理服务器不会在客户端请求的URL中看到目标域名,因为HTTP流量已加密并封装在TLS / SSL中,如下图所示。因此,与 HTTP 流量不同,HTTPS 流量在代理实现期间需要一些特殊处理。

NGINX解决方案

根据前面几节中的分类,当NGINX用作HTTPS代理时,代理是透明的传输(隧道)代理,既不解密也不感知上层流量。具体来说,有两种NGINX解决方案可用:第7层(L7)和第4层(L4)。以下各节详细介绍了这些解决方案。

HTTP 连接隧道 (L7 解决方案)

历史背景

早在1998年TLS还没有正式上市的时候,推广SSL协议的网景就提出使用Web代理进行SSL流量的隧道。核心思想是使用HTTP CONNECT请求在客户端和代理之间建立HTTP CONNECT隧道。CONNECT 请求必须指定客户端需要访问的目标主机和端口。互联网草案中的原始图表如下:

有关整个过程的详细信息,请参阅 HTTP:权威指南中的图表。以下步骤简要概述了该过程。

1) 客户端向代理服务器发送 HTTP CONNECT 请求。
2) 代理服务器使用 HTTP CONNECT 请求中的主机和端口信息与目标服务器建立 TCP 连接。
3) 代理服务器向客户端返回 HTTP 200 响应。
4) 客户端与代理服务器建立 HTTP CONNECT 隧道。在 HTTPS 流量到达代理服务器后,代理服务器通过 TCP 连接透明地将 HTTPS 流量传输到远程目标服务器。代理服务器仅透明地传输 HTTPS 流量,不解密 HTTPS 流量。

 

ngx_http_proxy_connect_module

作为反向代理服务器,NGINX并不正式支持HTTP CONNECT方法。但是,由于NGINX的模块化和可扩展功能,阿里巴巴@chobits提供了连接模块(中文内容)来支持HTTP CONNECT方法,以扩展NGINX作为转发代理。ngx_http_proxy_connect_module

环境建设

以 CentOS 7 環境為例,讓我們詳細看看這過程。

1) 环境安装

对于新环境安装,请参阅安装连接模块的常见安装步骤(中文内容)。ngx_http_proxy_connect_module

安装相应版本的修补程序,并在“configure”命令下添加参数,如以下示例所示。--add-module=/path/to/ngx_http_proxy_connect_module

./configure \
--user=www \
--group=www \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-threads \
--add-module=/root/src/ngx_http_proxy_connect_module

此外,为现有环境添加,如下所示。ngx_http_proxy_connect_module

# 停止NGINX服务
# systemctl stop nginx
# 备份原执行文件
# cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
# 在源代码路径重新编译
# cd /usr/local/src/nginx-1.16.0
./configure \
--user=www \
--group=www \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-threads \
--add-module=/root/src/ngx_http_proxy_connect_module
# make
# 不要make install
# 将新生成的可执行文件拷贝覆盖原来的nginx执行文件
# cp objs/nginx /usr/local/nginx/sbin/nginx
# /usr/bin/nginx -V
nginx version: nginx/1.16.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC)
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --user=www --group=www --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-threads --add-module=/root/src/ngx_http_proxy_connect_module

2) 配置 nginx.conf 文件

执行以下命令以配置文件。nginx.conf

server {
     listen  443;
    
     # dns resolver used by forward proxying
     resolver  114.114.114.114;
     # forward proxy for CONNECT request
     proxy_connect;
     proxy_connect_allow            443;
     proxy_connect_connect_timeout  10s;
     proxy_connect_read_timeout     10s;
     proxy_connect_send_timeout     10s;
     # forward proxy for non-CONNECT request
     location / {
         proxy_pass http://$host;
         proxy_set_header Host $host;
     }
 }

应用场景

在 L7 解决方案中,HTTP CONNECT 请求必须建立隧道,因此,代理服务器是客户端必须感知的公共代理。在客户端上手动配置 HTTP(S) 代理服务器的 IP 地址和端口。使用 cURL 的“-x”参数访问客户端,如下所示。

# curl https://www.baidu.com -svo /dev/null -x 39.105.196.164:443
* About to connect() to proxy 39.105.196.164 port 443 (#0)
*   Trying 39.105.196.164...
* Connected to 39.105.196.164 (39.105.196.164) port 443 (#0)
* Establish HTTP proxy tunnel to www.baidu.com:443
> CONNECT www.baidu.com:443 HTTP/1.1
> Host: www.baidu.com:443
> User-Agent: curl/7.29.0
> Proxy-Connection: Keep-Alive
>
 GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.baidu.com
> Accept: */*
>

由“-v”参数打印的上述详细信息指示客户端首先与代理服务器 39.105.196.164 建立 HTTP CONNECT 隧道。一旦代理回复为“HTTP/1.1 200 连接已建立”,客户端就会启动 TLS/SSL 握手并将流量发送到服务器。

NGINX流(L4解决方案)

由于上层流量是透明传输的,因此这里出现的关键问题是NGINX是否应该充当“L4代理”来实现TCP / UDP以上协议的完全透明传输。答案是肯定的。NGINX 1.9.0或更高版本支持ngx_stream_core_module。默认情况下不生成此模块。在命令下添加选项以启用此模块。-- with-streamconfigure

常见问题

使用NGINX流作为TCP层HTTPS流量的代理,会导致本文开头提到的相同问题:代理服务器未获得客户端要访问的目标域名。发生这种情况是因为在 TCP 层获得的信息仅限于 IP 地址和端口,而不获取域名。要获取目标域名,代理必须能够从上层数据包中提取域名。因此,NGINX流不是严格意义上的L4代理,它必须寻求上层的帮助才能提取域名。

ngx_stream_ssl_preread_module

为了在不解密HTTPS流量的情况下获取HTTPS流量的目标域名,唯一的方法是在TLS/SSL握手期间使用第一个ClientHello数据包中包含的SNI字段。从版本1.11.5开始,NGINX支持ngx_stream_ssl_preread_module。此模块有助于从 ClientHello 数据包获取 SNI 和 ALPN。对于L4转发代理,从ClientHello数据包中提取SNI的能力至关重要,否则NGINX流解决方案将无法实现。但是,这也带来了一个限制,即在 TLS/SSL 握手期间,所有客户端都必须在 ClientHello 数据包中包含 SNI 字段。否则,NGINX流代理将不知道客户端需要访问的目标域名。

环境建设

1) 环境安装

对于新安装的环境,请参考常用安装步骤(中文内容),直接在“configure”命令下添加、、和选项。请考虑以下示例以更好地理解。--with-stream--with-stream_ssl_preread_module--with-stream_ssl_module

./configure \
--user=www \
--group=www \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-threads \
--with-stream \
--with-stream_ssl_preread_module \
--with-stream_ssl_module

为已安装和已编译的环境添加上述三个与流相关的模块,如下所示。

# 停止NGINX服务
# systemctl stop nginx
# 备份原执行文件
# cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
# 在源代码路径重新编译
# cd /usr/local/src/nginx-1.16.0
# ./configure \
--user=www \
--group=www \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-threads \
--with-stream \
--with-stream_ssl_preread_module \
--with-stream_ssl_module
# make
# 不要make install
# 将新生成的可执行文件拷贝覆盖原来的nginx执行文件
# cp objs/nginx /usr/local/nginx/sbin/nginx
# nginx -V
nginx version: nginx/1.16.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC)
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --user=www --group=www --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-threads --with-stream --with-stream_ssl_preread_module --with-stream_ssl_module

2) 配置 nginx.conf 文件

与HTTP不同,在流块中配置NGINX流。但是,命令参数与HTTP块的命令参数类似。以下代码段显示了主配置。

stream {
    resolver 114.114.114.114;
    server {
        listen 443;
        ssl_preread on;
        proxy_connect_timeout 5s;
        proxy_pass $ssl_preread_server_name:$server_port;
    }
}

应用场景

作为L4转发代理,NGINX基本上透明地将流量传输到上层,并且不需要HTTP CONNECT来建立隧道。因此,L4 解决方案适用于透明代理模式。例如,当目标域名通过 DNS 解析定向到代理服务器时,需要通过绑定到客户端来模拟透明代理模式。/etc/hosts

以下代码段显示了客户端上的命令:

cat /etc/hosts
...
# 把域名www.baidu.com绑定到正向代理服务器39.105.196.164
39.105.196.164 www.baidu.com
 
# 正常利用curl来访问www.baidu.com即可。
# curl https://www.baidu.com -svo /dev/null
* About to connect() to www.baidu.com port 443 (#0)
*   Trying 39.105.196.164...
* Connected to www.baidu.com (39.105.196.164) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
*     subject: CN=baidu.com,O="Beijing Baidu Netcom Science Technology Co., Ltd",OU=service operation department,L=beijing,ST=beijing,C=CN
*     start date: 5月 09 01:22:02 2019 GMT
*     expire date: 6月 25 05:31:02 2020 GMT
*     common name: baidu.com
*     issuer: CN=GlobalSign Organization Validation CA - SHA256 - G2,O=GlobalSign nv-sa,C=BE
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.baidu.com
> Accept: */*
>

常见问题

现在,让我们快速看一下有关L4解决方案的关键问题。

1) 由于客户端上的手动代理设置,访问尝试失败。

L4 转发代理透明地传输上层 HTTPS 流量,不需要 HTTP CONNECT 即可建立隧道。因此,没有必要在客户端上设置 HTTP(S) 代理。关键问题是,在客户端上手动设置 HTTP(S) 代理是否可确保访问尝试成功。使用 cURL 的“-x”参数设置转发代理服务器并测试对此服务器的访问。以下代码段显示了结果。

# curl https://www.baidu.com -svo /dev/null -x 39.105.196.164:443
* About to connect() to proxy 39.105.196.164 port 443 (#0)
*   Trying 39.105.196.164...
* Connected to 39.105.196.164 (39.105.196.164) port 443 (#0)
* Establish HTTP proxy tunnel to www.baidu.com:443
> CONNECT www.baidu.com:443 HTTP/1.1
> Host: www.baidu.com:443
> User-Agent: curl/7.29.0
> Proxy-Connection: Keep-Alive
>
* Proxy CONNECT aborted
* Connection #0 to host 39.105.196.164 left intact

结果指示客户端尝试在 NGINX 之前建立 HTTP CONNECT 隧道。但是,由于NGINX透明地传输流量,因此CONNECT请求直接转发到目标服务器。目标服务器不接受 CONNECT 方法。因此,“代理连接中止”反映在上面的代码段中,导致访问失败。

2) 访问尝试失败,因为客户端在 ClientHello 数据包中不包含 SNI。

如前所述,当NGINX流用作转发代理时,使用从ClientHello中提取SNI字段至关重要。如果客户端在 ClientHello 数据包中未包含 SNI,则代理服务器将不知道目标域名,从而导致访问失败。ngx_stream_ssl_preread_module

在透明代理模式(由手动绑定主机模拟)下,使用 OpenSSL 在客户端上进行模拟。

# openssl s_client -connect www.baidu.com:443 -msg
CONNECTED(00000003)
>>> TLS 1.2  [length 0005]
    16 03 01 01 1c
>>> TLS 1.2 Handshake [length 011c], ClientHello
    01 00 01 18 03 03 6b 2e 75 86 52 6c d5 a5 80 d7
    a4 61 65 6d 72 53 33 fb 33 f0 43 a3 aa c2 4a e3
    47 84 9f 69 8b d6 00 00 ac c0 30 c0 2c c0 28 c0
    24 c0 14 c0 0a 00 a5 00 a3 00 a1 00 9f 00 6b 00
    6a 00 69 00 68 00 39 00 38 00 37 00 36 00 88 00
    87 00 86 00 85 c0 32 c0 2e c0 2a c0 26 c0 0f c0
    05 00 9d 00 3d 00 35 00 84 c0 2f c0 2b c0 27 c0
    23 c0 13 c0 09 00 a4 00 a2 00 a0 00 9e 00 67 00
    40 00 3f 00 3e 00 33 00 32 00 31 00 30 00 9a 00
    99 00 98 00 97 00 45 00 44 00 43 00 42 c0 31 c0
    2d c0 29 c0 25 c0 0e c0 04 00 9c 00 3c 00 2f 00
    96 00 41 c0 12 c0 08 00 16 00 13 00 10 00 0d c0
    0d c0 03 00 0a 00 07 c0 11 c0 07 c0 0c c0 02 00
    05 00 04 00 ff 01 00 00 43 00 0b 00 04 03 00 01
    02 00 0a 00 0a 00 08 00 17 00 19 00 18 00 16 00
    23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 03 05
    01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03
    03 02 01 02 02 02 03 00 0f 00 01 01
140285606590352:error:140790E5:SSL routines:ssl23_write:ssl handshake failure:s23_lib.c:177:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 289 bytes
⋯

默认情况下,OpenSSL 不包括 SNI。如代码段所示,在发送 ClientHello 后,前面的请求将在 TLS/SSL 握手阶段终止。发生这种情况是因为代理服务器不知道应将 ClientHello 转发到的目标域名。s_client

使用带有“服务器名称”参数的 OpenSSL 来指定 SNI,将产生成功的访问。

# openssl s_client -connect www.baidu.com:443 -servername www.baidu.com

结论

本文介绍了使用NGINX作为HTTPS流量转发代理的两种方法。它总结了NGINX使用HTTP CONNECT隧道和NGINX流充当HTTPS转发代理的解决方案的原则,环境构建要求,应用场景和关键问题。本文在各种情况下使用NGINX作为转发代理时用作参考,具体情况参考www.87cloud.com

到此这篇关于阿里云国际版使用Nginx作为HTTPS转发代理服务器的处理方法的文章就介绍到这了,更多相关Nginx作为HTTPS转发代理服务器内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • 在 CentOS 6.4 上安装 QT5 并启动 Qt Creator 时,可能会遇到缺少 GLIBCXX_3.4.15 的问题。这是由于系统中的 libstdc++.so.6 版本过低。本文将详细介绍如何通过更新 GCC 版本来解决这一问题。 ... [详细]
  • 秒建一个后台管理系统?用这5个开源免费的Java项目就够了
    秒建一个后台管理系统?用这5个开源免费的Java项目就够了 ... [详细]
  • 本文详细介绍了 InfluxDB、collectd 和 Grafana 的安装与配置流程。首先,按照启动顺序依次安装并配置 InfluxDB、collectd 和 Grafana。InfluxDB 作为时序数据库,用于存储时间序列数据;collectd 负责数据的采集与传输;Grafana 则用于数据的可视化展示。文中提供了 collectd 的官方文档链接,便于用户参考和进一步了解其配置选项。通过本指南,读者可以轻松搭建一个高效的数据监控系统。 ... [详细]
  • 在CentOS 7环境中安装配置Redis及使用Redis Desktop Manager连接时的注意事项与技巧
    在 CentOS 7 环境中安装和配置 Redis 时,需要注意一些关键步骤和最佳实践。本文详细介绍了从安装 Redis 到配置其基本参数的全过程,并提供了使用 Redis Desktop Manager 连接 Redis 服务器的技巧和注意事项。此外,还探讨了如何优化性能和确保数据安全,帮助用户在生产环境中高效地管理和使用 Redis。 ... [详细]
  • 在Linux系统中避免安装MySQL的简易指南
    在Linux系统中避免安装MySQL的简易指南 ... [详细]
  • 为了确保iOS应用能够安全地访问网站数据,本文介绍了如何在Nginx服务器上轻松配置CertBot以实现SSL证书的自动化管理。通过这一过程,可以确保应用始终使用HTTPS协议,从而提升数据传输的安全性和可靠性。文章详细阐述了配置步骤和常见问题的解决方法,帮助读者快速上手并成功部署SSL证书。 ... [详细]
  • 为了在Hadoop 2.7.2中实现对Snappy压缩和解压功能的原生支持,本文详细介绍了如何重新编译Hadoop源代码,并优化其Native编译过程。通过这一优化,可以显著提升数据处理的效率和性能。此外,还探讨了编译过程中可能遇到的问题及其解决方案,为用户提供了一套完整的操作指南。 ... [详细]
  • 本文详细介绍了在CentOS 6.5 64位系统上使用阿里云ECS服务器搭建LAMP环境的具体步骤。首先,通过PuTTY工具实现远程连接至服务器。接着,检查当前系统的磁盘空间使用情况,确保有足够的空间进行后续操作,可使用 `df` 命令进行查看。此外,文章还涵盖了安装和配置Apache、MySQL和PHP的相关步骤,以及常见问题的解决方法,帮助用户顺利完成LAMP环境的搭建。 ... [详细]
  • 本文详细介绍了在 CentOS 7 系统中配置 fstab 文件以实现开机自动挂载 NFS 共享目录的方法,并解决了常见的配置失败问题。 ... [详细]
  • 本文介绍如何使用 Python 的 DOM 和 SAX 方法解析 XML 文件,并通过示例展示了如何动态创建数据库表和处理大量数据的实时插入。 ... [详细]
  • 基于Linux开源VOIP系统LinPhone[四]
    ****************************************************************************************** ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 本文介绍了如何利用Shell脚本高效地部署MHA(MySQL High Availability)高可用集群。通过详细的脚本编写和配置示例,展示了自动化部署过程中的关键步骤和注意事项。该方法不仅简化了集群的部署流程,还提高了系统的稳定性和可用性。 ... [详细]
  • Spring框架中枚举参数的正确使用方法与技巧
    本文详细阐述了在Spring Boot框架中正确使用枚举参数的方法与技巧,旨在帮助开发者更高效地掌握和应用枚举类型的数据传递,适合对Spring Boot感兴趣的读者深入学习。 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
author-avatar
灬猎丶豹灬_511
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有