はじめに
この連載では、オープンソースのリレーショナル・データベース(RDB)の「MySQL」と「PostgreSQL」を使いこなすヒントを、両製品の共通点と違いを確認しながら解説していきます。
現在、それぞれの製品をベースとしたクラウド・データベースは複数存在しています。一方でユーザーがデータベースを含むインフラ全てを管理する運用形態にもクラウド・ベンダーの都合に振り回されずに済むなどのメリットもあります。連載ではクラウドにも共通するテーマにも触れながら、オープンソースである両製品をフル活用するためのTipsも紹介していきます。
なお、この連載では製品の比較を多く行いますが、製品機能や仕様の優劣についてを論ずる目的のものではないことはあらかじめご了承ください。
今回は、MySQLとPostgreSQLのセキュリティについて解説します。
セキュリティで検討すべき項目
昨今、標的型攻撃やランサムウェアによる攻撃、脆弱性に起因する情報漏洩など、セキュリティの脅威となる要因が激増しています。さらに不安定な国際情勢を背景とした地政学的なリスクもこれまで以上にシステムの運用において重要な考慮点となっています。機密情報を含めた業務に重要なデータを集積したデータベースを保護することは、事業継続性を担保する観点からも必須となっています。
米国国立標準技術研究所が組織のサイバーセキュリティのリスクを管理・軽減するためのガイドラインである「NIST Cybersecurity Framework (CSF) 2.0」では、サイバー攻撃対策を「経営リスク管理」の中核に据え、予防から復旧までのプロセスを強化するための指針を示しています。この中で施策の大項目として6個の機能(Function)を定義しています。
【出典】The NIST Cybersecurity Framework (CSF) 2.0
- ガバナンス(GV):戦略・方針の確立
- 特定(ID):資産とリスクの把握
- 防御(PR):攻撃の未然防止・データ保護
- 検知(DE):異常の早期発見
- 対応(RS):被害の最小化
- 復旧(RC):事業の早期再開
これらはデータベースのみに限った話ではなく、またデータベース単体で対策を行うものではありませんが、データベースの機能または関連ツールで担保されるものも数多くあります。また脆弱性情報を入手しておくことはリスクを把握することにもつながりますし、定期的にパッチの適用を行うことは攻撃を未然に防ぐことにもつながります。
データベースの「防御」
前項で紹介した6個の機能のうち「防御」は、データベース関連の機能で言えば、
- 3.1. 通信経路の防御 - 通信暗号化
- 3.2. 認証認可 - 権限の最小化、パスワード/認証方式
- 3.3. データの保護 - データ暗号化、鍵管理、DBファイアウォール、匿名化、バックアップ暗号化
通信経路の防御
アプリケーションとデータベースの通信を保護するための基本は通信経路の暗号化です。
MySQLは原稿執筆時点でサポートされている8.0、8.4 LTSおよび9.xイノベーション・リリースでは、OpenSSLによるTLS 1.2、1.3をサポートしています。サーバー側では暗号化通信がデフォルトで有効となっており、クライアント側も基本的には暗号化された通信を試みます。またX509証明書や利用するプロトコルおよび暗号スイートの設定を行うことが可能で、サーバー側とクライアント側の双方で暗号化を必須とするか、認証局(CA)やクライアントのホスト名の検証を必須とするか、などの設定も可能です。
同様にPostgreSQLもTLS 1.2、1.3をサポートし、X509証明書や暗号スイートの設定と検証の必須化に関する設定も可能です。デフォルトでは暗号化通信が有効となっていないため、設定ファイルpostgresql.confにてsslパラメータをonにする必要があります。
MySQLの通信暗号化に関する特徴的な点は、MySQLのシステム変数admin_ssl_*を使って管理者専用のポートであるAdmin portに対して、アプリケーション用のポートとは異なる暗号化の設定が可能なことです。
PostgreSQLで特徴的な点は、パスフレーズで保護された秘密鍵をサーバー起動時に復号する際などに、プロンプトでパスフレーズの入力の促す代わりに外部コマンドを実行するssl_passphrase_commandオプションを利用できること、またECDHキー交換で使われる曲線の名前を指定するssl_ecdh_curveオプションが用意されていることです。
クライアントからの接続が暗号化通信を利用しているかは、MySQLの場合にはMySQL Shellではプロンプトに「ssl」の文字が表示されていることで確認できます。旧来のMySQLクライアントmysqlには同様の出力はありません。PostgreSQLの場合は接続時にメッセージが表示されます。
$ psql -h 127.0.0.1 -U postgres
psql (18.1)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off, ALPN: postgresql)
Type "help" for help.
ここではTLSのバージョンが「1.3」で、暗号スイートが「TLS_AES_256_GCM_SHA384」であることが確認できます。
表1:通信の暗号化に関する比較
| MySQL | PostgreSQL | |
|---|---|---|
| デフォルト有効 | Yes | No |
| プロトコル | TLS 1.2、1.3 | TLS 1.2、1.3 |
| クライアントの検証モード | PREFERRED、REQUIRED、VERIFY_CA、VERIFY_IDENTITY | require、verify-ca、verify-full |
| 設定の確認 | SHOW VARIABLES LIKE 'require_secure_transport'; SHOW VARIABLES LIKE '%ssl%'; SHOW VARIABLES LIKE '%tls%'; |
SELECT name, setting FROM pg_settings WHERE name LIKE '%ssl%'; ※ postgresql*-contribに含まれる拡張機能sslinfoを有効後に実行 |
| 接続状況の確認 | SHOW SESSION STATUS LIKE '%tls_%'; SHOW SESSION STATUS LIKE '%tls_%'; |
接続時の出力 SELECT * FROM pg_stat_ssl; |
【参考】MySQLの暗号化通信設定
【参考】PostgreSQLの暗号化通信設定
認証認可
ここでは、認証をアプリケーションからデータベースに接続するユーザーを確認すること、認可を何にアクセスできるかの権限の確認を指しています。
ユーザーアカウント
MySQLのユーザーアカウントは、ユーザー名と接続元ホストの組み合わせとなっています。同じユーザ名scottでも、接続元ホストが異なると別のユーザーアカウントとして認識されます。ログインに関する情報はmysqlデータベースのuserテーブルにパスワード、または認証方式に関する情報を含めて格納されています。
【参考】https://dev.mysql.com/doc/refman/8.4/en/access-control.html
PostgreSQLのユーザーアカウントの仕組みはロールの概念が軸となり、LOGIN属性を持つロールがユーザーとみなされます。初心者向けの書籍などでは「ロールとユーザーを同様のものと捉えて良い」としている場合もあります。
【参考】https://www.postgresql.jp/document/17/html/user-manag.html
ユーザーに関するもう1つの大きな違いがOSのユーザーとデータベースのユーザーの関係です。MySQLではデフォルトでOSのユーザーはデータベースのユーザーとは一切関連がありません。一方でPostgreSQLはクライアントアプリケーションのpsqlのオプションでユーザーを指定しない場合、psqlを起動したユーザー名でデータベースへのログインを試みます。
認証方式
どちらの製品も、パスワードを用いた認証方式がサポートされています。
MySQLはパスワード認証がデフォルトです。認証方式はプラグインとして提供されており、Unixソケット経由でのアクセス時のみOSのユーザーを用いた認証を行う「Socket Peer認証」や、パスワードを平文でやりとりする「Client-Side Cleartext認証」などがあります。
MySQLの認証で特徴的なのは、データベース外の認証情報を利用する形式は商用版の「Enterprise Edition」でプラグインが利用可能となっている点です。また、ストアドルーチンやストアドファンクションの実行専用のユーザーを用意するための「No-Login認証」もあります。
MySQLは多要素認証(MFA)をサポートしており、最大で3つの認証方式を利用できます。パスワード変更時にもアプリケーションからのアクセスを阻害しないために、1つのユーザーアカウントに一時的に複数のパスワードを持たせることも可能です。
【参考】https://dev.mysql.com/doc/refman/8.4/en/pluggable-authentication.html
【参考】https://dev.mysql.com/doc/refman/8.4/en/multifactor-authentication.html
PostgreSQLでは、インストール直後は「trust認証」と呼ばれる、サーバーに接続できる全てのユーザーにアクセス権を付与する仕組みがデフォルトになっています。クライアント認証に関する設定ファイルpg_hba.confには、初期情報としてローカルホストからの接続に関する情報のみが記載されています。もちろんパスワード認証も利用でき、他にもMySQLでは商用版のみでサポートされている「Kerberos」や「Microsoft Active Directory」を用いた認証や「LDAP認証」「RADIUS認証」に加えて、クライアント証明書を用いた「証明書認証」もサポートしています。なお、PostgreSQL 18の時点で多要素認証はサポートされていません。
【参考】https://www.postgresql.jp/document/17/html/client-authentication.html
表2:認証に関する比較
| MySQL | PostgreSQL | |
|---|---|---|
| インストール時のデフォルトユーザー | root | postgres |
| パスワードのハッシュ方式 | - caching_sha2_password (暗号化アルゴリズム SHA-2) - 下位互換のためMySQL 8.4LTSのみ mysql_native_password (暗号化アルゴリズム SHA-1)をサポート |
- SCRAM-SHA-256 (暗号化アルゴリズム SHA-2) - 下位互換のためにmd5あり |
| パスワードポリシー | 期間指定 validate_passwordプラグインによる検証 |
期間指定 passwordcheckによる検証 |
| 認証方式 | パスワード認証 Client-Side Cleartext認証 PAM認証* Windows認証* LDAP認証* Kerberos認証* OpenID Connect認証* No Login認証 Socket Peer-Credential認証 WebAuthn認証* テスト認証(開発用途) ※はEnterprise Editionのみ |
trust認証 パスワード認証 GSSAPI認証 SSPI認証 ident認証 peer認証 LDAP認証 RADIUS認証 証明書認証 PAM認証 BSD認証(OpenBSDでのみ利用可能) |
権限管理
MySQLの権限モデルは、基本的にユーザーとロールが別の概念となっています。MySQLにおけるロールは基本的に「権限の集合」に名前を付けて再利用する仕組みです。
一方で、PostgreSQLの場合は先ほどユーザーアカウントについて説明したとおりLOGIN属性のあるロールがユーザーとなり、LOGIN属性がない、またはNOLOGIN属性のあるロールは「グループ」と呼ばれます。ロールでアカウントと権限の管理を両立しています。
MySQLの権限管理はスキーマやテーブル、列などのデータベース・オブジェクトへのアクセス権およびコマンドの実行権の管理となります。MySQLのデータベース・オブジェクトには所有者の概念がありません。MySQL 8.0より前のバージョンでは管理系の操作はSUPER権限に集約されていましたが、セキュリティの向上を目的として権限が細分化されています。なお、SUPER権限は非推奨となっており、将来のバージョンで削除されることになっています。
【参考】https://dev.mysql.com/doc/refman/8.4/en/privileges-provided.html
PostgreSQLのロールには、ログイン権限以外にもデータベースやロール、レプリケーションの作成といったデータベース全体に関わる「属性」があります。スーパーユーザーの属性も存在します。全てのデータベース・オブジェクトには所有者があり、ロールが所有者になります。所有者は対象のオブジェクトに対してフル権限を持ち、ALTER OWNERで他のロールに所有者を移譲可能です。オブジェクト単位でSELECTや各DMLの実行に関する権限を設定でき、ロールを別のロールに付与することで権限の継承も可能です。
【参考】https://www.postgresql.jp/document/17/html/ddl-priv.html
表3:権限管理に関する比較
| MySQL | PostgreSQL | |
|---|---|---|
| 権限モデルの基本 | データベース・オブジェクトへのアクセス権の管理 | ロールベースで一元管理され、所有権とオブジェクトごとの権限 |
| 権限のスコープ | グローバル、データベース、テーブル、カラム、ストアドブログラムなど | データベース、スキーマ、テーブル、カラム、シーケンス、関数、タイプなど |
| オブジェクト作成時の権限テンプレート | なし |
ALTER DEFAULT PRIVILEGESで設定可能 |
| ロールの一時的な利用 |
SET ROLEで可能 |
SET ROLEで可能 |
| 現在のユーザーの権限の確認 | SHOW GRANTS; |
\du(属性の確認)SELECT relname, relacl FROM pg_catalog.pg_class;(オブジェクト権限の確認) |
おわりに
今回はMySQLとPostgreSQLのセキュリティ関するテーマのうち、通信経路の防御と認証認可について解説しました。通信暗号化に関しては大きな違いは見られないものの、ユーザーや権限は概念が大きく異なっていることが分かります。
次回は両製品のセキュリティ関連の項目のうち、データの保護に関する機能の解説を予定しています。
- この記事のキーワード