<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
NGINX最初被設計為反向代理伺服器。但是,隨著不斷髮展,NGINX也可以作為實現轉發代理的選項之一。轉發代理本身並不複雜,它解決的關鍵問題是如何加密HTTPS流量。本文介紹了使用NGINX作為HTTPS流量轉發代理的兩種方法,以及它們的應用場景和主要問題。
今天87cloud詳談下阿里雲國際如何使用NGINX作為HTTPS轉發代理伺服器
首先,讓我們仔細看看轉發代理的分類。
分類依據:代理對客戶是否透明
分類依據:代理是否加密HTTPS
注意:在這種情況下,使用者端在TLS握手過程中實際獲取了代理伺服器的自簽名證書,預設情況下證書鏈的驗證不成功。代理自簽名證書中的根 CA 證書必須在使用者端上受信任。因此,使用者端知道此過程中的代理。如果將自簽名根 CA 證書推播到使用者端(在企業的內部環境中實現),則可實現透明代理。
在充當反向代理時,代理伺服器通常會終止 HTTPS 加密流量並將其轉發到後端範例。HTTPS 流量的加密、解密和身份驗證發生在使用者端和反向代理伺服器之間。
另一方面,當充當轉發代理並處理使用者端傳送的流量時,代理伺服器不會在使用者端請求的URL中看到目標域名,因為HTTP流量已加密並封裝在TLS / SSL中,如下圖所示。因此,與 HTTP 流量不同,HTTPS 流量在代理實現期間需要一些特殊處理。
根據前面幾節中的分類,當NGINX用作HTTPS代理時,代理是透明的傳輸(隧道)代理,既不解密也不感知上層流量。具體來說,有兩種NGINX解決方案可用:第7層(L7)和第4層(L4)。以下各節詳細介紹了這些解決方案。
早在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 流量。
作為反向代理伺服器,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 > < HTTP/1.1 200 Connection Established < Proxy-agent: nginx < * Proxy replied OK to CONNECT request * 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 ... > GET / HTTP/1.1 > User-Agent: curl/7.29.0 > Host: www.baidu.com > Accept: */* > < HTTP/1.1 200 OK ... { [data not shown]
由“-v”引數列印的上述詳細資訊指示使用者端首先與代理伺服器 39.105.196.164 建立 HTTP CONNECT 隧道。一旦代理回覆為“HTTP/1.1 200 連線已建立”,使用者端就會啟動 TLS/SSL 握手並將流量傳送到伺服器。
由於上層流量是透明傳輸的,因此這裡出現的關鍵問題是NGINX是否應該充當“L4代理”來實現TCP / UDP以上協定的完全透明傳輸。答案是肯定的。NGINX 1.9.0或更高版本支援ngx_stream_core_module。預設情況下不生成此模組。在命令下新增選項以啟用此模組。-- with-stream
configure
使用NGINX流作為TCP層HTTPS流量的代理,會導致本文開頭提到的相同問題:代理伺服器未獲得使用者端要存取的目標域名。發生這種情況是因為在 TCP 層獲得的資訊僅限於 IP 地址和埠,而不獲取域名。要獲取目標域名,代理必須能夠從上層封包中提取域名。因此,NGINX流不是嚴格意義上的L4代理,它必須尋求上層的幫助才能提取域名。
為了在不解密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: */* > < HTTP/1.1 200 OK < Accept-Ranges: bytes < Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform < Connection: Keep-Alive < Content-Length: 2443 < Content-Type: text/html < Date: Fri, 21 Jun 2019 05:46:07 GMT < Etag: "5886041d-98b" < Last-Modified: Mon, 23 Jan 2017 13:24:45 GMT < Pragma: no-cache < Server: bfe/1.0.8.18 < Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/ < { [data not shown] * Connection #0 to host www.baidu.com left intact
現在,讓我們快速看一下有關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轉發代理伺服器內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45