如何通过反向代理修改后端链接,实现隔离网络主机访问?
没问题,这个场景我熟!你遇到的核心问题是后端返回的HTML里包含了终端用户无法直接访问的内部网段链接,浏览器会直接跳去那个地址,完全绕开了你的反向代理。解决的关键就是在代理层改写后端响应里的链接,把内部地址换成代理的可访问地址,同时让代理负责转发这些请求到内部服务器。下面给你分三种代理分别讲解决方案:
HAProxy解决方案
你可以通过HAProxy的rsprep指令修改后端返回的响应内容,把内部链接替换成代理地址,同时新增一个后端来转发到30.30.30.2。修改后的配置如下:
#--------------------------------------------------------------------- # main frontend which proxys to the backends #--------------------------------------------------------------------- frontend main bind 10.10.10.1:443 ssl crt /etc/haproxy/haproxy.pem # 匹配指向内部链接的请求,转发到专门的后端 acl is_internal_link path_beg /internal-link use_backend internal_backend if is_internal_link default_backend app #--------------------------------------------------------------------- # 后端服务器app1的配置(原配置基础上加响应改写) #--------------------------------------------------------------------- backend app balance roundrobin server app1 30.30.30.1:443 check ssl verify none # 把响应里的内部链接替换成代理的可访问地址 rsprep ^(.*)http://30.30.30.2:8080(.*)$ \1https://10.10.10.1/internal-link\2 #--------------------------------------------------------------------- # 转发到30.30.30.2的后端配置 #--------------------------------------------------------------------- backend internal_backend server internal1 30.30.30.2:8080 check # 如果30.30.30.2返回的内容里也有内部地址,同样做改写 rsprep ^(.*)http://30.30.30.2:8080(.*)$ \1https://10.10.10.1/internal-link\2
说明:rsprep是HAProxy用于修改HTTP响应内容的指令,这里会把后端返回的HTML中所有http://30.30.30.2:8080替换成https://10.10.10.1/internal-link。用户点击链接时会请求代理,代理再转发到30.30.30.2,完美绕开用户无法访问内部网段的问题。
Nginx解决方案
Nginx可以用sub_filter模块(默认可能需要编译启用)来改写响应内容,同时配置路径转发:
server { listen 10.10.10.1:443 ssl; ssl_certificate /etc/nginx/certs/your_cert.pem; # 替换为你的证书路径 ssl_certificate_key /etc/nginx/certs/your_key.key; # 代理到app1的请求 location / { proxy_pass https://30.30.30.1:443; proxy_ssl_verify off; # 关闭后端证书验证,和HAProxy的verify none对应 # 替换响应中的内部链接 sub_filter 'http://30.30.30.2:8080' 'https://10.10.10.1/internal-link'; sub_filter_once off; # 替换页面中所有匹配的链接,而非仅第一个 } # 代理到30.30.30.2的请求 location /internal-link/ { proxy_pass http://30.30.30.2:8080/; # 末尾的/用于去掉路径前缀 # 对30.30.30.2返回的内容也做链接改写 sub_filter 'http://30.30.30.2:8080' 'https://10.10.10.1/internal-link'; sub_filter_once off; } }
说明:sub_filter会精准替换响应体中的指定字符串,sub_filter_once off确保页面中所有相同的内部链接都被替换,避免遗漏。
Apache解决方案
Apache需要启用mod_substitute模块(执行a2enmod substitute启用),然后通过配置实现链接改写和请求转发:
<VirtualHost 10.10.10.1:443> SSLEngine on SSLCertificateFile /etc/apache2/certs/your_cert.pem SSLCertificateKeyFile /etc/apache2/certs/your_key.key # 代理到app1的配置 ProxyPass / https://30.30.30.1:443/ ProxyPassReverse / https://30.30.30.1:443/ SSLProxyVerify none # 关闭后端证书验证 SSLProxyCheckPeerCN off SSLProxyCheckPeerName off # 对HTML响应中的内部链接做替换 AddOutputFilterByType SUBSTITUTE text/html Substitute "s|http://30.30.30.2:8080|https://10.10.10.1/internal-link|ni" # 代理到30.30.30.2的配置 ProxyPass /internal-link/ http://30.30.30.2:8080/ ProxyPassReverse /internal-link/ http://30.30.30.2:8080/ # 对30.30.30.2返回的内容也做链接改写 <Location /internal-link/> AddOutputFilterByType SUBSTITUTE text/html Substitute "s|http://30.30.30.2:8080|https://10.10.10.1/internal-link|ni" </Location> </VirtualHost>
说明:Substitute指令使用正则替换规则,ni参数表示不区分大小写且全局替换;AddOutputFilterByType指定仅对HTML类型的响应做替换,防止破坏图片、JS等非文本资源。
内容的提问来源于stack exchange,提问作者D10s

