비밀번호를 비워두고 접속 버튼을 눌렀다.
그런데 DB가 열렸다.
이 장면을 본 사람의 첫 반응은 거의 같다.
“잠깐, 이거 인증이 뚫린 거 아니야?”
충분히 합리적인 의심이다. 우리는 로그인 화면에서 ID와 비밀번호를 입력하고, 접속에 성공하면 당연히 그 값이 검증됐다고 생각한다.
하지만 DB 앞에 접근통제 Proxy가 들어오면 이야기가 달라진다. 화면에는 ID와 비밀번호 칸이 하나씩 있어도, 실제 인증은 여러 장소에서 서로 다른 정보로 일어날 수 있다.
오늘은 “비밀번호가 틀렸는데 왜 접속됐지?”라는 당황스러운 장면을 통해 인증의 위치, Proxy Credential, 실제 DB 계정, Audit Log의 관계를 쉽게 풀어보려 한다.
접속 성공은 입력한 비밀번호의 합격 도장이 아니다
먼저 가장 중요한 문장부터 보자.
DB 접속에 성공했다는 사실만으로 Client에 입력한 ID와 비밀번호가 실제 DB에서 검증됐다고 결론 내릴 수는 없다.
접근통제 Proxy가 있는 환경에서는 접속 과정이 대략 이렇게 나뉜다.
1. 접근통제 시스템에 로그인한 사용자인가?
2. 이 DB에 들어갈 권한이 있는가?
3. 어떤 DB 계정으로 접속할 것인가?
4. Target DB가 그 계정을 허용하는가?
DB Client에 보이는 ID/PW 칸은 이 네 질문 중 일부만 담당할 수 있다. 어떤 방식에서는 실제 DB 계정이고, 다른 방식에서는 Client와 Proxy 사이의 연결 절차를 완성하는 값일 뿐이다.
겉으로는 같은 입력창인데 맡은 일이 다르다.
이게 혼란의 시작이다.
회사 출입을 떠올리면 쉬워진다
회사 안에 중요한 문서가 보관된 금고가 있다고 해보자.
건물에 들어가려면 사원증이 필요하다. 특정 층에 올라가려면 별도 권한이 필요하다. 마지막으로 금고를 열 때는 금고 열쇠가 필요하다.
사원증
→ 건물에 들어갈 사람 확인
층별 출입권한
→ 이 구역에 들어가도 되는지 확인
금고 열쇠
→ 실제 금고 열기
DB 접근통제도 비슷하다.
사용자 로그인
→ 실제 사람 확인
DB 접근권한
→ 해당 DB에 접속해도 되는지 확인
등록된 DB 계정
→ 실제 Target DB 인증
여기서 DB Client의 ID/PW가 항상 금고 열쇠인 것은 아니다. 어떤 환경에서는 안내 데스크에서 받은 임시 출입번호처럼 Client와 Proxy 사이에서만 쓰인다. 또 어떤 환경에서는 입력칸은 존재하지만 실제 금고는 서버에 안전하게 보관된 별도 열쇠로 열린다.
그러니 입력한 비밀번호가 틀렸는데 문이 열렸다고 해서 곧바로 “금고가 무인증으로 열렸다”고 결론 내리면 안 된다.
먼저 어느 문이 어떤 열쇠를 확인했는지 봐야 한다.
인증정보는 사실 한 덩어리가 아니다
Proxy 환경을 이해하려면 최소 네 가지 값을 분리해야 한다.
| 구분 | 의미 |
|---|---|
| 로그인 사용자 | 접근통제 시스템에 로그인한 실제 사람 |
| Client 입력값 | DB 프로그램의 ID/PW 칸에 입력한 값 |
| Proxy Credential | Client와 Proxy 사이의 연결 절차에 쓰는 정보 |
| Target DB Credential | 실제 DB가 검증하는 DB 계정 |
여기에 Audit Log가 하나 더 붙는다.
좋은 Audit Log는 “Client 입력칸에 무슨 문자열을 썼는가”보다 다음 두 신원을 연결해야 한다.
누가 접속 권한을 사용했는가?
실제 DB에는 어떤 계정으로 접속했는가?
예를 들어 한 운영자가 개인 계정으로 접근통제 시스템에 로그인하고, 서버에 보관된 공용 DB 계정으로 작업했다고 해보자.
Audit Log에는 이렇게 두 축이 남아야 한다.
- 사람의 신원: 권한을 사용한 운영자
- DB의 신원: Target DB 인증에 사용된 공용 계정
Client 입력칸에 적은 임의의 문자열이 사람의 신원이나 실제 DB 사용자를 덮어쓰면 안 된다.
이 구분이 있어야 공용 계정을 쓰면서도 “누가 무엇을 했는지” 추적할 수 있다.
그런데 왜 DB마다 다르게 동작할까?
여기서 자연스럽게 다음 질문이 나온다.
“그럼 모든 DB에서 똑같이 처리하면 안 되나?”
사용자 경험만 생각하면 그게 가장 편하다. 하지만 DB protocol은 놀랄 만큼 제각각이다.
1. 새 답안지를 만들 수 있는 방식
어떤 protocol에서는 Proxy가 실제 DB 비밀번호와 서버가 보낸 임의값을 이용해 Target DB용 인증 응답을 새로 만들 수 있다.
Client가 만든 응답
→ 사용하지 않음
등록된 DB 비밀번호 + Server challenge
→ Target DB용 응답 새로 생성
이 구조에서는 Client가 입력한 비밀번호를 Target DB 인증에 그대로 사용할 필요가 없다.
2. Client가 만든 암호문을 먼저 풀어야 하는 방식
어떤 protocol은 Client 비밀번호로 session key와 인증정보를 암호화한다.
Proxy가 실제 DB 계정으로 바꾸려면 먼저 Client 쪽 암호문을 풀고, 그다음 Target DB 비밀번호로 다시 암호화해야 한다.
Client password
→ Client 쪽 암호문 복호화
Target DB password
→ Server 쪽 인증정보 재암호화
이 경우에는 정확한 Proxy Credential이 반드시 필요하다. 틀린 비밀번호로는 첫 번째 암호문부터 풀 수 없다.
3. 비밀번호 대신 증명서를 주고받는 방식
SCRAM 같은 인증 방식은 비밀번호 원문을 직접 보내지 않는다. 대신 “나는 이 비밀번호를 알고 있다”는 proof를 주고받는다.
도장을 찍은 봉투와 비슷하다. 봉투 안의 비밀번호를 꺼내 볼 수는 없지만, 도장이 올바른지는 확인할 수 있다.
Proxy는 Client proof를 검증하고, 실제 DB 비밀번호로 Target DB용 proof를 새로 만들어야 한다. Client에게 돌려줄 server proof도 올바르게 계산해야 한다.
그래서 이런 방식에서도 정확한 Proxy Credential이 필요하다.
결국 차이는 제품이 변덕을 부려서 생긴 것이 아니라, 각 DB protocol이 비밀번호를 다루는 방식에서 시작된다.
MySQL도 첫 질문에서 끝나지 않을 수 있다
MySQL이라고 해서 인증 흐름이 언제나 한 번의 질문과 답변으로 끝나는 것은 아니다. Target MySQL 계정에는 어떤 password 인증 방식을 쓸지 정하는 인증 plugin이 붙어 있고, 이 plugin에 따라 Proxy가 처리해야 하는 대화 길이가 달라진다.
| 인증 plugin | 쉽게 말하면 | Proxy가 주의할 점 |
|---|---|---|
mysql_native_password |
첫 번째 출입 질문에 답하면 끝나는 경우가 많은 방식 | 등록된 DB password와 서버 challenge로 최초 응답을 새로 만들면 인증이 끝날 수 있다 |
caching_sha2_password |
첫 답변 뒤에 추가 확인이 이어질 수 있는 방식 | fast authentication 또는 full authentication 과정에서 추가 응답이 필요할 수 있다. 환경에 따라 TLS나 RSA public key도 관여한다 |
비유하면 mysql_native_password는 안내 데스크가 “출입증 있나요?”라고 한 번 묻고 끝나는 경우에 가깝다. caching_sha2_password는 출입증을 본 뒤에도 “그럼 이 추가 확인에도 답해 주세요”라고 물을 수 있다.
이때 Proxy의 일은 첫 번째 답안만 바꿔 끼우는 것으로 끝나지 않는다. 등록된 DB Credential으로 대신 인증하는 구조라면, 추가 질문이 왔을 때도 Target DB가 기대하는 형식으로 답을 계속 만들어야 한다.
최초 Login Request 치환 성공
≠ 추가 인증 교환까지 성공
그래서 “MySQL 접속이 된다”는 한 문장만으로 빈 password나 임의 password가 모든 MySQL 환경에서 같은 방식으로 동작한다고 결론 내리면 안 된다. 인증 plugin, TLS 여부, Client 버전까지 함께 봐야 한다.
사용자에게는 이 복잡함을 떠넘기지 않는 편이 좋다. 인증 plugin을 바꾸는 우회책보다 Connection Information에 표시된 사용자명과 password를 입력하도록 안내하는 편이 안전하고 일관된다.
기술은 달라도 사용법은 같아야 한다
기술적 이유가 있다고 해서 사용자가 모든 protocol 차이를 외워야 하는 것은 아니다.
“이 DB는 challenge response고, 저 DB는 session key 암호화니까…”를 사용자가 매번 판단하게 만드는 건 좋은 UX가 아니다.
운영 원칙은 더 단순해야 한다.
등록 계정 방식
→ Connection Information에 제공된 Proxy Credential 사용
기존 DB 계정 방식
→ 실제 Target DB 계정 사용
어떤 DB에서는 Proxy Credential이 handshake에 반드시 필요하다. 어떤 DB에서는 서버에 등록된 Target Credential로 완전히 바뀔 수 있다.
그래도 사용자는 Connection Information에 나온 값을 그대로 입력하면 된다. 내부 구현의 차이를 공통 사용법으로 감싸는 것이다.
이런 일관성은 문서만으로 해결되지 않는다. UI도 역할을 말해줘야 한다.
ID / Password
보다는 다음 표현이 더 낫다.
Proxy Credential
- Client와 Proxy 사이의 연결에 사용
- 실제 DB 계정과는 별도
실제 DB 계정을 입력하는 방식이라면 아예 다르게 표시해야 한다.
Target DB Credential
- 실제 DB에서 직접 검증
같은 칸에 서로 다른 의미를 담아놓고 사용자가 알아서 이해하길 기대하면, 정상 기능도 보안 사고처럼 보인다.
오류 메시지도 어느 문에서 실패했는지 말해야 한다
인증 경계가 여러 개라면 실패 메시지도 구간을 알려줘야 한다.
좋지 않은 메시지:
Authentication failed
조금 더 나은 메시지:
Proxy Credential 확인 실패
Target DB 인증 실패
사용자 DB 접근권한 없음
로그인 세션 만료
모두 “접속 실패”지만 원인은 완전히 다르다.
- 로그인 세션이 끝난 것인지
- DB 접근권한이 없는 것인지
- Proxy handshake가 실패한 것인지
- 실제 DB가 등록 계정을 거절한 것인지
이 경계를 알려주면 사용자는 비밀번호를 열 번 다시 입력하지 않아도 된다. 운영팀도 엉뚱한 DB 계정을 바꾸지 않아도 된다.
보안 판단은 한 줄 로그가 아니라 경계 전체를 봐야 한다
“빈 비밀번호로 접속 성공”이라는 한 줄은 강렬하다.
하지만 보안 판단에는 다음 질문이 함께 필요하다.
로그인하지 않은 사용자도 접속할 수 있었나?
DB 접근권한이 없는 사용자도 접속할 수 있었나?
Target DB는 실제로 어떤 계정을 검증했나?
Audit Log에는 어떤 사용자와 DB 계정이 남았나?
로그아웃하거나 권한을 회수한 뒤 신규 접속은 차단됐나?
이 중 첫 두 질문까지 통과해버렸다면 심각한 문제일 수 있다.
반대로 사용자 로그인과 DB 권한이 정상적으로 확인됐고, Target DB도 등록된 실제 계정을 검증했다면 이야기는 달라진다. Client 입력값의 역할이 우리가 예상했던 것과 달랐던 것이다.
즉, 보안은 “비밀번호 칸이 있었는가”보다 “어느 경계에서 무엇을 검증했는가”로 판단해야 한다.
이번 질문이 남긴 다섯 가지 교훈
1. 접속 성공과 입력 Credential 검증은 같은 말이 아니다
Proxy가 중간에서 인증정보를 바꿀 수 있다면 둘은 반드시 분리해서 확인해야 한다.
2. 사용자 신원과 DB 계정은 다를 수 있다
접근통제의 중요한 역할은 실제 사람과 공용 DB 계정을 연결하는 것이다.
3. Client password가 필요해도 Target DB password라는 뜻은 아니다
Client와 Proxy 사이의 handshake에만 쓰는 Proxy Credential일 수 있다.
4. DB별 구현 차이는 피하기 어려워도 UX 차이는 줄일 수 있다
사용자에게는 공통 사용법을 제공하고, 내부에서는 protocol별 adapter가 차이를 처리해야 한다.
5. Audit Log는 두 신원을 함께 보여줘야 한다
누가 권한을 사용했는지와 실제 DB가 어떤 계정을 봤는지를 구분해야 한다.
비밀번호보다 먼저 물어야 할 질문
비밀번호가 틀렸는데 접속이 됐다면 놀라는 게 맞다.
하지만 그다음 질문은 “비밀번호 검사가 없었나?”에서 멈추면 안 된다.
어떤 비밀번호가,
어느 구간에서,
무엇을 위해 사용됐는가?
접근통제 Proxy가 있는 환경에서는 문이 하나가 아니다. 사용자 로그인, 권한 확인, Proxy handshake, Target DB 인증이 차례로 이어진다.
보안은 모든 문에 똑같은 열쇠를 쓰게 만드는 일이 아니다.
각 문에 맞는 열쇠를 쓰되, 사용자가 어느 열쇠를 들어야 하는지 헷갈리지 않게 만드는 일이다.