【Redis核心原理和应用实践】拓展 9:隔墙有耳 —— Redis 安全通信

想象这样一个应用场景,公司有两个机房。因为一个紧急需求,需要跨机房读取 Redis 数据。应用部署在 A 机房,存储部署在 B 机房。如果使用普通 tcp 直接访问,因为跨机房所以传输数据会暴露在公网,这非常不安全,客户端服务器交互的数据存在被窃听的风险。

Redis 本身并不支持 SSL 安全链接,不过有了 SSL 代理软件,我们可以让通信数据透明地得到加密,就好像 Redis 穿上了一层隐身外套一样。spiped 就是这样的一款 SSL 代理软件,它是 Redis 官方推荐的代理软件。 

spiped 原理

让我们放大细节,仔细观察 spiped 实现原理。spiped 会在客户端和服务器各启动一个 spiped 进程。 

左边的 spiped 进程 A 负责接受来自 Redis Client 发送过来的请求数据,加密后传送到右边的 spiped 进程 B。spiped B 将接收到的数据解密后传递到 Redis Server。然后 Redis Server 再走一个反向的流程将响应回复给 Redis Client。 
每一个 spiped 进程都会有一个监听端口 (server socket) 用来接收数据,同时还会作为一个客户端 (socket client) 将数据转发到目标地址。 
spiped 进程需要成对出现,相互之间需要使用相同的共享密钥来加密消息。 

spiped 使用入门 

安装 spiped,我用的是 Mac。 
> brew install spiped 
如果是 Linux,可以使用 apt-get 或者 yum 安装: 
> apt-get install spiped 
> yum install spiped 
使用 Docker 启动 redis-server,注意要绑定本机的回环 127.0.0.1; 
> docker run -d -p127.0.0.1:6379:6379 --name redis-server-6379 redis 
12781661ec47faa8a8a967234365192f4da58070b791262afb8d9f64fce61835 
> docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED                  
STATUS              PORTS                      NAMES 
12781661ec47        redis               "docker-entrypoint.s…"   Less than a second ago   Up 1 
second         127.0.0.1:6379->6379/tcp   redis-server-6379 
    生成随机的密钥文件; 
# 随机的 32 个字节 
> dd if=/dev/urandom bs=32 count=1 of=spiped.key 
1+0 records in 
1+0 records out 
32 bytes transferred in 0.000079 secs (405492 bytes/sec) 
> ls -l 
rw-r--r--  1 qianwp  staff  32  7 24 18:13 spiped.key 
    使用密钥文件启动服务器 spiped 进程,172.16.128.81 是我本机的公网 IP 地址; 
# -d 表示 decrypt(对输入数据进行解密),-s 为源监听地址,-t 为转发目标地址 
> spiped -d -s '[172.16.128.81]:6479' -t '[127.0.0.1]:6379' -k spiped.key 
> ps -ef|grep spiped 
501 30673     1   0  7:29 下午 ??         0:00.04 spiped -d -s [172.16.128.81]:6479 -t 
[127.0.0.1]:6379 -k spiped.key 
这个 spiped 进程监听公网 IP 的 6479 端口接收公网上的数据,将数据解密后转发到本机回环地址的 6379 端口,也就是 redis-server 监听的端口。 
    使用密钥文件启动客户端 spiped 进程,172.16.128.81 是我本机的公网 IP 地址; 
# -e 表示 encrypt,对输入数据进行加密 
> spiped -e -s '[127.0.0.1]:6579' -t '[172.16.128.81]:6479' -k spiped.key 
> ps -ef|grep spiped 
501 30673     1   0  7:29 下午 ??         0:00.04 spiped -d -s [172.16.128.81]:6479 -t 
[127.0.0.1]:6379 -k spiped.key 
501 30696     1   0  7:30 下午 ??         0:00.03 spiped -e -s [127.0.0.1]:6579 -t 
[172.16.128.81]:6479 -k spiped.key 
客户端 spiped 进程监听了本地回环地址的 6579 端口,将该端口上收到的数据加密转发到服务器 spiped 进程。 
启动客户端链接,因为 Docker 里面的客户端不好访问宿主机的回环地址,所以 Redis 的客户端我们使用 Python 代码来启动; 
>> import redis 
>> c=redis.StrictRedis(host="localhost", port=6579) 
>> c.ping() 
>> c.info('cpu') 
{'used_cpu_sys': 4.83, 
 'used_cpu_sys_children': 0.0, 
 'used_cpu_user': 0.93, 
 'used_cpu_user_children': 0.0} 
可以看出客户端和服务器已经通了,如果我们尝试直接链接服务器 spiped 进程 (加密的端口 6379),看看会发生什么。 
>>> import redis 
>>> c=redis.StrictRedis(host="172.16.128.81", port=6479) 
>>> c.ping() 
Traceback (most recent call last): 
  File "<stdin>", line 1, in <module> 
  File "/Users/qianwp/source/animate/juejin-redis/.py/lib/python2.7/site-packages/redis/client.py", line 777, 
in ping 
    return self.execute_command('PING') 
  File "/Users/qianwp/source/animate/juejin-redis/.py/lib/python2.7/site-packages/redis/client.py", line 674, 
in execute_command 
    return self.parse_response(connection, command_name, **options) 
  File "/Users/qianwp/source/animate/juejin-redis/.py/lib/python2.7/site-packages/redis/client.py", line 680, 
in parse_response 
    response = connection.read_response() 
  File "/Users/qianwp/source/animate/juejin-redis/.py/lib/python2.7/site-packages/redis/connection.py", 
line 624, in read_response 
    response = self._parser.read_response() 
  File "/Users/qianwp/source/animate/juejin-redis/.py/lib/python2.7/site-packages/redis/connection.py", 
line 284, in read_response 
    response = self._buffer.readline() 
  File "/Users/qianwp/source/animate/juejin-redis/.py/lib/python2.7/site-packages/redis/connection.py", 
line 216, in readline 
    self._read_from_socket() 
  File "/Users/qianwp/source/animate/juejin-redis/.py/lib/python2.7/site-packages/redis/connection.py", 
line 191, in _read_from_socket 
    (e.args,)) 
redis.exceptions.ConnectionError: Error while reading from socket: ('Connection closed by server.',) 
从输出中可以看出来请求是发送过去了,但是却出现了读超时,要么是服务器在默认的超时时间内没有返回数据,要么是服务器没有返回客户端想要的数据。 
spiped 可以同时支持多个客户端链接的数据转发工作,它还可以通过参数来限定允许的最大客户端连接数。但是对于服务器 spiped,它不能同时支持多个服务器之间的转发。意味着在集群环境下,需要为每一个 server 节点启动一个 spiped 进程来代收消息,在运维实践上这可能会比较繁琐。 

作业 

请读者将 Redis 替换成 MySQL 来体验一下 spiped 的神奇魔力。 

发布了152 篇原创文章 · 获赞 50 · 访问量 43万+

猜你喜欢

转载自blog.csdn.net/shenchaohao12321/article/details/88147920