隐藏在站点下的NGINX前置WSS隧道建设
在之前的文章《带探测防御的高级HTTP/HTTPS隧道建设》中,阐述了一种向外表示为正常网页服务,而真正的代理服务无法被探测的隧道建设方式。不难发现,在那个方法中,NGINX只作为实现HSTS的301跳转工具,整个功能其实都是由Gost实现的。
该文章的实现方式不同之前,这次的实现中把NGINX前置,首先利用NGINX实现了一个完整的网页服务(HTTP、HTTPS、HSTS),然后利用NGINX的路径分流功能来在正常的HTTPS流量中建立代理连接,显得更加真实,而NGINX实现的TLS会比golang的实现更快。但是本方法并非没有缺点,gost仍然要处理websocket连接,且websocket连接增加了握手耗时(在TLS基础上)。
配置服务端
配置服务端NGINX
安装NGINX
可以查看之前的文章《编译安装NGINX与使用》。
书写配置文件
先建立第一个server(HTTP服务):
1 | server { |
这个server的配置意义是,监听在80端口(HTTP服务默认端口),监听域名的 my.site
,如果访问的域名不是 my.site
则拒绝连接,对合法连接进行301跳转到本机的HTTPS服务。
然后建立第二个server(HTTPS服务):
1 | server { |
其中,对于websocket分流的路径,为了保证安全性,可以用工具随机生成一个UUID(Universally Unique Identifier,通用唯一识别码),例如:
1 | location /dadefda5-2ff4-4481-a46c-06d26e598ca4 { |
下面对配置中的一些字段做解释:
listen 443 ssl
:监听443端口,并启用SSL。ssl_certificate
:填写SSL证书的绝对路径。ssl_certificate_key
:填写SSL证书密钥的绝对路径。ssl_protocols
:指定使用的TLS版本,这里锁定了TLS1.3。(注意:如果OpenSSL版本太老,有可能不支持TLSv1.3,例如CentOS7自带的就不支持,这需要你自行升级OpenSSL并重新编译安装NGINX来指定OpenSSL的安装路径。)ssl_early_data on
:开启了TLS1.3的0-RTT特性,减少握手延迟,NGINX因为安全原因默认关闭此项。(注意:如果NGINX版本太老,有可能不支持该字段。)location /
:该路径以下的请求将被该代码块处理。add_header Cache-Control no-cache;
:无缓存。proxy_set_header Host remote.site;
:HTTP header 中的 Host 含义为所请求的目的主机名。当 NGINX 作为反向代理使用,而后端真实 web 服务器设置有类似 防盗链功能 ,或者根据 HTTP header 中的 Host 字段来进行 路由 或 过滤 功能的话,若作为反向代理的 nginx 不重写请求头中的 Host 字段,将会导致请求失败。
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
:HTTP header 中的 X_Forward_For 表示该条 http 请求是由谁发起的。如果反向代理服务器不重写该请求头的话,那么后端真实 web 服务器在处理时会认为所有的请求都来自反向代理服务器。如果后端 web 服务器有防攻击策略的话,那么反向代理服务器对应的 ip 地址就会被封掉。
上述配置的意思是增加一个
$proxy_add_x_forwarded_for
到X-Forwarded-For
里去,注意是增加,而不是覆盖。当然由于默认的X-Forwarded-For
值是空的,所以我们总感觉X-Forwarded-For
的值就等于$proxy_add_x_forwarded_for
的值。X-Forwarded-For
的格式为X-Forwarded-For:real client ip, proxy ip 1, proxy ip N
,每经过一个反向代理就在请求头X-Forwarded-For后追加反向代理IP。proxy_set_header X-Real-IP $remote_addr;
:获取真实的客户端IP。proxy_redirect off;
:禁止URL重定向。proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
以上三个字段都是在保证NGINX会将请求当作websocket处理。
加载新的配置文件
1 | nginx -s reload |
配置服务端Gost
1 | gost -L ws://:34567/:12345?path=/websocketPathDiversion |
配置客户端
客户端只需配置gost。
1 | gost -L tcp://:45678 -F="forward+wss://my.site:443?secure=true&ip=x.y.z.v&path=websocketPathDiversion" |
然后连接客户端的45678端口就能连接上服务端的12345的tcp服务了。