本文基于Redis 6.0.9版本,前提至少 Redis 3.0或更高版本。
目录
1.Redis安全
本文档从Redis的角度介绍了安全性主题:涵盖了Redis提供的访问控制,代码安全性问题,可以通过选择恶意输入从外部触发的攻击以及其他类似主题。
对于与安全性相关的联系人,请在GitHub上打开一个问题,或者当你认为保留通信的安全性非常重要时,请使用本文档末尾的GPG键。
1.1.Redis一般安全模型
Redis旨在供受信任环境中的受信任客户端访问。 这意味着通常不建议直接将Redis实例公开到Internet或通常在不受信任的客户端可以直接访问Redis TCP端口或UNIX套接字的环境中公开。
例如,在使用Redis作为数据库,缓存、消息传递系统、实现的Web应用程序的常见上下文中,应用程序前端(Web端)内部的客户端将查询Redis以生成页面或执行Web应用程序用户请求或触发的操作。
在这种情况下,Web应用程序会接受Redis与不受信任的客户端(访问Web应用程序的用户浏览器)之间的访问。
这是一个特定的示例,但是通常,对Redis的不可信访问应该始终由实现ACL,验证用户输入并决定要对Redis实例执行哪些操作。
1.2.网络安全
网络中除受信任的客户端外,所有其他人都应拒绝对Redis端口的访问,因此只有使用Redis实现应用程序的计算机才能直接访问运行Redis的服务器。
对于直接暴露于互联网的单台计算机(例如虚拟化Linux实例(Linode,EC2等))的常见情况,应该对Redis端口进行防火墙保护,以防止外部访问。 客户端仍然可以使用回送(loopback )接口访问Redis。
请注意,可以通过在redis.conf文件中添加如下一行来将Redis绑定到单个接口:
bind 127.0.0.1
由于Redis的性质,未能保护Redis端口不受外界影响可能会带来很大的安全影响。 例如,外部攻击者可以使用单个FLUSHALL 命令删除整个数据集。
1.3.保护模式
不幸的是,许多用户无法保护Redis实例不被外部网络访问。 许多实例只是通过公共IP暴露在Internet上。 由于这个原因,从版本3.2.0开始,使用默认配置(绑定所有接口)执行Redis且不使用任何密码即可对其进行访问时,它将进入一种称为保护模式的特殊模式。 在这种模式下,Redis仅回复来自回送(loopback )接口的查询,并回复其他从其他地址连接的客户端并显示错误,解释正在发生的事情以及如何正确配置Redis。
我们希望保护模式会严重降低由未经保护的Redis实例执行而导致的安全问题,但是系统管理员仍然可以忽略Redis给出的错误,而只是禁用保护模式或手动绑定所有接口。
1.4.认证功能
虽然Redis不会尝试实现访问控制,但它提供了一个很小的身份验证层,可以选择打开它来编辑redis.conf文件。
启用授权层后,Redis将拒绝未经身份验证的客户端的任何查询。 客户端可以通过发送AUTH命令和密码来对自己进行身份验证。
密码由系统管理员在redis.conf文件内以明文设置。 它应该足够长以防止暴力攻击,原因有两个:
- Redis在服务查询方面非常快。 外部客户端每秒可以测试许多密码。
- Redis密码存储在redis.conf文件和客户端配置内部,因此系统管理员无需记住该密码,因此它可能很长。
全局认证层的目标是可选地提供冗余层。 如果防火墙或为保护Redis免受外部攻击者而实施的任何其他系统失败,则外部客户端在不知道身份验证密码的情况下仍将无法访问Redis实例。
与其他Redis命令一样,AUTH命令也未加密地发送,因此它无法防止攻击者拥有对网络的足够访问权以执行窃听。
1.5.TLS支持
Redis在所有通信通道(包括客户端连接,复制链接和Redis Cluster总线协议)上对TLS的可选支持。
1.6.禁用特定命令
可以在Redis中禁用命令或将其重命名为无法猜测的名称,以便普通客户端只能使用一组指定的命令。
例如,虚拟服务器提供商可以提供托管Redis实例服务。 在这种情况下,普通用户可能不能调用Redis CONFIG命令来更改实例的配置,但是提供和删除实例的系统应该能够执行此操作。
在这种情况下,可以从命令表中重命名或完全隐藏命令。 该功能作为一条语句可用,可以在redis.conf配置文件中使用。 例如:
rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
在上面的示例中,CONFIG命令被重命名为一个不可猜测的名称。 也可以通过将其重命名为空字符串来完全禁用它(或任何其他命令),如以下示例所示:
rename-command CONFIG ""
1.7.由外部客户端精心选择的输入触发的攻击
即使没有外部访问实例,攻击者也可以从外部触发一类攻击。 这种攻击的一个例子是将数据插入Redis的能力,从而触发Redis内部实现的数据结构的病态的(最坏情况)算法复杂性。
例如,攻击者可以通过Web表单提供一组字符串,这些字符串已知会散列到同一存储桶中,成为散列表,从而将 O(1) 预期时间(平均时间)变为O(N) ,最坏的情况是,它消耗的CPU比预期的要多,并最终导致拒绝服务。
为了防止这种特定攻击,Redis将每个执行的伪随机种子用于哈希函数。
Redis使用qsort算法实现SORT命令。 当前,该算法尚未随机化,因此可以通过仔细选择正确的输入集来触发二次最坏情况行为。
1.8.字符串转义和NoSQL注入
Redis协议没有字符串转义的概念,因此在正常情况下无法使用正常的客户端库进行注入。 该协议使用前缀长度的字符串,并且完全是二进制安全的。
由EVAL和EVALSHA命令执行的Lua脚本遵循相同的规则,因此这些命令也是安全的。
尽管这将是一个非常奇怪的用例,但应用程序应避免使用从不受信任的来源获得的字符串来编写Lua脚本的主体。
1.9.代码安全
在传统的Redis设置中,允许客户端完全访问命令集,但是访问实例绝不能导致控制Redis运行所在系统的能力。
在内部,Redis使用所有众所周知的做法来编写安全代码,以防止缓冲区溢出,格式错误和其他内存损坏问题。 但是,使用CONFIG命令控制服务器配置的能力使客户端能够更改程序的工作目录和转储文件的名称。 这使客户端可以在随机路径上写入RDB Redis文件,这是一个安全问题,很容易导致破坏系统和/或与Redis运行同一用户一样运行不受信任的代码的能力。
Redis不需要root特权即可运行。 建议以仅用于此目的的非特权Redis用户身份运行它。 Redis作者目前正在研究添加新配置参数以防止CONFIG SET/GET dir和其他类似运行时配置指令的可能性。 这样可以防止客户端强制服务器在任意位置写入Redis转储文件。
1.10.GPG键
ohNVthFF2MGFRT4OZ5VvK7UcRLYTZoGRlKRGKi9HWea
2xFvyUd9jSuGZG/MMuoslgEPxei09rhDrKxnDNQzQZQpamm/42MITh/1dzEC5ZRx
8hgh1J70/c+zEU7s6kVSGvmYtqbV49/YkqAbhENIeZQ+bCxcTpojEhfk6HoQkXoJ
oK5m21BkMlUEvf1oTX22c0tuOrAX8k0y1M5oismT2e3bqs2OfezNsSfK2gKbeASk
CyYivnbTjmOSPbkvtb27nDqXjb051q6m2A5d59KHfey8BZVuV9j35Ettx4nrS1Ni
S7QrHWRvqceRrIrqXJKopyetzJ6kYDlbP+EVN9NJ2kz/WG6ermltMJQoC0oMhwAG
dfrttG+QJ8PCOlaYiZLD2bjzkDfdfanE74EKYWt+cseenZUf0tsncltRbNdeGTQb
1/GHfwJ+nbA1uKhcHCQ2WrEeGiYpvwKv2/nxBWZ3gwaiAwsz/kI6DQlPZqJoMea9
8gDK2rQigMgbE88vIli4sNhc0yAtm3AbNgAO28NUhzIitB+av/xYxN/W/LkCDQRS
e6LgARAAtdfwe05ZQ0TZYAoeAQXxx2mil4XLzj6ycNjj2JCnFgpYxA8m6nf1gudr
C5V7HDlctp0i9i0wXbf07ubt4Szq4v3ihQCnPQKrZZWfRXxqg0/TOXFfkOdeIoXl
Fl+yC5lUaSTJSg21nxIr8pEq/oPbwpdnWdEGSL9wFanfDUNJExJdzxgyPzD6xubc
OIn2KviV9gbFzQfOIkgkl75V7gn/OA5g2SOLOIPzETLCvQYAGY9ppZrkUz+ji+aT
Tg7HBL6zySt1sCCjyBjFFgNF1RZY4ErtFj5bdBGKCuglyZou4o2ETfA8A5NNpu7x
zkls45UmqRTbmsTD2FU8Id77EaXxDz8nrmjz8f646J0rqn9pGnIg6Lc2PV8j7ACm
/xaTH03taIloOBkTs/Cl01XYeloM0KQwrML43TIm3xSE/AyGF9IGTQo3zmv8SnMO
F+Rv7+55QGlSkfIkXUNCUSm1+dJSBnUhVj/RAjxkekG2di+Jh/y8pkSUxPMDrYEa
OtDoiq2G/roXjVQcbOyOrWA2oB58IVuXO6RzMYi6k6BMpcbmQm0y+TcJqo64tREV
tjogZeIeYDu31eylwijwP67dtbWgiorrFLm2F7+povfXjsDBCQTYhjH4mZgV94ri
hYjP7X2YfLV3tvGyjsMhw3/qLlEyx/f/97gdAaosbpGlVjnhqicAEQEAAYkCJQQY
AQIADwUCUnui4AIbDAUJXfwPAAAKCRAxgTcoDlyI1kAND/sGnXTbMvfHd9AOzv7i
hDX15SSeMDBMWC+8jH/XZASQF/zuHk0jZNTJ01VAdpIxHIVb9dxRrZ3bl56BByyI
8m5DKJiIQWVai+pfjKj6C7p44My3KLodjEeR1oOODXXripGzqJTJNqpW5eCrCxTM
yz1rzO1H1wziJrRNc+ACjVBE3eqcxsZkDZhWN1m8StlX40YgmQmID1CC+kRlV+hg
LUlZLWQIFCGo2UJYoIL/xvUT3Sx4uKD4lpOjyApWzU40mGDaM5+SOsYYrT8rdwvk
nd/efspff64meT9PddX1hi7Cdqbq9woQRu6YhGoCtrHyi/kklGF3EZiw0zWehGAR
2pUeCTD28vsMfJ3ZL1mUGiwlFREUZAcjIlwWDG1RjZDJeZ0NV07KH1N1U8L8aFcu
+CObnlwiavZxOR2yKvwkqmu9c7iXi/R7SVcGQlNao5CWINdzCLHj6/6drPQfGoBS
K/w4JPe7fqmIonMR6O1Gmgkq3Bwl3rz6MWIBN6z+LuUF/b3ODY9rODsJGp21dl2q
xCedf//PAyFnxBNf5NSjyEoPQajKfplfVS3mG8USkS2pafyq6RK9M5wpBR9I1Smm
gon60uMJRIZbxUjQMPLOViGNXbPIilny3FdqbUgMieTBDxrJkE7mtkHfuYw8bERy
vI1sAEeV6ZM/uc4CDI3E2TxEbQ==
1.11.键指纹
pub 4096R/0E5C88D6 2013-11-07 [expires: 2063-10-26]
Key fingerprint = E5F3 DA80 35F0 2EC1 47F9 020F 3181 3728 0E5C 88D6
uid Salvatore Sanfilippo <antirez@gmail.com>
sub 4096R/3B34D15F 2013-11-07 [expires: 2063-10-26]