[입 개발] Redis 접속이 안되요!!! – Protected Mode

최근에 자주 다음 질문을 받는 케이스가 늘어서 정리합니다.(사실 저도 당한…)
최신 버전 3.2.x 을 설치하고 클라이언트를 접속하고 보면… 접속이 안됩니다.

일단 client 로 접속을 하게 되면 다음과 같은 에러를 볼 수 있습니다.
(항상이 아니라 흔히 볼 수 있습니다.)

“-DENIED Redis is running in protected mode because protected ”
“mode is enabled, no bind address was specified, no ”
“authentication password is requested to clients. In this mode ”
“connections are only accepted from the loopback interface. ”
“If you want to connect from external computers to Redis you ”
“may adopt one of the following solutions: ”
“1) Just disable protected mode sending the command ”
“‘CONFIG SET protected-mode no’ from the loopback interface ”
“by connecting to Redis from the same host the server is ”
“running, however MAKE SURE Redis is not publicly accessible ”
“from internet if you do so. Use CONFIG REWRITE to make this ”
“change permanent. ”
“2) Alternatively you can just disable the protected mode by ”
“editing the Redis configuration file, and setting the protected ”
“mode option to ‘no’, and then restarting the server. ”
“3) If you started the server manually just for testing, restart ”
“it with the ‘–protected-mode no’ option. ”
“4) Setup a bind address or an authentication password. ”
“NOTE: You only need to do one of the above things in order for ”
“the server to start accepting connections from the outside.\r\n”;

이유가 무엇인고 하면 3.2.x 부터 Redis 에 Protected mode 라는 것이 생겼습니다. 이 Protected Mode라는 것은 또 무엇인고 하니, 혹시 예전의 보안 사고를 기억하시나요? Redis 는 굉장히 보안에 취약합니다. 특히 public 으로 열어두면 거의 해킹의 온상이 되는… 방법은 그렇게 공개하지는 않겠습니다.

그래서 추가된 것이 이 protected mode 입니다. protected mode 가 설정되어 있는 상태에서 패스워드가 설정되지 않고, 특정 ip로 bind가 되어있지 않으면, connection 자체가 위의 에러를 내면서 실패하게 됩니다.

그런데 이런 문의가 급증하는 것은 이 protected mode 가 default yes 이고 보통 특정 ip로 bind 시키지 않고 requirepass 를 지정하지 않습니다. 보통은 내부망에서만 쓰라는 얘기가 되는거죠. 그래서 이걸 해결 하기 위해서는 다음 명령을 127.0.0.1 즉 local loopback 주소에서 접속한 다음 날려야 합니다.

config set protected-mode no

 

실제 코드를 보면 다음 부분에서 문제가 되는겁니다. src/networking.c 에 있습니다.

    if (server.protected_mode &&
        server.bindaddr_count == 0 &&
        server.requirepass == NULL &&
        !(flags & CLIENT_UNIX_SOCKET) &&
        ip != NULL)
    {
        if (strcmp(ip,"127.0.0.1") && strcmp(ip,"::1")) {
            char *err =
                "-DENIED Redis is running in protected mode because protected "
                "mode is enabled, no bind address was specified, no "
                "authentication password is requested to clients. In this mode "
                "connections are only accepted from the loopback interface. "
                "If you want to connect from external computers to Redis you "
                "may adopt one of the following solutions: "
                "1) Just disable protected mode sending the command "
                "'CONFIG SET protected-mode no' from the loopback interface "
                "by connecting to Redis from the same host the server is "
                "running, however MAKE SURE Redis is not publicly accessible "
                "from internet if you do so. Use CONFIG REWRITE to make this "
                "change permanent. "
                "2) Alternatively you can just disable the protected mode by "
                "editing the Redis configuration file, and setting the protected "
                "mode option to 'no', and then restarting the server. "
                "3) If you started the server manually just for testing, restart "
                "it with the '--protected-mode no' option. "
                "4) Setup a bind address or an authentication password. "
                "NOTE: You only need to do one of the above things in order for "
                "the server to start accepting connections from the outside.\r\n";
            if (write(c->fd,err,strlen(err)) == -1) {
                /* Nothing to do, Just to avoid the warning... */
            }
            server.stat_rejected_conn++;
            freeClient(c);
            return;
        }
    }

 

점점 보안이 중요해지네요. 제 acl 패치는 언제 받아들여질지 T.T