连上 Redis 之后到底要经过什么才能执行命令?这篇把认证流程每一步的服务端回答量出来:没登录能做什么,几种登录方式,requirepass 和 ACL 是什么关系,改密码对老连接的影响,密码会不会漏到监控里,以及最关键的——错误密码能试多快。
> AUTH whatever (error) ERR AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?
> CONFIG SET requirepass S3cretPw "OK" > CONFIG GET requirepass 1) "requirepass" 2) "S3cretPw" PING → (error) NOAUTH Authentication required. GET k → (error) NOAUTH Authentication required. SET k v → (error) NOAUTH Authentication required. ECHO x → (error) NOAUTH Authentication required. INFO → (error) NOAUTH Authentication required. COMMAND COUNT → (error) NOAUTH Authentication required. CLIENT SETNAME x → (error) NOAUTH Authentication required. SELECT 0 → (error) NOAUTH Authentication required. HELLO 2 → (error) NOAUTH HELLO must be called with the client already authenticated, otherwise the HELLO <proto> AUTH <user> <pass> opt QUIT → "OK"
设了 requirepass 后,未登录连接发出的几乎任何命令都是 NOAUTH,包括 PING、INFO、HELLO 2(不带 AUTH)。QUIT 回 OK(它只是关连接)。
> AUTH wrongpw (error) WRONGPASS invalid username-password pair or user is disabled. > AUTH S3cretPw "OK" > ACL WHOAMI "default" > AUTH default S3cretPw "OK" > HELLO 2 AUTH default S3cretPw → 登录后 ACL WHOAMI = default > HELLO 2 AUTH default bad → (error) WRONGPASS invalid username-password pair or user is disabled.
错误的用户名、错误的密码、被 off 的用户,得到的是同一句 WRONGPASS,攻击者无法据此判断用户名是否存在。
> AUTH S3cretPw "OK" > ACL LIST 1) "user default on sanitize-payload #3556ff3510590c935379c2dda7554753f688a012855630f0b9979db3c58a0b3e ~* &* +@all" > ACL SETUSER default nopass "OK" > CONFIG GET requirepass 1) "requirepass" 2) "S3cretPw" > ACL LIST 1) "user default on nopass sanitize-payload ~* &* +@all" 现在 default 已是 nopass,但 CONFIG GET requirepass 还显示旧密码。再执行一次相同值的 CONFIG SET requirepass: > CONFIG SET requirepass S3cretPw "OK" > ACL LIST 1) "user default on nopass sanitize-payload ~* &* +@all" > ACL SETUSER default resetpass >S3cretPw "OK" 用 ACL SETUSER default resetpass >S3cretPw 恢复: > ACL LIST 1) "user default on sanitize-payload #3556ff3510590c935379c2dda7554753f688a012855630f0b9979db3c58a0b3e ~* &* +@all" > CONFIG SET requirepass S3cretPw "OK"
requirepass 只是设置 default 用户密码的旧接口。要小心两点:一是 CONFIG GET requirepass 返回的是明文,任何有 +config|get 权限的用户都能读到(第 123 篇的子命令粒度可以限制);二是 ACL SETUSER default nopass 之后 CONFIG GET requirepass 还显示旧值,同值的 CONFIG SET requirepass 没有效果。判断当前到底要不要密码,看 ACL LIST 里的 default 一行。
> ACL SETUSER alice on >ap ~* +@all "OK" > ACL SETUSER bob on >bp ~* +@all "OK" > AUTH alice ap "OK" > ACL WHOAMI "alice" > AUTH bob bp "OK" > ACL WHOAMI "bob" > AUTH bob nope (error) WRONGPASS invalid username-password pair or user is disabled. > ACL WHOAMI "bob"
> AUTH S3cretPw "OK" > CONFIG SET requirepass NewPw! "OK" > GET k (nil) > AUTH S3cretPw (error) WRONGPASS invalid username-password pair or user is disabled. > AUTH NewPw! "OK"
同一条连接可以重新 AUTH 成另一个用户。失败的 AUTH 不改变当前身份。改密码只影响之后的登录,已经登录的连接继续有效——所以怀疑密码泄露时,改密码之后还要把旧连接踢掉(CLIENT KILL 本文没有验证)。
> AUTH NewPw!
"OK"
> CONFIG SET slowlog-log-slower-than 0
"OK"
MONITOR 回复: OK
MONITOR 里与认证相关的行:
1790730769.580503 [0 127.0.0.1:61644] "AUTH" "(redacted)"
1790730769.580666 [0 127.0.0.1:61644] "AUTH" "(redacted)" "(redacted)"
1790730769.580796 [0 127.0.0.1:61644] "AUTH" "(redacted)" "(redacted)"
SLOWLOG 里与认证相关的条目(命令参数):
['CONFIG', 'SET', 'requirepass', '(redacted)']
['ACL', 'SETUSER', '(redacted)', '(redacted)']
['AUTH', '(redacted)', '(redacted)']
['AUTH', '(redacted)', '(redacted)']
['AUTH', '(redacted)']
['AUTH', '(redacted)']
CLIENT LIST 里有没有密码文本: FalseAUTH 的参数、CONFIG SET requirepass 与 ACL SETUSER 里的密码在 SLOWLOG 里都是 (redacted);MONITOR 里 AUTH 也被打码。这次 MONITOR 抓取里没有出现 CONFIG SET 和 ACL SETUSER 两行(原因没有验证)。但要注意:redis.conf 里的 requirepass 是明文,备份与配置文件的权限见第 132 篇。
一问一答:5000 次错误 AUTH 0.19 s → 26089 次/秒 流水线:20000 次错误 AUTH + 1 次正确 AUTH + PING 一次性发出,0.06 s 后收到 PONG; 收到的全部回复字节数 2700,其中 WRONGPASS 42 条、OK 1 条、PONG 1 条 服务端 INFO stats 里 acl_access_denied_auth 增加了 20000(这 20000 次错误尝试都被计数,但客户端只收到 42 条错误回复)
一问一答 26089 次/秒,流水线把 20000 次错误尝试在 0.06 s 里送完,最后的正确密码照样收到 OK。服务端把每次尝试都计入 acl_access_denied_auth,但流水线里的失败回复客户端只收到了 42 条——为什么没有验证,只是观察到的事实。这里没有观察到任何延迟、限速或锁定。所以 Redis 的密码不能当「有人试就会被挡住」的机制,它需要足够长的随机密码 + 不暴露在不可信网络。