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

一、安全

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

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

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

[html] view plaincopyprint?

  1. bind 127.0.0.1

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

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

[html] view plaincopyprint?

  1. requirepass TAFK(@~!ji^XALQ(sYh5xIwTn5Ds7JF

客户端每次连接到Redis时都需要发送密码,否则Redis会拒绝执行客户端发来的命令。例如:

[html] view plaincopyprint?

  1. redis>GET foo
  2. (error)ERR operation not permitted

发送密码需要使用AUTH命令,就像这样:

[html] view plaincopyprint?

  1. AUTH TAFK(@~!ji^XALQ(sYh5xIwTn5Ds7JF
  2. OK

之后就可以执行任何命令了:

[html] view plaincopyprint?

  1. redis>GET foo
  2. "1"

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

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

[html] view plaincopyprint?

  1. rename-command  FLUSHALL oyfekmjvmwxq5a9c8usofuo369x0it2k

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

[html] view plaincopyprint?

  1. 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程序测试:

[html] view plaincopyprint?

  1. telnet 127.0.0.1 6379
  2. Trying 127.0.0.1...
  3. Connected  to localhost.
  4. Escape character is ‘^]‘ .
  5. SET foo bar
  6. +OK
  7. GET foo
  8. $3
  9. bar
  10. LPUSH plist 1 2 3
  11. :3
  12. LRANGE plist 0 -1
  13. *3
  14. $1
  15. 3
  16. $1
  17. 2
  18. $1
  19. 1
  20. ERRORCOMMAND
  21. -ERR unknown command  ‘ERRORCOMMAND‘

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

[html] view plaincopyprint?

  1. C:SET foo 3
  2. C:bar
  3. S:+OK

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

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

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

[html] view plaincopyprint?

  1. -ERR unknown command ‘ERRORCOMMAND‘\r\n

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

[html] view plaincopyprint?

  1. +OK\r\n

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

[html] view plaincopyprint?

  1. :3\r\n

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

[html] view plaincopyprint?

  1. $3\r\nbar\r\n

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

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

[html] view plaincopyprint?

  1. *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进行演示:

[html] view plaincopyprint?

    1. telnet 127.0.0.1 6379
    2. Trying 127.0.0.1...
    3. Connected to localhost.
    4. Escape character is ‘^]‘ .
    5. *3
    6. $3
    7. SET
    8. $3
    9. foo
    10. $3
    11. bar
    12. +OK
    13. http://www.youyuanapp.com/thread-11419-1-1.html
      http://www.youyuanapp.com/thread-11418-1-1.html
      http://www.youyuanapp.com/thread-11417-1-1.html
      http://www.youyuanapp.com/thread-11412-1-1.html
      http://www.youyuanapp.com/thread-11409-1-1.html
      http://www.youyuanapp.com/thread-11404-1-1.html
      http://www.youyuanapp.com/thread-11403-1-1.html
      http://www.youyuanapp.com/thread-11398-1-1.html
      http://www.youyuanapp.com/thread-11397-1-1.html
      http://www.youyuanapp.com/thread-11395-1-1.html
      http://yishujiayuanq.blog.163.com/blog/static/2447250612015025101147963/
      http://yishujiayuanq.blog.163.com/blog/static/2447250612015025101251829/
      http://yishujiayuanq.blog.163.com/blog/static/244725061201502510133740/
      http://yishujiayuanq.blog.163.com/blog/static/2447250612015025101653328/
      http://yishujiayuanq.blog.163.com/blog/static/2447250612015025101718995/
      http://yishujiayuanq.blog.163.com/blog/static/2447250612015025101738627/
      http://yishujiayuanq.blog.163.com/blog/static/2447250612015025101822599/
      http://yishujiayuanq.blog.163.com/blog/static/2447250612015025101841318/
      http://yishujiayuanq.blog.163.com/blog/static/2447250612015025101927982/
      http://yishujiayuanq.blog.163.com/blog/static/244725061201502510197287/
时间: 2024-10-14 21:59:22

Redis研究(十三)—安全和通信协议的相关文章

Redis研究(十二)—数据复制

在上一节中我们写了Redis的数据持久化 http://blog.csdn.net/wtyvhreal/article/details/42916503 通过持久化功能,Redis保证了即使在服务器重启的情况下也不会损失(或少量损失)数据.但是由于数据是存储在一台服务器上的,如果这台服务器的硬盘出现故障,也会导致数据丢失.为了避免单点故障,我们希望将数据库复制多个副本以部署在不同的服务器上,即使有一台服务器出现故障其他服务器依然可以继续提供服务.这就要求当一台服务器上的数据库更新后,可以自动将更

Redis研究(十一)—数据持久化

一. 持久化 Redis的强劲性能很大程度上是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中以某种形式同步到硬盘中,这一过程就是持久化. Redis支持两种方式的持久化,一种是RDB方式,一种是AOF方式.可以单独使用其中一种或将二者结合使用. 1. RDB方式 RDB方式的持久化是通过快照(snapshotting )完成的,当符合一定条件时Redis会自动将内存中的所有数据进行快照并存储在硬盘上.进行快照的条件可以由用户在配置文件中自定义,

Redis研究(六)—集合类型

一.介绍 一个集合类型(set)键可以存储至多2^32-1个字符串. 集合类型在Redis内部是使用值为空的散列表(hash table)实现的,所以操作的复杂度为O(1).多个集合类型键之间还可以进行并集.交集和差集运算. 二.命令 1.增加/删除元素 sadd key member srem key member sadd用来向集合中增加一个或者多个元素,如果键不存在则会自动创建.一个集合中不能有相同的元素,所以如果要加入的元素已经存在于集合中就会忽略这个元素.本命令的返回值是成功加入的元素

Redis研究(四)—散列类型

散列类型(hash)的键值也是一种字典结构,其存储了字段(field)和字段值的映射,但字段值只能是字符串,不支持其他数据类型. 散列类型不能嵌套其他的数据类型.一个散列类型键可以包含至多2^32-1个字段. 一.介绍 散列类型适合存储对象:使用对象类别和ID构成键名,使用字段表示对象的属性,而字段值则存储属性值. 如果要关系数据中存储汽车对象: 数据是以二维表的形式存储的,这就要求所有的记录都有同样的属性,无法单独为某条记录增减属性.如果想要为ID为1的汽车增加生产日期属性,就需要把数据表更改

Redis研究(十四)—管理工具

工欲善其事,必先利其器.在使用Redis的时候如果能够有效利用Redis的各种管理工具,将会大大方便开发和管理. 一. redis-cli 相信大家对redis-cli已经很熟悉了,作为Redis自带的命令行客户端,你可以从任何安装有Redis的服务器中找到它,所以对于管理Redis 而言redis-cli是最简单实用的工具.redis-cli可以执行大部分的Redis命令,包括查看数据库信息的INFO命令,更改数据库设置的 CONFIG命令和强制进行RDB快照的SAVE命令等,下面会介绍几个管

Redis研究(十五)—任务队列

在网站开发中,当页面需要进行如发送邮件.复杂数据运算等耗时较长的操作时会阻塞页面的渲染.为了避免用户等待太久,应该使用独立的线程来完成这类操作. 不过一些编程语言或框架不易实现多线程,这时很容易就会想到通过其他进程来实现.设想有一个进程能够完成发邮件的功能,那么在页面中只需要想办法通知这个 进程向指定的地址发送邮件就可以了. 通知的过程可以借助任务队列来实现.任务队列顾名思义,就是“传递任务的队列”.与任务队列进行交互的实体有两类,一类是生产者(producer),一类是消费者(consumer

Redis研究-3.1 数据结构之链表

我们知道,数据结构中,链表的最大好处就是能高效的实现动态增.删.改,缺点就是遍历访问比较慢,因此,在Redis中,很多功能的底层实现都是基于链表的,因为Redis是基于C语言来写的,所以只能自己实现自己的链表结构.对于一个常规的双向链表节点,我们通常使用下面的方式来定义: typedef struct Node{ void *value; struct Node *prev; struct Node *next; }Node; Redis中,在adlist.h中也是这样子定义的 typedef

(转)Redis研究(一)—简介

http://blog.csdn.net/wtyvhreal/article/details/41855327 Redis是一个开源的高性能键值对数据库.它通过提供多种键值数据类型来适应不同场景下的存储需求,并借助许多高层级的接口使其可以胜任如缓存.队列系统等不同的角色. 1.1历史和发展 2008年,意大利一家创业公司Merzia的创始人Salvatore Sanfilippo为了避免MySQL的低性能,亲自定做一个数据库,并于2009年开发完成,这个就是redis. 短短几年,用户数据量猛增

Redis研究(十六)—发布/订阅模式

在上一篇中我们写了Redis的任务队列. 除了实现任务队列外,Redis还提供了一组命令可以让开发者实现"发布/订阅"(publish/subscribe)模式."发布/订阅"模式同样可以实现进程间的消息传递,其原理是这样的: "发布/订阅"模式中包含两种角色,分别是发布者和订阅者.订阅者可以订阅一个或若干个频道(channel),而发布者可以向指定的频道发送消息,所有订阅此频道的订阅者都会收到此消息. 发布者发布消息的命令是PUBLISH,用法