MySQLサーバーのセキュリティ設定を強化するためのベストプラクティス

最小権限のユーザー、ホスト制限、TLS、安全なmy.cnf設定、パッチ適用、基本的な監査でMySQLを強化します。

MySQLサーバーのセキュリティ設定を強化するためのベストプラクティス

MySQLの強化は、単純な質問から始まります。アプリケーションのパスワードが1つ漏洩した場合、攻撃者は何を得るでしょうか?答えが「どこからでもすべてのデータベース」である場合、サーバーにはより厳格なユーザー、ネットワークルール、および構成が必要です。

これらのプラクティスを使用して、日常の管理を困難にすることなく、侵害の爆発半径を減らします。

1. ユーザーとアクセス管理:最小権限の原則

効果的なユーザー管理は、MySQLのセキュリティの基盤です。ユーザーに必要な権限のみを付与することが最も重要です。

特定のアプリケーション用に特定のユーザーを作成する

アプリケーション接続にrootユーザーを使用しないでください。代わりに、詳細な権限を持つ専用ユーザーを作成します。

CREATE USER 'my_app_user'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON `your_database`.* TO 'my_app_user'@'localhost';

強力なパスワードを適用する

強力でユニークなパスワードは、最初の防御線です。利用可能な場合は、MySQLの組み込みパスワード検証プラグインを活用します。

  • 複雑さ:大文字、小文字、数字、記号を混在させます。
  • 長さ:少なくとも12〜16文字を目指します。
  • ユニークさ:パスワードを再利用しないでください。
  • ローテーション:定期的なパスワード変更のポリシーを実装します。

validate_passwordコンポーネント(MySQL 8.0+)またはプラグイン(MySQL 5.7+)を有効にできます。

INSTALL COMPONENT 'file://component_validate_password';
-- または古いバージョンの場合
INSTALL PLUGIN validate_password SONAME 'validate_password.so';

-- 強度ポリシーを設定します(例:8文字以上、大文字小文字混在、数字、特殊文字のMEDIUM)
SET GLOBAL validate_password.policy = MEDIUM;
SET GLOBAL validate_password.length = 12;

デフォルトおよび未使用のユーザーを削除する

MySQLには、管理アカウントや内部アカウントが含まれる場合があります。mysql.sessionmysql.sysなどの必要なシステムアカウントはそのままにし、匿名アカウントや使用しなくなった人間またはアプリケーションアカウントを削除します。

-- 匿名ユーザーを特定するには:
SELECT user, host FROM mysql.user WHERE user = '';
-- 匿名ユーザーを削除するには(見つかった場合):
DROP USER ''@'localhost';

-- テストデータベースを削除するには(存在する場合):
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%';
FLUSH PRIVILEGES;

ホストアクセスを制限する

ユーザーアカウントを特定のIPアドレスまたはホスト名からのみ接続できるように制限します。特に必要な場合や他の強力なセキュリティ制御と組み合わせる場合を除き、ホストのワイルドカードとして%を使用しないでください。

-- ユーザーはlocalhostからのみ接続可能
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'AnotherStrongPass!';

-- ユーザーは特定のIPアドレスからのみ接続可能
CREATE USER 'backup_user'@'192.168.1.100' IDENTIFIED BY 'BackupPass!';

GRANT OPTIONには注意する

WITH GRANT OPTION句を使用すると、ユーザーは自分の権限を他のユーザーに付与できます。これは、信頼できないユーザーに付与された場合、重大なセキュリティリスクになる可能性があります。この機能を本当に必要とする管理アカウントにのみ、控えめに使用してください。

-- 権限を付与できるユーザー(細心の注意を払って使用)
CREATE USER 'superadmin'@'localhost' IDENTIFIED BY 'SuperAdminPass!';
GRANT ALL PRIVILEGES ON *.* TO 'superadmin'@'localhost' WITH GRANT OPTION;

2. ネットワークセキュリティ:データベースの分離

ネットワークレベルの制御は、MySQLサーバーへの不正な外部アクセスを防ぐために重要です。

ファイアウォールを構成する

MySQLのデフォルトポート(3306)への接続を、信頼できるIPアドレスまたはネットワークからのみ許可します。このポートへの他のすべての受信接続をブロックします。

例(LinuxのUFW):

sudo ufw enable
sudo ufw allow from 192.168.1.0/24 to any port 3306
sudo ufw deny 3306
sudo ufw status

例(firewalldを使用したCentOS/RHEL):

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="3306" protocol="tcp" accept'
sudo firewall-cmd --permanent --remove-port=3306/tcp --zone=public # グローバルに開いていないことを確認
sudo firewall-cmd --reload

SSL/TLSで接続を保護する

SSL/TLSを使用してクライアントとMySQLサーバー間のすべてのトラフィックを暗号化し、盗聴や中間者攻撃(MitM)を防ぎます。これは、信頼できないネットワークを介した接続では特に重要です。

SSL/TLSを有効にするには、通常、SSL証明書とキーを生成し、my.cnfを構成する必要があります。

# my.cnf
[mysqld]
ssl_ca=/etc/mysql/certs/ca.pem
ssl_cert=/etc/mysql/certs/server-cert.pem
ssl_key=/etc/mysql/certs/server-key.pem

次に、クライアントをSSL/TLSを使用して接続するように構成する必要があります。多くの場合、ユーザーのGRANTステートメントでREQUIRE SSLを使用します。

CREATE USER 'ssl_user'@'%' IDENTIFIED BY 'SSLUserPass!';
GRANT SELECT ON `your_database`.* TO 'ssl_user'@'%' REQUIRE SSL;

特定のIPアドレスにバインドする

デフォルトでは、MySQLは利用可能なすべてのネットワークインターフェース(0.0.0.0)でリッスンする場合があります。接続を受け入れる必要があるインターフェース(例:ローカルアプリケーションの場合はlocalhost、内部接続の場合はプライベートネットワークIP)でのみリッスンするように制限します。

# my.cnf
[mysqld]
bind-address = 127.0.0.1  # ローカル接続のみ
# または
bind-address = 192.168.1.10  # 特定の内部IP

ヒント:アプリケーションとMySQLサーバーが同じマシンにある場合、bind-address = 127.0.0.1(localhost)が最も安全なオプションであり、外部からの接続を完全に防ぎます。

3. 構成ファイルの強化(my.cnf / my.ini

MySQL構成ファイル(Linuxではmy.cnf、Windowsではmy.ini)は、セキュリティを強化するための多くのパラメーターを提供します。

未使用の機能を無効にする

デプロイメントに不要な機能を無効にして、攻撃対象領域を最小限に抑えます。

  • local_infile = 0LOAD DATA LOCAL INFILEを無効にします。これにより、クライアントとサーバーの両方が許可している場合、クライアントホストからファイルを読み取られる可能性があります。
    [mysqld]
    local_infile = 0
    
  • skip-networking:データベースが同じサーバー上のアプリケーションからのみアクセスされる場合は、ネットワーキングを完全に無効にします。これにより、すべての接続がUnixソケットまたは名前付きパイプを使用するよう強制されます。
    [mysqld]
    skip-networking
    
  • symbolic-links = 0:データベーステーブルスペースへのシンボリックリンクの使用を防ぎます。これは、MySQLデータディレクトリ外のファイルにアクセスするために悪用される可能性があります。
    [mysqld]
    symbolic-links = 0
    
  • secure_file_privLOAD DATA INFILESELECT ... INTO OUTFILEなどのファイルインポートおよびエクスポート操作で使用されるディレクトリを制限します。
    [mysqld]
    secure_file_priv = /var/lib/mysql-files
    

secure_file_privを、MySQLサービスアカウントが所有する専用ディレクトリに設定します。/tmp、アプリケーションのアップロードディレクトリ、または信頼できないユーザーが書き込めるパスを指定しないでください。

オプションファイルに平文のシークレットを避ける

クライアントオプションファイルは、読み取り可能な人にデータベースパスワードを誤って公開する可能性があります。自動化のために資格情報を保存する必要がある場合は、ファイルのアクセス許可を制限し、専用の低権限アカウントを使用します。

chmod 600 /home/backup/.my.cnf
chown backup:backup /home/backup/.my.cnf

対話型管理の場合は、パスワードの入力を促す方法を優先します。

mysql -u admin -p

4. サーバーにパッチを適用して確認する

セキュリティ構成は、パッチが適用されていないサーバーを保護しません。通常のパッケージまたはベンダーの更新プロセスを通じて、MySQL、クライアントライブラリ、およびオペレーティングシステムを最新の状態に保ちます。

my.cnfを変更した後、メンテナンスウィンドウ中に検証して再起動します。

mysqld --validate-config
sudo systemctl restart mysql
sudo systemctl status mysql

パッケージ名とサービス名はディストリビューションによって異なります。一部のシステムでは、mysqlの代わりにmysqldを使用します。

5. アクセスを監視し、権限を確認する

強化は最初の1回で終わりではありません。特にアプリケーションの変更やスタッフの異動後は、アカウントと権限を定期的に確認します。

SELECT user, host, account_locked FROM mysql.user ORDER BY user, host;
SHOW GRANTS FOR 'my_app_user'@'localhost';

%ホスト、広範な*.*権限、FILESUPERSYSTEM_USER、またはWITH GRANT OPTIONを使用するアカウントに注意してください。これらの権限は、少数の管理アカウントでは有効である可能性がありますが、通常のアプリケーションユーザーには決して表示されるべきではありません。

要点

MySQLをレイヤーで強化します。専用の最小権限ユーザーから始め、接続元を制限し、ネットワークを通過するトラフィックを暗号化し、使用しないリスクの高い機能を無効にし、サーバーにパッチを適用し続けます。次に、古いアクセスが静かに次のインシデントにならないように、権限レビューをスケジュールします。