相关文章推荐
开朗的枕头  ·  如何解决 ...·  2 年前    · 
风度翩翩的排球  ·  mysql ...·  2 年前    · 
首发于 DustTech
使用反向代理进行内网穿透

使用反向代理进行内网穿透

这篇教程主要是向大家介绍反向代理和内网穿透的简单概念和使用场景。并且教大家如何自己搭建一个反向代理服务器进行内网穿透。

背景

在开始前我们先来看一个场景。某一天你新学了一个Web框架,弄了一个HelloWorld后很兴奋,要给朋友show一下(因为只是临时show一下,所以你没有考虑将网站部署到服务器上)。这时候就比较尴尬了,你家宽带没有独占IP,公司是独占IP但是你又没权限配置路由器的转发表。你发现你的网页只有在局域网内才能访问得到,在外网的朋友是无法访问的。这时候有两个方法,一个方法是将网站部署到有公网IP的服务器上,另一个方法就是本文的主角——使用 反向代理 进行 内网穿透



反向代理-Reserve Proxy

反向代理其实不是什么新鲜玩意儿,它本质上和正向代理一样,都是把流量做转发。而正向代理的最典型的例子就是大家所用的梯子。假如客户端 A 到服务端 B 中间有个防火墙,屏蔽了所有 A B 的流量,而有个设备 C A C C B 的路由都是通的。这时候我们就可以把流量先发给 C C 收到后再将流量发给 B ,这样我们就可以访问到 B 上的资源了。这就是正向代理比较直观的例子。



如果说正向代理代理的是客户端,那么反向代理代理的就是服务端。比较直观的例子是负载均衡。比如我访问百度的域名,我的请求会首先到一个服务器 C 上, C 会给根据我的网络情况从很多的实例服务器中给我分配一个最快的实例服务器。这里的 C 做的工作其实就是反向代理。从这里我们可以看出正向代理多是管理出去的流量的,而反向代理多是管理进来的流量的。



反向代理的作用有

  • 对客户端隐藏服务器(集群)的IP地址
  • 安全:作为 应用层防火墙 ,为网站提供对基于Web的攻击行为(例如 DoS / DDoS )的防护,更容易排查 恶意软件
  • 为后端服务器(集群)统一提供加密和 SSL 加速(如SSL终端代理)
  • 负载均衡 ,若服务器集群中有负荷较高者,反向代理通过 URL重写 ,根据连线请求从负荷较低者获取与所需相同的资源或备援
  • 对于静态内容及短时间内有大量访问请求的动态内容提供 缓存服务
  • 对一些内容进行 压缩 ,以节约 带宽 或为网络带宽不佳的网络提供服务
  • 减速上传
  • 为在私有网络下(如 局域网 )的服务器集群提供 NAT穿透 及外网发布服务
  • 提供HTTP访问认证
  • 突破互联网封锁(不常用,因为反向代理与客户端之间的连线不一定是加密连线,非加密连线仍有遭内容审查进而遭封禁的风险;此外面对针对 域名 的关键字过滤、DNS缓存污染/投毒攻击乃至深度数据包检测也无能为力)

内网穿透-Intranet Penetration

在文章的开头我们举了一个例子,在外网的设备是无法直接访问到内网的资源的。因为各种路由(运营商的、自己的)将我们的内网的设备给屏蔽了。就像你无法直接访问到百度最下层的实例服务器一样。这时候我们就可以利用反向代理实现将内网的服务暴露出去,称之为内网穿透。

具体流程是这样的。我们需要一个有公网IP的服务器 C ,然后从本地 A C 访问,和 C 握手、建立稳定的信道。在外网的设备 B C 发送请求, C 通过刚才建立的稳定信道将请求转发给 A A 收到请求后将响应发给 C C 再将响应返给 B 。这样 B 就能访问到内网 A 的资源了。

比较著名的远程桌面控制软件 Teamviewer 其实背后的原理就是这样。



构建自己的内网穿透服务

我们这里使用的是ngrok。ngrok 是一个开源的反向代理工具(2.0版本后闭源),通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。ngrok 可捕获和分析所有通道上的流量,便于后期分析和重放。

我们会在云服务器上安装ngrok服务端,并为客户端生成证书。没有什么敲代码的工作,直接拿来用就行了。

我云服务器的环境为Ubuntu18,本地环境为macOS,不同的环境接下来的步骤可能会有区别,请大家自行解决。

安装GO

在云服务器上安装GO。

$ sudo apt upgrade
$ sudo apt install golang

装完后应该可以看到go的版本。

$ go version
go version go1.10.4 linux/amd64

配置Ngrok

从Github拉取Ngrok源码。

$ git clone https://github.com/inconshreveable/ngrok.git
$ export GOPATH=~/ngrok

接下来我们需要生成自己的证书,并编译携带该证书的客户端。

接下来的mytencent为我的hostname,请换成自己的。不能直接使用IP地址,否则会有证书错误。可以在本地的hosts里把自己的云服务器加上。
$ cd ngrok
$ NGROK_DOMAIN="mytencent.com"
$ openssl genrsa -out rootCA.key 2048
$ openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -out rootCA.pem 
$ openssl genrsa -out device.key 2048 
$ openssl req -new -key device.key -subj "/CN=$NGROK_DOMAIN" -out device.csr 
$ openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 5000

如果在第三步报错:

139632903422400:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/home/ubuntu/.rnd

删除 /usr/lib/ssl/openssl.cnf 开头的 RANDFILE=...

执行完以上命令,在ngrok目录下会生成6个新的文件

device.crt device.csr device.key rootCA.key rootCA.pem rootCA.srl

替换证书

Ngrok通过bindata将ngrok源码目录下的 assets 目录打包到可执行文件( ngrokd ngrok )中去, assets/client/tls assets/server/tls 下分别存放着用于 ngrok ngrokd 的默认证书文件,我们需要将它们替换成我们自己生成的。

$ cp rootCA.pem assets/client/tls/ngrokroot.crt
$ cp device.crt assets/server/tls/snakeoil.crt
$ cp device.key assets/server/tls/snakeoil.key

编译

选择对应平台的编译方式,编译服务端

$ GOOS=linux GOARCH=amd64 make release-server

如果这步速度慢超时,手动拉一个文件

$ git clone https://gopkg.in/yaml.v1 : ~/ngrok/src/gopkg.in/yaml.v1

编译客户端

$ GOOS=darwin GOARCH=amd64 make release-client

编译完成后 ~/ngrok/bin/ngrokd 为服务端运行文件, ngrok/bin/darwin_amd64/ngrok 为客户端运行文件。将服务端文件放到 /usr/bin/ 下就可以直接执行了。将客户端文件下载到自己的电脑上。

$ sudo cp ~/ngrok/bin/ngrokd /usr/bin/
$ scp <your user name>@<your ip>:<your generated client path> <your save path>

运行

服务端运行

$ sudo ngrokd -domain="mytencent.com" -httpAddr=":6000"

客户端目录下放一个配置文件 grok.conf

server_addr: "mytencent.mt:4443"
trust_host_root_certs: false

运行

$ ./ngrok -config=ngrok.conf -subdomain=test 8080

没问题的话应该可以看到如下界面,本地和云服务器成功建立了一个信道。当有请求云端6000端口的http请求时,请求会通过云服务器转发到我们本地的80端口。



我们在本地起个服务测试一下。用Flask快速起一个网页。

from flask import Flask
app = Flask(__name__)