背景

因为工作的一些场景,想到一个问题,在不重启redis的情况下,使用config set修改密码,修改成功后,已经建立的长连接在执行需要认证的命令时,会不会报错

实验

带着问题,我们进行了实验,正常进入,执行命令:

root@3b9d47d51ffc:/data# redis-cli
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> get key
"value"

新开一个窗口修改密码

root@3b9d47d51ffc:/# redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> config set requirepass 654321
OK
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) "654321"

可以看到密码已经修改成功了,我们继续在刚在的窗口执行命令

root@3b9d47d51ffc:/data# redis-cli
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> get key
"value"
127.0.0.1:6379> get key
"value"
127.0.0.1:6379> get key
"value"
127.0.0.1:6379> get key
"value"
127.0.0.1:6379> get key
"value"
127.0.0.1:6379>

可以看到仍然可以正常执行命令。

源码探究

阅读redis源码,我们发现在执行成功auth命令之后,server把这个客户端对象中的一个是否认证的标识设置为1

void authCommand(client *c) {
    if (!server.requirepass) {
        addReplyError(c,"Client sent AUTH, but no password is set");
    } else if (!time_independent_strcmp(c->argv[1]->ptr, server.requirepass)) {
      c->authenticated = 1;
      addReply(c,shared.ok);
    } else {
      c->authenticated = 0;
      addReplyError(c,"invalid password");
    }
}

然后再processCommand函数里面,只会对这个表示进行验证,不会重新校验密码

  /* Check if the user is authenticated */
    if (server.requirepass && !c->authenticated && c->cmd->proc != authCommand)
    {
        flagTransaction(c);
        addReply(c,shared.noautherr);
        return C_OK;
    }

另外,在configSetCommand函数里面(config set requirepass实际执行的内容),修改密码只是修改了全局变量的值,并没有重置会话内变量的操作。

config_set_special_field("requirepass") {
        if (sdslen(o->ptr) > CONFIG_AUTHPASS_MAX_LEN) goto badfmt;
        zfree(server.requirepass);
        server.requirepass = ((char*)o->ptr)[0] ? zstrdup(o->ptr) : NULL;
    } 

润雨冰雪
36 声望4 粉丝