Redis研究(十三)—安全和通信协议

一、安全

      Redis的作者Salvatore Sanfilippo曾经发表过Redis宣言,其中提到Redis以简洁为美。同样在安全层面Redis也没有做太多的工作。

1、可信的环境
      Redis的安全设计是在“Redis运行在可信环境”这个前提下做出的,在生产环境运行时不能允许外界直接连接到Redis服务器上,而应该通过应用程序进行中转,运行在可信的环境中是保证Redis安全的最重要方法。

      Redis的默认配置会接受来自任何地址发送来的请求,即在任何一个拥有公网IP的服务器上启动Redis服务器,都可以被外界直接访问到。要更改这一设置,在配置文件中修改bind参数,如只允许本机应用连接Redis,可以将bind参数改成:

bind 127.0.0.1
bind参数只能绑定一个地址。如果想更自由地设置访问规则需要通过防火墙来完成。
注释:Redis可能会在2.8版本中支持绑定多个地址,参见https://github.com/antirez/redis/issues/274。


2、数据库密码
       除此之外,还可以通过配置文件中的requirepass参数为Redis设置一个密码。例如:

requirepass TAFK(@~!ji^XALQ(sYh5xIwTn5Ds7JF
客户端每次连接到Redis时都需要发送密码,否则Redis会拒绝执行客户端发来的命令。例如:
redis>GET foo
(error)ERR operation not permitted

发送密码需要使用AUTH命令,就像这样:
AUTH TAFK(@~!ji^XALQ(sYh5xIwTn5Ds7JF
OK

之后就可以执行任何命令了:
redis>GET foo
"1"

      由于Redis的性能极高,并且输入错误密码后Redis并不会进行主动延迟(考虑到Redis的单线程模型),所以攻击者可以通过穷举法破解Redis的密码(1秒内能够尝试十几万个密码),因此在设置时一定要选择复杂的密码。
      配置Redis复制的时候如果主数据库设置了密码,需要在从数据库的配置文件中通过masterauth 参数设置主数据库的密码,以使从数据库连接主数据库时自动使用AUTH命令认证。


3、命名命令
      Redis支持在配置文件中将命令重命名,比如将FLUSHALL 命令重命名成一个比较复杂的名字,以保证只有自己的应用可以使用该命令。就像这样:

rename-command  FLUSHALL oyfekmjvmwxq5a9c8usofuo369x0it2k

如果希望直接禁用某个命令可以将命令重命名成空字符串:
rename-command  FLUSHALL ""

注意:无论设置密码还是重命名命令,都需要保证配置文件的安全性,否则就没有任何意义了。


二、 通信协议

      Redis通信协议是Redis客户端与Redis之间交流的语言,通信协议规定了命令和返回值的格式。了解Redis通信协议后不仅可以理解AOF文件的格式和主从复制时主数据库向从数据库发送的内容等,还可以开发自己的Redis客户端(不过由于几乎所有常用的语言都有相应的Redis客户端,需要使用通信协议直接和Redis打交道的机会确实不多)。

      Redis支持两种通信协议,一种是二进制安全的统一请求协议(unified request  protocol),一种是比较直观的便于在telnet程序中输入的简单协议。这两种协议只是命令的格式有区别,命令返回值的格式是一样的。

1、简单协议
      简单协议适合在telnet程序中和Redis通信。简单协议的命令格式就是将命令和各个参数使用空格分隔开,如“EXISTS foo”、“SET foo bar”等。由于Redis解析简单协议时只是简单地以空格分隔参数,所以无法输入二进制字符。我们可以通过telnet程序测试:

telnet 127.0.0.1 6379
Trying 127.0.0.1...
Connected  to localhost.
Escape character is '^]' .
SET foo bar
+OK
GET foo
$3
bar
LPUSH plist 1 2 3
:3
LRANGE plist 0 -1
*3
$1
3
$1
2
$1
1
ERRORCOMMAND
-ERR unknown command  'ERRORCOMMAND'

     Redis 2.4之前的版本对于某些命令可以使用类似简单协议的特殊方式输入二进制安全的参数,例如:
C:SET foo 3
C:bar
S:+OK

其中C:表示客户端发出的内容,S:表示服务端发出的内容。第一行的最后一个参数表示字符串的长度,第二行是字符串的实际内容,因为指定了长度,所以第二行的字符串可以包含二进制字符。但是这个协议已经废弃,被新的统一请求协议取代。“统一”二字指所有的命令使用同样的请求方式而不再为某些命令使用特殊方式,如果需要在参数中包含二进制字符应该使用统一请求协议。


     我们在telnet程序中输入的5条命令恰好展示了Redis的5种返回值类型的格式,之前展现形式是经过了redis-cli封装的,而上面的内容才是Redis真正返回的格式。下面分别介绍。


(1)错误回复
错误回复(error reply )以-开头,并在后面跟上错误信息,最后以\r\n 结尾:
-ERR unknown command 'ERRORCOMMAND'\r\n

(2)状态回复
状态回复(status reply )以+开头,并在后面跟上状态信息,最后以\r\n 结尾:
+OK\r\n

(3)整数回复
整数回复(integer reply )以:开头,并在后面跟上数字,最后以\r\n 结尾:
:3\r\n

(4)字符串回复
字符串回复(bulk  reply )以$开头,并在后面跟上字符串的长度,并以\r\n 分隔,接着是字符串的内容和\r\n :
$3\r\nbar\r\n

如果返回值是空结果nil,则会返回$-1以和空字符串相区别。


(5)多行字符串回复
多行字符串回复(multi-bulk  reply )以*开头,并在后面跟上字符串回复的组数,并以\r\n 分隔。接着后面跟的就是字符串回复的具体内容了:
*3\r\n1\r\n3\r\n1\r\n2\r\n1\r\n1\r\n


2、 统一请求协议
      统一请求协议是从Redis 1.2开始加入的,其命令格式和多行字符串回复的格式很类似,如SET foo bar的统一请求协议写法是“*3\r\n3\r\nSET\r\n3\r\nfoo\r\n3\r\nbar\r\n ”。还是使用telnet进行演示:
telnet 127.0.0.1 6379
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]' .
*3
$3
SET
$3
foo
$3
bar
+OK

同样发送命令时指定了后面字符串的长度,所以命令的每个参数都可以包含二进制的字符。统一请求协议的返回值格式和简单协议一样,这里不再赘述。


      Redis的AOF文件和主从复制时主数据库向从数据库发送的内容都使用了统一请求协议。如果要开发一个和Redis直接通信的客户端,推荐使用此协议。如果只是想通过telnet向Redis服务器发送命令则使用简单协议就可以了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值