[Spring/MySQL] Public key retrieval is not allowed 의미 파헤치기

 

개요

대부분의 백엔드 개발자들이 처음 데이터를 영속화할 DBMS를 선택할 때 MySQL을 선택한다.

그리고 JDBC를 이용해 MySQL에 연결하고자 하는 Spring 백엔드 개발자라면, 애플리케이션 서버와 MySQL을 연결하다가 아래와 같은 오류를 마주하게 될 수 있다.

“Public key retrieval is not allowed”

어? 이게 뭐지? 구글에 검색해보니, 아래와 같은 옵션을 붙이면 문제를 해결할 수 있다고 한다.

useSSL=false&allowPublicKeyRetrieval=true

DB 연결 세팅에 위 옵션을 더하니 정말로 연결이 잘 된다.

이제 문제를 해결했으니 내 애플리케이션을 구동하면 되겠다. 그런데…

저 오류는 정말 문제일까? 위 옵션을 더하는 것은 문제의 해결이라고 볼 수 있을까?

이 글에서는 이 에러가 왜 발생하는지, 위와 같은 방식으로 해결하는 것이 어떤 의미를 갖는지를 다뤄보고자 한다.

 

 

MySQL의 SSL 강제 활성화

일단 이 에러를 한 번도 만난 적 없지만 이 글을 읽는 사람들을 위해 간단히 설명하자면, 해당 에러는 MySQL 8버전에서 SSL을 비활성화하고(useSSL=false) 데이터베이스에 연결을 시도할 때 발생한다.

그렇다면 이전 버전에서는 발생하지 않던 이 에러가 갑자기 왜 8버전부터 발생하기 시작했을까?

default authentication-plugin의 변경

MySQL 8.0의 가장 큰 변화 중 하나는, 기본 인증 플러그인이 mysql_native_password에서 caching_sha2_password로 변경되었다는 것이다.

우선 mysql_native_password 인증 방식의 경우 연결을 시도하는 클라이언트가 아이디/비밀번호를 해시 값으로 변환하여 서버에 전달한다. 이 기존 방식의 경우, SSL 옵션이 없어도 연결을 확립할 수 있었다.

하지만 해당 방식의 경우 *레인보우 테이블을 통해 복호화가 가능하며, 이 경우 DB 계정 정보가 유출될 위험이 있다. (레인보우 테이블: 해시 함수를 사용하여 변환 가능한 모든 해시 값을 저장시켜 놓은 표)

따라서 8버전부터 기본 인증 플러그인이 caching_sha2_password 으로 변경되었으며, 이 플러그인의 경우 클라이언트의 계정 정보를 MySQL 서버의 Public key로 암호화한 후 전달하여 MySQL 서버가 자신의 Private key로 복호화하여 확인할 수 있는 방식을 사용한다.

이 방식은 MySQL의 Private key만 안전하게 관리하면 공격자에게 계정 정보가 유출될 위험이 없다는 점에서 기존 인증 플러그인보다 안전하다고 볼 수 있다.

caching_sha2_password 은 왜 기본적으로 SSL 연결을 활성화하는가?

하지만 SSL 연결이 없으면 완전히 안전하다고 볼 수는 없는데, 그 이유는 caching_sha2_password 플러그인 또한 보호되지 않은 네트워크에서 통신한다면 중간자 공격(MITM)의 위험이 있기 때문이다.

DB 클라이언트가 Public key 조회 요청을 전송할 때, 이 요청을 가로채 공격자의 Public key를 제공한다면 공격자는 이를 통해 암호화된 계정 정보를 자신의 Private key로 복호화할 수 있게 된다.

따라서 해당 인증 방식을 사용하는 경우 클라이언트 - DB 서버 간에 SSL 연결을 확립한 후 공개키를 주고받는 것이 안전하다.

 

 

여기서 다시 한 번 살펴보는 각 옵션의 의미

  • useSSL: SSL 연결을 비활성화한다. 기본적으로 SSL 연결을 활성화한다.
  • allowPublicKeyRetrieval: SSL 연결 없이도 클라이언트가 DB서버의 공개키를 획득할 수 있게 한다.

이제 이 옵션들이 DB 연결을 위한 통신 과정에 어떤 영향을 미치는지는 대략적으로 이해가 갈 것이다.

즉, 안전한 인증을 위해 기본적으로 활성화된 SSL 연결 옵션을 비활성화한 뒤, SSL 연결 없이 MySQL 서버의 Public key를 획득한 뒤 이 키를 통해 계정을 암호화하여 인증을 수행하겠다는 것이다.

따라서, 사실 이 에러의 발생을 문제라고 볼 수는 없다. “우리가 보안적 측면에서 위험성이 있어 SSL 연결 없이 공개키를 조회하는 걸 막아뒀는데, 네가 그 행동을 별도의 설정이나 권한 없이 수행했다” 정도의 경고라고 볼 수 있겠다.

그러니 당장의 에러를 해결하기 위해 위 옵션들을 설정하고, 에러가 더이상 발생하지 않으니 문제가 해결되었다고 생각하고 넘기는 것은 사실 아주 위험한 행동이라고 할 수 있다. 특히 이러한 보안 관련 설정들은 어떤 보안 취약점을 유발하는지 충분한 검토를 하고 결정하는 것이 좋다.

 

 

그렇다면 SSL 연결을 해야겠군요…

운영 환경에서만큼은 확실히 그렇다. 하지만, 로컬 애플리케이션 서버에서 로컬 DB 서버에 연결하는 경우 보통 localhost를 사용해 내부 IP로 통신하기도 하고, 애당초 로컬 DB에 그렇게 중요한 데이터를 저장하는 경우도 드물다.

따라서, 로컬 통신에서는 SSL을 비활성화해도 괜찮지만, 운영 환경에서는 DB 보안을 위해 인증서를 세팅하고 SSL 연결을 활성화하도록 하자.

보통 MySQL 서버는 부팅 시점에 기본적으로 인증서를 생성한다. 따라서, useSSL=false 옵션을 제거하거나 true로 설정하고 allowPublicKeyRetrieval=true 옵션을 제거하는 것만으로도 기본적으로 생성되는 인증서 기반의 SSL 연결을 사용할 수 있긴 하다.

하지만 운영 환경에서는 SSL 연결을 위해 어떤 인증서를 사용하느냐도 중요하다. 공신력 있는 기관의 인증서를 사용하는 편이 보안적 측면에서 더 안전하다고 할 수 있다.

 

 

요약 ✏️

  • MySQL 8버전에서는 SSL 연결을 비활성화하여 커넥션을 시도할 시 Public key retrieval is not allowed 에러가 발생할 수 있음
  • 이는 기본 인증 플러그인 변경에 의해 대칭키 기반 사용자 인증이 도입되며 기본적으로 SSL 통신이 아니면 공개키 조회를 허용하지 않기 때문에 발생하는 것
  • 로컬 환경에서는 보통 내부망 통신을 하므로 공격 위험이 적어 SSL 옵션을 비활성화해도 큰 문제가 없음
  • 하지만 운영 환경에서는 중간자 공격 등을 예방하기 위해 SSL 통신을 할 것이 권장되며, 이 때 인증서 또한 신뢰 가능한 기관의 인증서를 사용해야 안전함