参考:https://www.cnblogs.com/guanshan/p/guan2022-7-26_001.html
https://blog.csdn.net/weixin_41560737/article/details/123287073
https://www.jianshu.com/p/cd813d68ed25
由于工作需要访问https://tpay.test.95516.com 进行测试,而内网服务器禁止访问互联网,须通过代理或者NAT实现访问。
该域名在外网通过域名能正常访问,但是解析成IP就无法访问(该站点使用了nginx)。
为什么正向代理处理HTTPS流量需要特殊处理?
作为反向代理时,代理服务器通常终结 (terminate) HTTPS加密流量,再转发给后端实例。HTTPS流量的加解密和认证过程发生在客户端和反向代理服务器之间。
而作为正向代理在处理客户端发过来的流量时,HTTP加密封装在了TLS/SSL中,代理服务器无法看到客户端请求URL中想要访问的域名,如下图。所以代理HTTPS流量,相比于HTTP,需要做一些特殊处理。
nginx代理访问互联网https有两种方式:
一、HTTP CONNECT隧道 (7层解决方案)
1.客户端给代理服务器发送HTTP CONNECT请求。
2.代理服务器利用HTTP CONNECT请求中的主机和端口与目的服务器建立TCP连接。
3.代理服务器给客户端返回HTTP 200响应。
4.客户端和代理服务器建立起HTTP CONNECT隧道,HTTPS流量到达代理服务器后,直接通过TCP透传给远端目的服务器。代理服务器的角色是透传HTTPS流量,并不需要解密HTTPS。
阿里的@chobits提供了ngx_http_proxy_connect_module模块,来支持HTTP CONNECT方法,从而让NGINX可以扩展为正向代理。
二、NGINX stream (4层解决方案)
ngx_stream_ssl_preread_module模块
要在不解密的情况下拿到HTTPS流量访问的域名,只有利用TLS/SSL握手的第一个Client Hello报文中的扩展地址SNI (Server Name Indication)来获取。NGINX官方从1.11.5版本开始支持利用ngx_stream_ssl_preread_module模块来获得这个能力,模块主要用于获取Client Hello报文中的SNI和ALPN信息。对于4层正向代理来说,从Client Hello报文中提取SNI的能力是至关重要的,否则NGINX stream的解决方案无法成立。同时这也带来了一个限制,要求所有客户端都需要在TLS/SSL握手中带上SNI字段,否则NGINX stream代理完全没办法知道客户端需要访问的目的域名。
三、外网https通过代理转成http
在ngx_http_proxy_module
模块的proxy_pass
指令需要在location段加上请求头proxy_set_header
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
$http_host:代理服务器本身IP
$remote_addr:前一节点的IP,并不一定是用户的真实IP。
$proxy_add_x_forwarded_for:获取的是前一节点的X-Forwarded-For的值
X-Forwarded-For 对应不同值:
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
当只有一层代理服务器的情况下,两者的X-Forwarded-For值一致,都是用户的真实IP。