보안은 기능이 아니라 설계의 핵심적인 부분으로 국제화 또는 접근성과 다를 바 없습니다. 우수한 보안 설계는 가능한 모든 단계에서 시스템 침해를 어렵게 만드는 것을 목표로 하며, 데이터베이스 환경에서는 이를 데이터베이스 '강화'라고 합니다.
이러한 단계에는 소프트웨어를 최신 상태로 업데이트하고, 시스템에 액세스할 수 있는 위치를 제한하고, 비밀번호를 강화하고, 액세스를 정기적으로 감사하는 단계 등이 있습니다. 이 도움말은 광범위하게 적용되지만 이러한 기법을 사용하여 MySQL용 Cloud SQL 데이터베이스 인스턴스를 최대한 침해하기 어렵게 만드는 방법을 살펴보겠습니다.
달리 좋게 표현할 방법이 없습니다. 몇 분 안에 인터넷 전체를 쉽게 스캔하고 몇 초 안에 비밀번호를 크래킹할 수 있는 공격자들이 있기 때문입니다. 공개 IP 네트워크를 통해 데이터베이스에 액세스할 수 있어야 하는 경우도 있지만 이로 인해 데이터베이스가 훨씬 더 취약해집니다. 공개 IP의 위험을 완화하는 한 가지 방법은 데이터베이스 액세스를 한정된 IP 주소 집합으로 제한하는 것입니다.
종합적으로 볼 때 Virtual Private Cloud(VPC) 내의 액세스만 허용하고 배스천 호스트 내의 연산자 연결만 허용하는 것이 더 효과적입니다. Google Cloud에서는 이 솔루션을 비공개 IP라고 합니다. VPC 내부에서만 MySQL 인스턴스에 액세스할 수 있는 경우 공격자는 먼저 VPC에 침해해야 인스턴스 침해를 시도할 수 있습니다.
모든 MySQL 부 버전에는 출시 노트가 있으며 보안 업데이트와 관련된 섹션이 거의 항상 포함되어 있습니다. 인스턴스가 오래된 여러 버전인 경우 데이터베이스에 없는 여러 버전의 보안 수정이 있습니다.
MySQL은 시간 경과에 따라 보안 문제를 해결하는 것 외에도 완전히 새로운 몇 가지 보안 기능을 주기적으로 도입합니다. 예를 들어 MySQL 8.0에는 역할, 실패한 로그인 추적, 임의의 비밀번호 생성과 같이 MySQL 스키마 및 사용자를 강화하는 다양한 방법이 도입되었습니다.
커피 전문점에서 작업하고 있는 경우 몇 가지 쿼리를 실행하기 위해 매장의 무료 Wi-Fi 네트워크를 통해 MySQL에 연결한다고 가정해 보겠습니다. TLS(전송 계층 보안)를 사용하지 않았다면 인터넷의 기본 프로토콜 중 하나인 TCP(전송 제어 프로토콜)를 통해 사용자 이름과 비밀번호를 외치는 것이나 다름 없습니다. MySQL 인스턴스에 TLS를 적용하면 네트워크에 대한 다른 고객의 스누핑에 신경 쓸 필요 없이 라떼를 마시며 작업할 수 있습니다.
SQL 삽입
공격에 가장 취약한 것은 데이터베이스가 아니라 애플리케이션인 경우가 많습니다. 애플리케이션에서 유효한 SQL 문이라고 간주하는 악의적인 입력을 공격자가 삽입하는 SQL 삽입 공격에 많은 애플리케이션이 노출되었습니다. 이러한 공격에 보다 효과적으로 대응하는 방법은 SQL 문을 사용하여 사용자 입력을 연결하는 대신 SQL 문을 생성할 때 준비된 문을 사용하는 것입니다.
저장소의 보안 비밀
개발자가 실수로 사용자 이름과 비밀번호를 소스 코드 저장소에 푸시하여 수많은 데이터베이스가 침해되었습니다. 대신 Google Cloud의 Secret Manager와 같은 도구를 사용하면 데이터베이스 비밀번호를 비롯한 모든 종류의 보안 비밀을 관리할 수 있습니다.
비밀번호 로깅
마지막으로 로깅 프레임워크의 필터링 도구를 사용하여 애플리케이션 로그에서 데이터베이스 비밀번호를 필터링합니다. Log4j Filters와 Rails ParameterFilter를 예로 들 수 있지만 대부분의 로깅 프레임워크에는 이에 상응하는 도구가 있어야 합니다. 그러지 않으면 데이터베이스를 보호하기 위해 애플리케이션 로그가 안전한지 확인해야 합니다.
데이터베이스의 모든 비밀번호가 충분히 복잡한지 확인하기 위해 비밀번호 유효성 검사를 사용하는 것이 좋습니다. 애플리케이션 비밀번호의 경우 길고 복잡하게 만들고 자주 변경합니다. Secret Manager를 사용하면 복잡하고 자주 변경되는 비밀번호를 기억할 필요가 없으므로 특히 유용합니다.
애플리케이션이 아닌 사람이 데이터베이스 사용자를 사용하는 경우 NIST의 표준을 따르고 무엇보다 길이를 우선시합니다. 비밀번호 만료일과 지나치게 복잡한 비밀번호 요구사항으로 인해 사람들이 자신의 기억을 일반 텍스트 파일 및 스티커 메모에 위임하여 이러한 규칙의 목적이 훼손되는 경우가 많습니다.
이를 참고하여 애플리케이션이 아닌 사용자에 대해서는 IAM 인증을 활용하는 것이 좋습니다. IAM 인증은 연결 설정을 Google Cloud의 IAM 서비스에 위임합니다. 즉, IAM 사용자와 데이터베이스 사용자가 아니라 IAM 사용자에게만 위험이 완화됩니다.
마지막으로 MySQL은 데이터베이스 비밀번호에 솔트가 아닌 해시를 기본값으로 사용합니다. 즉, 동일한 비밀번호를 사용하는 사용자는 동일한 인증 문자열을 갖게 되므로 레인보우 테이블 공격을 통한 취약한 비밀번호 크래킹을 간과하게 됩니다. 다음 두 MySQL 사용자의 authentication_string이 어떻게 동일한지 확인하세요.
default_authentication_plugin 플래그를 caching_sha2_password로 설정하는 것이 좋습니다. 이렇게 하면 동일한 비밀번호를 사용하는 두 사용자의 해시가 달라집니다. 다음 예시에서 두 사용자의 authentication_string 값이 어떻게 다른지 확인하세요.
액세스를 제한하는 것은 외부로부터의 액세스를 보호하는 것만이 아니라 내부에서의 액세스도 정기적으로 감사하는 것입니다.
애플리케이션 감사: 결제, 제품, 고객 테이블만 읽는 경우 실제로 다른 모든 항목에 액세스해야 하나요? 데이터베이스에 대한 루트 액세스를 허용하면 공격자가 데이터베이스에 엄청난 손상을 입힐 수 있습니다. 대신 인스턴스의 모든 요구사항을 고려하고 필요한 권한을 항목별로 기재한 후 각각에 대한 데이터베이스 사용자를 만듭니다. 공격자가 이러한 데이터베이스 사용자 중 한 명의 데이터베이스를 침해하는 경우 손상 범위가 제한됩니다.
사용자 감사: 인스턴스에 대한 관리자 권한이 실제로 필요한 데이터베이스 사용자 수는 몇 명인가요? 이 가운데 아직 조직에 남아 있거나 비활성 프로젝트에 연결되어 있거나 비활성 상태인 사용자는 몇 명인가요? 액세스 토큰이 유출될 수 있으며 내부자 위협은 대부분의 시스템에서 상시 문제입니다. 가능한 한 사용자 수를 적게 유지하면 인스턴스가 이러한 등급의 문제에 대응하는 데 도움이 됩니다.
'관리자' 감사: '루트' 또는 '관리자'와 같은 사용자를 삭제하거나 이름을 바꿔 보세요. 이들은 공격자의 표적이 되기 쉽기 때문에 존재하지 않는다면 시스템을 침해하기가 더 어려워집니다. 이를 모호성을 통한 보안이라고 하며, 첫 번째 방어선은 아니지만 MySQL 데이터베이스에 얇은 보안 레이어를 추가할 수 있습니다.
정기적인 데이터 백업과 검증 가능한 데이터 복구 계획은 정상적인 데이터베이스 관리에 매우 중요합니다. 하지만 정기적인 백업을 수행하더라도 마지막 백업 이후에 작성된 데이터는 모두 손실될 수 있습니다. MySQL 생태계의 이점 중 하나는 PITR(point-in-time recovery)입니다. 이를 사용하면 어느 시점이든 데이터를 복구할 수 있습니다. PITR을 가능하게 하려면 MySQL용 Cloud SQL 인스턴스에 바이너리 로그를 사용 설정합니다.
위의 작업을 모두 완료했다면 잘 대비되고 잘 보호된 것입니다. 그렇더라도 데이터베이스 감사와 같은 지속적인 경계가 없다면 보안 설계를 완벽하게 수행할 수 없습니다. MySQL용 Cloud SQL 감사 플러그인을 사용하면 침해가 발생할 경우 비정상적인 동작을 추적할 수 있습니다.
위의 사항을 적용하면 공격자가 데이터베이스를 침해하는 방법을 더욱 어렵게 만들 수 있습니다. 공격자는 애플리케이션을 침해해야 하고 애플리케이션의 데이터베이스 사용자에게 공격에 대한 충분한 권한이 있기를 기대합니다. 그렇지 않으면 VPC를 침해하고 기존 사용자 이름을 찾고 비밀번호를 크래킹해야 하고 사용자에게 공격을 실행할 충분한 권한이 있기를 바랍니다. 그동안 MySQL 데이터베이스 로그 또는 감사 로그를 확인하여 데이터베이스의 정상적인 동작을 모니터링하고 그에 따라 대응할 수 있습니다.
이것이 바로 보안 내재화 설계가 의미하는 바입니다. 공격자는 계속해서 머신을 악용할 방법을 탐색할 것입니다. 데이터베이스를 보호하기 위해 최대한 많은 보호 레이어를 갖춘 시스템을 설계하는 것이 중요한 이유가 바로 여기에 있습니다.