本文从 Valkey 的角度介绍了安全主题。它涵盖了 Valkey 提供的访问控制、代码安全问题、通过选择恶意输入从外部触发的攻击以及其他类似主题。
有关安全相关联系方式,请在 GitHub 上开一个 issue,或者当你认为保护通信安全非常重要时,请使用本文档末尾的 GPG 密钥。
安全模型
Valkey 旨在由受信任环境中的受信任客户端访问。这意味着通常不建议将 Valkey 实例直接暴露给互联网,或者通常暴露给不受信任的客户端可以直接访问 Valkey TCP 端口或 UNIX 套接字的环境。
例如,在将 Valkey 用作数据库、缓存或消息传递系统的常见 Web 应用程序上下文中,应用程序前端(Web 侧)的客户端将查询 Valkey 以生成页面或执行 Web 应用程序用户请求或触发的操作。
在这种情况下,Web 应用程序在 Valkey 和不受信任的客户端(访问 Web 应用程序的用户浏览器)之间进行访问中介。
通常,对 Valkey 的非受信任访问应始终由实现 ACL、验证用户输入并决定对 Valkey 实例执行哪些操作的层进行中介。
网络安全
除了网络中受信任的客户端外,应拒绝所有其他人访问 Valkey 端口,因此运行 Valkey 的服务器应仅由使用 Valkey 的应用程序所在的计算机直接访问。
在直接暴露于互联网的单台计算机(例如虚拟化的 Linux 实例(Linode、EC2 等))的常见情况下,应使用防火墙保护 Valkey 端口,以防止外部访问。客户端仍然能够使用环回接口访问 Valkey。
请注意,可以通过在 valkey.conf 文件中添加如下一行来将 Valkey 绑定到单个接口
bind 127.0.0.1
未能保护 Valkey 端口免受外部攻击可能会产生巨大的安全影响,因为 Valkey 的性质使然。例如,外部攻击者可以使用单个 FLUSHALL
命令删除整个数据集。
保护模式
不幸的是,许多用户未能保护 Valkey 实例免受外部网络的访问。许多实例只是简单地暴露在互联网上,拥有公共 IP。当 Valkey 以默认配置(绑定所有接口)并且在没有密码的情况下运行时,它会进入一种称为保护模式的特殊模式。在此模式下,Valkey 仅回复来自环回接口的查询,并向从其他地址连接的客户端返回一个错误,解释问题以及如何正确配置 Valkey。
我们期望保护模式能够大大减少由于未受保护的 Valkey 实例在没有适当管理的情况下执行而导致的安全问题。然而,系统管理员仍然可以忽略 Valkey 给出的错误并禁用保护模式或手动绑定所有接口。
认证
Valkey 提供两种方式来认证客户端。推荐的认证方法是通过访问控制列表 (Access Control Lists),允许创建命名用户并分配细粒度权限。在此处阅读更多关于访问控制列表的信息。
旧版认证方法通过编辑 valkey.conf 文件并使用 requirepass
设置提供数据库密码来启用。此密码将由所有客户端使用。
当启用 requirepass
设置时,Valkey 将拒绝未经认证的客户端的任何查询。客户端可以通过发送 AUTH 命令后跟密码来认证自己。
密码由系统管理员以明文形式设置在 valkey.conf 文件中。它应该足够长以防止暴力破解攻击,原因有二:
- Valkey 处理查询的速度非常快。外部客户端每秒可以测试许多密码。
- Valkey 密码存储在 valkey.conf 文件和客户端配置中。由于系统管理员不需要记住它,因此密码可以非常长。
认证层的目标是可选地提供一个冗余层。如果防火墙或任何其他用于保护 Valkey 免受外部攻击的系统失败,外部客户端在不知道认证密码的情况下仍然无法访问 Valkey 实例。
由于 AUTH
命令与所有其他 Valkey 命令一样都是未加密发送的,因此它不能防止有足够网络访问权限进行窃听的攻击者。
TLS 支持
Valkey 可选择支持所有通信通道的 TLS,包括客户端连接、复制链接和 Valkey Cluster 总线协议。
由外部客户端恶意输入触发的攻击
有一类攻击,攻击者即使没有对实例的外部访问权限也可以从外部触发。例如,攻击者可能会将数据插入 Valkey,从而在 Valkey 内部实现的数据结构上触发病态(最坏情况)算法复杂度。
攻击者可以通过网络表单提供一组已知在哈希表中散列到同一桶的字符串,从而将 O(1) 预期时间(平均时间)变为 O(N) 最坏情况。这可能会消耗比预期更多的 CPU,并最终导致拒绝服务。
为了防止这种特定攻击,Valkey 为哈希函数使用了每个执行的伪随机种子。
Valkey 使用 qsort 算法实现 SORT 命令。目前,该算法不是随机的,因此通过仔细选择正确的输入集,有可能触发二次最坏情况行为。
字符串转义和 NoSQL 注入
Valkey 协议没有字符串转义的概念,因此在正常情况下使用普通客户端库进行注入是不可能的。该协议使用前缀长度字符串,并且是完全二进制安全的。
由于 EVAL
和 EVALSHA
命令执行的 Lua 脚本遵循相同的规则,因此这些命令也是安全的。
虽然这是一个奇怪的用例,但应用程序应避免从不可信来源获取字符串来构成 Lua 脚本的主体。
代码安全
在内部,Valkey 遵循所有编写安全代码的众所周知实践,以防止缓冲区溢出、格式错误和其他内存损坏问题。
Valkey 不需要 root 权限即可运行。建议将其作为非特权 valkey 用户运行,该用户仅用于此目的。