加密隧道技术

        在现在的互联网上传输数据,首要考虑的就是安全。这关乎到你的隐私,个人信息,财产安全等等重大问题。如果你的程序本身传输的信息没有加密,也可以通过其他辅助方式让你的通信加密。一些工具的就是为了解决这样的场景的,即数据先通过源端代理,让你的所有通信数据都加密,然后到达目的后再使用目的端代理进行解密后转发给目标进程。即加密隧道的简单示意图如下所示:

       加密隧道的始末即为源端代理和目的端代理。其中数据发送进程和源端代理可以是同在一个主机的不同进程,也可以是分属不同的主机。目的端代理和数据接收进程也一样。如果你也不希望你的数据有任何的明文信息在互联网上传输,你就可以使用加密隧道技术。当然,如果你的数据发送进程和数据接收进程之间的网络通信本身就是加密的,那就不用借助中间的代理环节。

        这种独立于应用本身的加密隧道技术,有一个很明显的优点是它对收发数据的双方完全透明,收发数据的双方不需要任何的变更。另外收发数据的应用因为不用处理加解密数据,应用本身的开发的难度和复杂度也会降低,间接达到解耦的目的。

加密隧道的应用        

        这种加密隧道的一个典型应用是是对http代理的数据进行加密。http代理本身是可以既代理http协议数据,也可以代理https数据的,但是http代理协议的头部还是明文传输的。比如你的浏览器需要通过http代理访问www.bing.com,那么,浏览器发给http代理的协议数据是下面这样的:

Ncat: Connection from 192.168.56.1:51472.
CONNECT www.bing.com:443 HTTP/1.1
Host: www.bing.com:443
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0

        你会发现这完全是明文传输,只要在中间传输的环节截获你这个报文,就知道你要访问的是哪个网址,如果你要访问的地址被认为非法,那么你的报文会直接被丢弃。上面的http头部和普通的http头部有点区别的就是使用的CONNECT方法,这个方法指示代理服务器,让其代理访问目标主机。所以这种也称为CONNECT代理。

        此时就可以使用加密隧道技术,把处于浏览器到代理服务器之间的数据都加密传输。 例如可以在本地局域网的网关部署一个加密隧道源端代理,在http代理服务器机器上或者在其局域网内部署一个加密隧道的目的端代理,目的代理解密后的数据全部转发给http代理服务器。那样我们浏览器的数据就不会在因特网上明文传输了。

加密隧道技术的实现

      这种独立于应用本身的加密隧道技术,还是有不少的。

1、stunnel

        第一种加密隧道技术,当选stunel。stunnel应该能达到企业级的应用标准,stunnel的设计初衷就是为了单纯的建立加密隧道,当然可以覆盖所有场景。stunnel这个我目前还在使用。具体的应用可以参考我的另一篇博文:stunnel 配置(contos7 windows) - 知乎 (zhihu.com)

2、nginx建立加密隧道

        nginx作为网关,我们做IT的一般都知道。完全能满足企业级的应用需求。同时支持高并发和高可靠性。我们用ngixn建立加密隧道也很简单,下面介绍一下使用nginx建立加密隧道的配置

(1)nginx源端代理(客户端)

        配置文件nginx.conf如下:

user root;
worker_processes  4;

events {
    worker_connections  100000;
}

stream {
    server {
        listen 9999;  # 监听9999端口
        proxy_pass 2.2.2.2:9999;  # 将流量加密后转发到2.2.2.2:9999
        proxy_ssl on;  # 启用SSL代理
        proxy_ssl_verify on;  # 启用SSL验证,校验上游服务器的证书,默认是off不验证
        proxy_ssl_trusted_certificate ../certs/ca.crt;  # 指定可信的CA证书,用于服务端证书的校验
        proxy_ssl_protocols TLSv1.2 TLSv1.3;  # 指定SSL协议版本
        proxy_ssl_session_reuse on;  # 启用SSL会话复用
        proxy_ssl_certificate ../certs/client.crt;  # 客户端SSL证书
        proxy_ssl_certificate_key ../certs/client.key;  # 客户端SSL证书私钥
        proxy_ssl_verify_depth 2;  # SSL验证深度
        proxy_ssl_name myserver;  # 服务器端证书的CN(Common Name)名称,如果不一致会握手失败
        proxy_ssl_server_name on;  # 启用SSL服务器名称

    }
}

         上面的nginx客户端配置了双向认证,nginx的双向认证会额外校验服务端证书中的Common Name,如果我们没有按服务端证书的CN配置,客户端在校验服务端证书的时候就会因为CN不一致导致校验失败。proxy_ssl_name myserver;这个配置就是通知服务端,我需要的是CN为"myserver"的证书。

        以上的客户端就是将发往本地9999端口的数据加密后转发至2.2.2.2:9999

 (2)nginx目的端代理(服务端)

         服务端的配置nginx.conf如下:

#user  nobody;
user root;
worker_processes  4;

events {
    worker_connections  65535;
}

stream {
    server {
        listen 9999 ssl;  # 监听9999端口并启用SSL
		server_name ssl-tunnel-server;
        ssl_certificate ../certs/server.crt;  # SSL证书路径
        ssl_certificate_key ../certs/server.key;  # SSL证书私钥路径
        ssl_client_certificate ../certs/ca.crt;  # 指定可信的CA证书
        ssl_verify_client on;  # 启用客户端SSL验证,那么就需要配置ca证书,就是上面的ssl_client_certificate指定的ca证书
        proxy_pass 127.0.0.1:4433;  # 将流量转发到本地端口4433
    }
}

        以上的配置是将服务器端的9999端口的数据,解密后转发到本地的4433端口 

        

3、ssh加密隧道 

   (1)ssh本地端口转发

        我们常用的ssh命令,很多人都只是用来做远程登录工具的。其实它还有一个作用是给我们建立一条加密隧道,从而让我们通过这条加密隧道,安全的访问远程主机。并且ssh加密隧道的建立不需要我们做任何额外的配置,只需要一条命令就能完成。命令如下:

ssh -f -L 0.0.0.0:9999:113.104.189.18:6379 root@1.1.1.1 -N -g

-f是让ssh命令能在后台运行,直到有连接到来才转入前台运行

-L后面跟本地监听端口以及将数据转发到达的远程主机的ip端口,即两组ip端口,即local_ip:local_port:remote_ip:remote_port的格式,如果本地绑定任意ip,0.0.0.0也可以不写出来,只用9999:113.104.189.18:6379.其中remote_ip:port是想访问的任意远程主机ip和端口,也可以是ssh服务器端所在主机的ip端口

-N 是告诉远程主机,只负责转发隧道数据,不执行任何命令。没有这个参数,ssh对端收到后一般是要执行这个命令的,也就是正常的远程shell的功能。

-g 参数,是为了使当前ssh隧道能被除本机外的进程使用,没有该选项,默认只有本地数据包可以通过该隧道,也是一种安全机制,防止在非授权的情况下被其他主机使用

root@1.1.1.1是远程主机的ip和用户名,也可以在后面用":port"添加端口,默认都是22端口。

假设ssh客户端所在主机的ip是192.169.56.2,则执行完成后建立的加密隧道示意图如下:

        数据发送主机和ssh客户端主机可以是在同一台,数据接收主机和ssh服务端主机也可以是同一台 。图中用***表示的是系统随机分配的端口。这时候你会发现这个ssh隧道还有一个很好的用处,就是能绕过防火墙。假如ssh服务端主机防火墙只开放了22端口(这个是ssh端口,一般服务器都会开放),但是你要访问该主机的其他端口,怎么办,用这个ssh隧道,就能做一个端口转发,将22端口的数据转发给其他端口,比如80端口。

        用ssh建立加密隧道,只是用作暂时的,一旦某个时候连接断开后,就不会重连了,需要重新执行这个命令。这就不能作为提供长久通道的服务,这就是有很大的局限性

(2)ssh远程端口转发(内网穿透)

        除了上面提到的使用ssh本地端口转发建立加密隧道外,还有一个很有用的功能是远程端口转发,这也是一条加密隧道。远程端口转发一个非常得心应手的应用场景是可以进行内网穿透。

        有这样的场景,我们在局域网里面有一台主机192.168.1.1,因为在局域网里面我们是没法进行ssh登录的。如果我们有一台公网主机1.1.1.1,在局域网主机上执行远程端口转发,把发往公网主机某个端口(比如222)的数据转发到局域网网主机的22端口,那么我们只要访问公网主机1.1.1.1的222端口,就能远程登录到我们处于局域网的主机192.168.1.1,实现内网穿透。

        远程端口转发示例如下:

ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -R 222:127.0.0.1:22 root@1.1.1.1 -N -f

-R 参数指明进行远程端口转发,将远程主机1.1.1.1 222端口的数据转发到本地的22端口

 -o ServerAliveInterval=60 -o ServerAliveCountMax=3 这两个参数是连接保活,避免长时间没有通信被断掉。

        如果想要建立长久的连接,避免某个时间ssh连接断开后就需要重新连接,可以做一些辅助工作,局域网主机192.168.1.1和公网主机1.1.1.1直接使用公钥免密登录,然后配合screen命令,在连接断开后使用脚本进行免密重连。

下面是简单的例子:

0、前提是要在公网主机上配置局域网主机的公钥免密登录,不懂的可以自行谷歌

1、先编写一个脚本continuous-ssh.sh

# !/bin/bash
while [ true ]
do
# 先清理有可能还存在的ssh进程,避免监听失败
ssh root@1.1.1.1 << 'ENDSSH'
netstat -nltp | awk '{if (index($4,":222") != 0 && index($7,"sshd") != 0){;split($7,arr,"/"); cmd="kill -TERM "arr[1];system(cmd);}}'
ENDSSH
ssh -v -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -R 222:127.0.0.1:22 root@1.1.1.1 -N
sleep 1
done

 上面加-v参数,会输出一些信息,因为是在screen内部,不会影响其他会话和命令的执行。

2、然后在局域网主机执行

screen -dmS continuous-ssh ./continuous-ssh.sh

执行完后可以使用screen -ls查看,或者直接screen -r continuous-ssh进入查看是否成功,使用ctrl+A+D退出screen(里面的程序继续运行)

3、在公网主机上对局域网主机进行ssh登录

ssh root@127.0.0.1 -p 222

        这样就能得到一个永不掉线的ssh连接,连接暂时中断后也会继续重连,让你不会失去局域网主机的控制。

4、ncat建立加密隧道

        ncat是nc的加强版,nc本身不支持建立ssl连接,但是ncat是可以的。但是ncat在支持多连接的时候代价会比较大,因为每建立一个连接就要创建一个新进程处理,对于需要建立多连接的场景不建议使用。下面是例子:

(1)ncat目的端代理

        ncat -v -k -l  --ssl --ssl-verify  --ssl-cert crt/server.crt --ssl-key crt/server.key --ssl-trustfile crt/ca.crt -p 3333 -c "ncat 127.0.0.1 5555"

        上面命令是在服务端机器上启动一个ssl监听端口,一旦有连接到来,就执行命令"ncat 127.0.0.1 5555",这个命令是连接目标ip端口,然后把接收到的数据转发到目标ip端口。可以看出,这个过程是存在两个独立的进程来完成的,一个是作为ssl服务器端,另一个是连接目标ip端口的客户端,这两个进程之间的通信使用管道进行。

(2)ncat源端代理

        ncat -v -k -l  -p 5554 -c "ncat -u --ssl --ssl-cert crt/client.crt --ssl-key crt/client.key --ssl-verify --ssl-trustfile crt/ca.crt --ssl-servername 18.211.144.206 192.168.56.105 3333"

        上面启动一个tcp监听端口5554,当接受一个连接后,执行命令"ncat -u --ssl --ssl-cert crt/client.crt --ssl-key crt/client.key --ssl-verify --ssl-trustfile crt/ca.crt --ssl-servername myserver 192.168.56.105 3333",这个命令是使用ssl连接远端的ssl服务器(192.168.56.105:3333),然后把数据都往建立的ssl连接上转发。--ssl-servername参数是指定需要访问的服务端名称,也就是服务端ssl证书的CommonName字段名称。

        其实ncat建立加密隧道的确不太适合,因为太耗资源。不管是在源端的代理还是目的端的代理,都需要两个进程才能完成。优点是ncat不用安装和进行繁琐的配置,即使需要安装也直接用yum install或者apt-get install就可以安装完成。临时救急也是可以的。另外推荐使用socat,socat做端口转发最方便不过了

        另外VPN也可以作为加密隧道,其实VPN本身和外部的通信就是加密的,我们可以借助这个加密通道做任何事而不用担心被别人窥探到。比如你浏览器访问的任何地址,如果你都是通过VPN服务器作为出口的话,别人即使在中途截获了你的请求数据,只知道是这台VPN服务器访问了某个网址,而无法得知是这个VPN网络中的哪一个用户,因为明文的http头部信息只能在VPN服务器到目标网址之间被截获,而不可能在你的主机到VPN服务器之间被截获。

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值