소개
이 랩에서는 MySQL 데이터베이스의 보안을 강화하는 방법을 배우게 됩니다. root 사용자에 대한 비밀번호 설정, 최소 권한 원칙에 따른 전용 사용자 생성, 사용자 권한 관리, 익명 계정 제거 등 필수적인 보안 모범 사례를 다룰 것입니다. 이 랩이 끝나면 일반적인 취약점으로부터 MySQL 서버를 보호하는 방법에 대한 이해를 높일 수 있습니다.
이 랩에서는 MySQL 데이터베이스의 보안을 강화하는 방법을 배우게 됩니다. root 사용자에 대한 비밀번호 설정, 최소 권한 원칙에 따른 전용 사용자 생성, 사용자 권한 관리, 익명 계정 제거 등 필수적인 보안 모범 사례를 다룰 것입니다. 이 랩이 끝나면 일반적인 취약점으로부터 MySQL 서버를 보호하는 방법에 대한 이해를 높일 수 있습니다.
기본 MySQL 설치 시 종종 root 사용자가 로컬 머신에서 비밀번호 없이 연결할 수 있습니다. MySQL 보안을 위한 첫 번째 단계는 root 계정에 강력한 비밀번호를 설정하는 것입니다.
먼저 데스크톱에서 터미널을 엽니다.
root 사용자로 MySQL 서버에 연결합니다. 이 랩 환경에서는 sudo를 사용하여 비밀번호 없이 연결할 수 있습니다.
sudo mysql -u root
연결되면 MySQL 프롬프트 (mysql>) 가 표시됩니다.
이제 root 사용자에 대한 비밀번호를 설정합니다. ALTER USER 문은 사용자 계정을 수정하는 데 사용됩니다. YourStrongPassword!를 원하는 비밀번호로 바꾸십시오.
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourStrongPassword!';
이 명령은 localhost에서 연결할 때 root 사용자에 대한 비밀번호를 설정합니다. 명령이 성공적으로 실행되었음을 확인하는 다음 출력이 표시됩니다.
Query OK, 0 rows affected (0.01 sec)
다음으로 FLUSH PRIVILEGES 명령을 사용하여 권한 변경 사항을 즉시 적용합니다.
FLUSH PRIVILEGES;
출력은 다음과 같습니다.
Query OK, 0 rows affected (0.00 sec)
이제 root 사용자에 대한 비밀번호를 성공적으로 설정했습니다. sudo mysql -u root를 사용하여 계속 연결할 수 있지만, mysql -u root -p로 직접 연결을 시도하면 방금 설정한 비밀번호가 필요합니다. 이것은 데이터베이스 보안을 위한 중요한 첫 번째 단계입니다.
root 계정은 무제한 권한을 가지고 있어 애플리케이션에 사용하는 것은 보안 위험이 있습니다. 모범 사례는 각 애플리케이션에 대해 제한된 권한을 가진 전용 사용자를 생성하는 것입니다. 이 단계에서는 새 데이터베이스와 해당 데이터베이스에만 액세스할 수 있는 사용자를 생성합니다.
이제 애플리케이션을 위한 새 데이터베이스를 생성합니다. app_db라고 명명하겠습니다.
CREATE DATABASE app_db;
다음과 같은 확인 메시지가 표시됩니다.
Query OK, 1 row affected (0.01 sec)
다음으로 애플리케이션이 데이터베이스에 연결하는 데 사용할 새 사용자를 생성합니다. 이 사용자를 app_user라고 명명하고 비밀번호를 할당합니다.
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'UserPassword123';
출력은 다음과 같습니다.
Query OK, 0 rows affected (0.01 sec)
이제 app_user에 필요한 권한을 부여합니다. 이 예에서는 app_db 데이터베이스 내의 모든 테이블에 대해 SELECT 및 INSERT 권한을 부여합니다. 이는 최소 권한 원칙을 따르며 사용자에게 필요한 권한만 부여합니다.
GRANT SELECT, INSERT ON app_db.* TO 'app_user'@'localhost';
권한을 플러시하여 변경 사항을 적용합니다.
FLUSH PRIVILEGES;
다음 명령을 실행하여 방금 부여한 권한을 확인할 수 있습니다.
SHOW GRANTS FOR 'app_user'@'localhost';
출력에는 app_user에 대한 정확한 권한이 표시됩니다.
+------------------------------------------------------------------+
| Grants for app_user@localhost |
+------------------------------------------------------------------+
| GRANT USAGE ON *.* TO `app_user`@`localhost` |
| GRANT SELECT, INSERT ON `app_db`.* TO `app_user`@`localhost` |
+------------------------------------------------------------------+
2 rows in set (0.00 sec)
이제 적절한 권한을 가진 전용 데이터베이스와 사용자를 성공적으로 생성했습니다.
애플리케이션 요구 사항은 변경될 수 있으며, 이에 따라 사용자 권한을 조정해야 할 수도 있습니다. 이 단계에서는 app_user에서 기존 권한을 철회하여 권한을 수정하는 연습을 합니다.
이제 app_user는 데이터 읽기 (SELECT) 만 가능하고 새 데이터 추가 (INSERT) 는 할 수 없어야 한다고 가정합니다. INSERT 권한을 철회해야 합니다.
REVOKE 문을 사용하여 app_db 데이터베이스에서 app_user의 INSERT 권한을 제거합니다.
REVOKE INSERT ON app_db.* FROM 'app_user'@'localhost';
다음과 같은 확인 메시지가 표시됩니다.
Query OK, 0 rows affected (0.00 sec)
권한을 플러시하여 변경 사항을 적용합니다.
FLUSH PRIVILEGES;
이제 사용자의 권한을 다시 확인하여 권한이 철회되었는지 확인합니다.
SHOW GRANTS FOR 'app_user'@'localhost';
출력에는 이제 app_user가 app_db에 대해 SELECT 권한만 가지고 있음을 보여야 합니다. INSERT 권한은 사라졌습니다.
+--------------------------------------------------------------+
| Grants for app_user@localhost |
+--------------------------------------------------------------+
| GRANT USAGE ON *.* TO `app_user`@`localhost` |
| GRANT SELECT ON `app_db`.* TO `app_user`@`localhost` |
+--------------------------------------------------------------+
2 rows in set (0.00 sec)
이는 변경되는 보안 요구 사항에 적응하기 위해 사용자 권한을 효과적으로 관리하는 방법을 보여줍니다.
기본적으로 일부 MySQL 설치는 사용자 이름이 비어 있는 익명 사용자 계정을 생성합니다. 이러한 계정은 무단 액세스를 허용할 수 있으므로 보안 위험을 초래합니다. 익명 사용자가 있는지 확인하고 존재하는 경우 제거하는 것은 중요한 보안 관행입니다.
빈 사용자 이름 항목에 대해 mysql.user 테이블을 쿼리하여 익명 사용자를 식별할 수 있습니다.
SELECT User, Host FROM mysql.user WHERE User = '';
익명 사용자가 존재하는 경우 이 쿼리는 해당 사용자를 나열합니다. Ubuntu 에 새로 설치한 경우 하나가 포함될 수 있지만, 최신 버전의 MySQL/MariaDB는 기본적으로 익명 사용자가 없는 경우가 많습니다.
다음과 같은 결과가 표시되는 경우:
+------+-----------+
| User | Host |
+------+-----------+
| | localhost |
+------+-----------+
1 row in set (0.00 sec)
그러면 사용자 이름 (빈 문자열 '') 과 호스트를 모두 지정하는 DROP USER 문을 사용하여 익명 사용자를 제거해야 합니다.
DROP USER ''@'localhost';
다음과 같은 확인 메시지가 표시됩니다.
Query OK, 0 rows affected (0.01 sec)
하지만 쿼리가 다음과 같이 빈 세트를 반환하는 경우:
Empty set (0.00 sec)
이는 데이터베이스에 익명 사용자가 없음을 의미하며, 이는 이미 안전한 상태입니다. 이 경우 존재하지 않는 익명 사용자를 삭제하려고 하면 오류가 발생합니다.
ERROR 1396 (HY000): Operation DROP USER failed for ''@'localhost'
익명 사용자가 존재하지 않는 경우 이 오류는 예상된 것이며 안전하게 진행할 수 있습니다.
익명 사용자를 확인하고 필요한 경우 제거한 후에는 권한을 플러시하여 변경 사항이 적용되었는지 확인합니다.
FLUSH PRIVILEGES;
SELECT 쿼리를 다시 실행하여 익명 사용자가 남아 있지 않은지 확인합니다.
SELECT User, Host FROM mysql.user WHERE User = '';
이 쿼리는 빈 세트를 반환하여 익명 사용자가 없음을 확인해야 합니다.
Empty set (0.00 sec)
서버의 잠재적인 보안 취약점을 성공적으로 확인하고 해결했습니다. 이제 MySQL 셸을 종료할 수 있습니다.
exit;
이 실습에서는 필수적인 여러 MySQL 보안 모범 사례를 학습하고 적용했습니다. root 계정에 암호를 성공적으로 설정하고, 최소 권한 원칙에 따라 제한된 권한을 가진 전용 애플리케이션 사용자를 생성했으며, 권한을 철회하여 사용자 액세스를 관리하고, 잠재적인 익명 사용자 계정을 확인 및 해결했습니다.
이러한 기본적인 보안 조치를 구현함으로써 MySQL 데이터베이스의 보안 상태를 크게 개선하고 무단 액세스 및 잠재적 위협으로부터 보호할 수 있습니다.