オープンソースDB運用管理Tips 3

「MySQL」と「PostgreSQL」の「データの暗号化」機能を比較する

第3回の今回は、「MySQL」と「PostgreSQL」のセキュリティに関するテーマのうち、「データの暗号化」について解説します。

梶山 隆輔

8:40

はじめに

この連載では、オープンソースのリレーショナル・データベース(RDB)の「MySQL」と「PostgreSQL」を使いこなすヒントを、両製品の共通点と違いを確認しながら解説していきます。

現在、それぞれの製品をベースとしたクラウド・データベースは複数存在しています。一方でユーザーがデータベースを含むインフラ全てを管理する運用形態にもクラウド・ベンダーの都合に振り回されずに済むなどのメリットもあります。連載ではクラウドにも共通するテーマにも触れながら、オープンソースである両製品をフル活用するためのTipsも紹介していきます。

なお、この連載では製品の比較を多く行いますが、製品機能や仕様の優劣についてを論ずる目的のものではないことはあらかじめご了承ください。

今回は、MySQLとPostgreSQLのセキュリティの中でも特にデータの暗号化について解説します。

データベースのデータ暗号化の方式

データベースの保存データ暗号化は、権限の不適切な設定による不正アクセスによるデータの盗難、また物理的なストレージデバイスの紛失や盗難、などのリスクに備える基本対策です。

データを暗号化せずに保管すると、データへの不正アクセスが行われた際に再利用可能な形で漏えいすることになります。これは、各種の法規制違反、企業価値やブランドの毀損を招き、多大な経済的損失につながります。データの暗号化には「暗号鍵」を利用しますが、この鍵の管理も重要です。鍵が攻撃者に入手されてしまえば、データの暗号化も無意味になってしまいます。

データベースに保存されたデータの暗号化は、目的と脅威モデルに応じて大別すると3つの方式に分類できます。

  1. アプリケーションでDBの暗号化関数を利用
  2. データベースの透過的データ暗号化(TDE: Tranparent Data Encryption)
  3. ファイルシステムやストレージ・デバイスの持つ暗号化機能を利用

このデータの暗号化の3つの方式を比較すると、下表のようになります。

表1:データの暗号化の方式の比較

レイヤーメリットデメリット
1. アプリケーションでDBの暗号化関数を利用内部不正や侵害時もデータの露出の可能性を最小化
列単位で最小限の保護
バックアップやレプリケーションでも暗号化状態を維持しやすい
アプリケーション側での暗号化と複合の処理が必須
(アプリケーションの改修が必要な可能性)
ソートやインデックスの利用は制約が大きい
2. データベースの透過的データ暗号化アプリケーション改修不要で広範囲を一括保護
データ以外にもログなども保護
運用が比較的シンプル
データベースへの正規のアクセスには効果なし
データベースに侵入された場合や特権ユーザーへの対策にはならない
仕様は製品依存(機能未搭載の製品では使えない)
3. ファイルシステムやストレージ・デバイスの
持つ暗号化機能
データベースに非依存で一括適用が容易
ログや各種のファイルもまとめて保護
既存システムへ低コスト適用しやすい
粒度が粗く内部脅威対策にならない(マウント後は平文扱い)
暗号化対象の列を個別制御できない
図:データの暗号化の方式の比較概念図

データの暗号化を行うためのSQL関数

データベースに用意された暗号化関数を利用する場合、アプリケーションがデータの暗号/復号を担います。データベースには暗号化済みのデータが保存されるため、データベースへの不正ログインによる侵害時にデータの漏洩の可能性を最小化できることが利点です。

なお、SQL関数を明示的に利用する必要がある点に加えて、元のデータとは異なる値がデータベースに格納されるため元データに基づくソートや範囲検索ができない点は注意が必要です。また暗号化によりデータの分布や特性が変化するため、インデックスを使った検索が効率的に機能しない可能性があります。

MySQLの暗号化関数はコミュニティ版で利用できるものと、商用版のEnterprise Edtionで追加されるものがあります。PostgreSQLの暗号化関数ははcontribにあるpgcryptoモジュールに含まれています。どちらもOpenSSLを利用する点は共通しています。

ハッシュ関数

どちらの製品にも不可逆なランダムの文字列を生成する「ハッシュ関数」と、可逆的な変換を行う「暗号化関数」が用意されています。MySQLではハッシュ化の規格によって関数が分かれていますが、PostgreSQLは関数の引数で規格を指定する仕様になっています。

MySQLではSHA-2を用いるSHA2()関数のみが推奨となっており、第2引数でハッシュ長を選択できます。MySQLで特徴的なのがSQL文のハッシュ値を計算するSTATEMENT_DIGEST()関数です。

この関数はMySQLのパーサーによる構文解析を行った上でハッシュ値を生成します。MySQLの内部ではSTATEMENT_DIGEST_TEXT()関数によりSQL文からスペースの調整や条件式の値を「?」に置き換えるなどの「正規化」を行った上でハッシュ化を行い、Performance SchemaでのSQL文を一意に識別するための値として利用されています。

PostgreSQLの汎用ハッシュ関数であるdigest()はシンプルにハッシュ値の計算を行いますが、hmac()関数は第2引数にキーの文字列を設定することでキーを知っている場合にのみ同じハッシュ値が得られるようになっています。同様の関数はMySQLには用意されていません。

表2:ハッシュ関数の比較

MySQLPostgreSQL
セットアップ追加作業不要
非対称暗号はEnterprise Edition利用
pgcryptoのインストールと関数の登録が必要
ハッシュ関数MD5(), SHA1(), SHA(), SHA2()
*SHA2()以外の関数は衝突攻撃のリスクがあるため非推奨
digest(), hmac()
ハッシュ長224, 256, 384, 512224, 256, 384, 512

暗号化関数

「対称暗号関数」は、基本的にはMySQLではAES_ENCRYPT()AES_DECRYPT()の組み合わせ、PostgreSQLでは「PGP暗号化関数」であるpgp_sym_encrypt()pgp_sym_decrypt()の組み合わせです。なお、PostgreSQLにはencrypt()decrypt()も用意されていますが、マニュアルでもPGP暗号化の利用が多く、こちらの組み合わせはあまり使用されないとされています。

MySQLでは、アプリケーションから第2引数で渡された鍵の文字列を元に「鍵導出関数(KDF)」で暗号的に強力な秘密鍵を作成し、暗号化と復号に利用できるようになっています。

PostgreSQLではオプション文字列はGnuPGに似せて定義されており、この中で暗号アルゴリズムなどを指摘できます。特徴的なのはオプションの1つとして暗号化関数の中でデータの圧縮が可能な点です。

  • MySQL: AES_ENCRYPT(暗号化対象文字列, 鍵の文字列[, 初期化ベクトル][, 鍵導出関数KDF名][, ソルト][, KDFのオプション])
  • PostgreSQL: pgp_sym_encrypt(暗号化対象文字列, パスワードの文字列 [, オプション文字列 ])

非対称暗号はMySQLでは商用版のEnterprise Editionに付属のcomponent_enterprise_encryptionコンポーネントをインストールの上でasymmetric_encrypt()asymmetric_decrypt()が利用可能です。PostgerSQLではpgp_pub_encrypt()pgp_pub_decrypt()が該当します。

MySQLでは用意されている関数create_asymmetric_priv_key()create_asymmetric_pub_key()を利用して秘密鍵とそこから公開鍵を生成し、それぞれをアクセスできるユーザーを分離したテーブルや列などに格納しておきます。秘密鍵は復号時に利用するため、暗号化前のデータにアクセスしても問題ないユーザーのみが参照できるテーブルや列に保管しておきます。

PostgreSQLでは鍵を作成する関数は用意されていないため、GnuPGを用いて鍵を生成する方法がマニュアルに記載されています。

表3:暗号化関数の比較

MySQLPostgreSQL
対称暗号関数AES_ENCRYPT()AES_DECRYPT()pgp_sym_encrypt()pgp_sym_decrypt()
対称暗号アルゴリズムAES128, AES196, AES256AES128, AES196, AES256, Blowfish, CAST5, TripleDES
非対称暗号関数asymmetric_encrypt()asymmetric_decrypt()
*商用版のEnterprise Editionのみで利用可能
pgp_pub_encrypt()pgp_pub_decrypt()
非対称暗号アルゴリズムRSARSA, DSA, ElGamal
OpenPGPの仕様に基づく
SELECT AES_ENCRYPT('機密情報', HEX(RANDOM_BYTES(32)));

いずれの暗号化関数もアプリケーション側でSQL文の中で利用する必要があるため、既存アプリケーションでの利用には修正が伴います。SQL文の修正を抑えて対応するには、以下の2つの方法が考えられます。

  1. ビューを利用する
  2. サーバー側でSQLの書き換える

ビューを利用する方法は暗号化用と復号用の関数を使ったビューをそれぞれ作成しておき、アプリケーションからのアクセス先を振り分けます。この場合でもテーブル名が異なるためアプリケーションの書き換えは必要となってしまいます。

サーバー側でSQLの書き換える方法は、MySQLではクエリ・リライト・プラグインを利用することで対応できます。PostgreSQLではオープンソースのpg_query_rewriteが候補となりますが、プリペアドステートメントには非対応となっています。

暗号化関数を利用する上での注意点はログです。MySQLであれば一般ログやスロークエリーログに、PostgreSQLでもログに暗号化前の値が記録されるため、機密情報の取り扱いの際はログへのアクセス管理も重要です。

【MySQLの場合】
# スロークエリーログに記録される閾値を1秒として下記を実行した場合
mysqlsh> SELECT SLEEP(2), AES_ENCRYPT('機密情報', 'my_pass');
+----------+------------------------------------+
| SLEEP(2) | AES_ENCRYPT('機密情報', 'my_pass') |
+----------+------------------------------------+
|        0 | 0xB039A8B18F19AACB4CF68AF75A6D05F8 |
+----------+------------------------------------+

# 一般ログ
2026-01-01T12:34:56.003306Z	   10 Query	SELECT SLEEP(2), AES_ENCRYPT('機密情報', 'my_pass')

# スロークエリーログ (抜粋)
# Time: 2026-01-01T12:34:56.003306Z
SELECT SLEEP(2), AES_ENCRYPT('機密情報', 'my_pass');
【PostgreSQLの場合】
# ログの出力対象をALLとして下記を実行した場合
postgres=# select pgp_sym_encrypt('機密情報', 'my_pass');
               pgp_sym_encrypt                
                                                         
-------------------------------------------------------------------------------------------------------
 \xc30d04070302dca52e8e45d73ca877d23d012159b8a5c8c4910ad51e4af5737246a0722a4b55d9cc6846fb91269d70415f78
4a58bf1ab03b2053c2e3babae649f027494d3886f8d340712a17d12f
(1 row)

# ログ
2026-01-01 12:34:56.789 GMT [8010] LOG:  statement: select pgp_sym_encrypt('機密情報', 'my_pass');

データベースの透過的データ暗号化(TDE)

TDEは、データベースのデータファイルに不正アクセスがあってもデータが漏洩しないことを目的に利用されています。データをアプリケーション側で暗号化した上でデータベースに格納する暗号化関数とは異なり、TDEではアプリケーションは暗号化の処理は行いません。データをファイルシステムやストレージに書き込む際にデータベースが自動的に暗号化します。

読み込みの際にも自動的に復号が行われます。アプリケーションは暗号化について意識しなくても良いという意味で「透過的」と呼ばれています。データベース内ではデータは暗号化されていない平文となっています。

MySQLでは5.7以降でInnoDBストレージ・エンジンの表および表領域単位での暗号化がサポートされています。サーバーの設定でdefault_table_encryptionONにすると全てのテーブルが暗号化の対象となります。

表および表領域単位で個別に指定する場合は、CREATE文またはALTER文のオプションにENCRYPTION = 'Y'を指定します。また、バイナリログ、REDOログやUNDOログも下記の設定をONにすることで暗号化可能です。ダブルライトバッファは表および表領域で暗号化を行う対象の場合には内容が暗号化されます。

  • バイナリログ: binlog_encryption
  • REDOログ: innodb_redo_log_encrypt
  • UNDOログ: innodb_undo_log_encrypt

【参考】[リファレンス・マニュアル] 17.13 InnoDB Data-at-Rest Encryption

PostgreSQL本体やcontribにはTDEは実装されていません。2016年に最初のパッチが提案されていますが、原稿執筆時点では実装に至っていません

一方で複数の企業が独自の実装を商用版として提供しており、NECからは一部機能をFree Editionとしてオープンソースで公開しています。主なTDEを提供する製品は以下の通りです。

透過的データ暗号化における鍵管理

データの暗号化においては、暗号化そのものももちろん重要ですが、暗号化の際に利用する鍵の管理も同じく重要です。仮にどれだけ高度な暗号化アルゴリズムを利用していても、鍵が正しく保護されていなければ、結局元のデータが読み取られてしまい意味がありません。

MySQLのコミュニティ版では、TDEで利用する鍵はローカルまたはファイルサーバー上のファイルに格納します。MySQLサーバーの起動時にメモリ上にロードされ、以降は鍵ファイルにアクセスする必要はないため、起動時のみマウントする領域に鍵ファイルを置くなど、運用で工夫することでリスクを下げることも考えられます。

また、運用負荷を抑えつつセキュリティを強化するために、商用版のEnterprise Editionではパスワードで保護された鍵ファイルやOracle Key Vault、Gemalto KeySecureといったKMIP(Key Management Interoperability Protocol) 1.1準拠の鍵管理システムをはじめ、AWS Key Management Service(AWS KMS)およびHashiCorp Vaultで鍵を管理できるようになっています。提案されているPostgreSQLのパッチでも、設計として外部の鍵管理ソリューションと連携できるAPIを用意するとしています。

暗号化の鍵は定期的に新しいものに切り替える「ローテーション」を行うのが一般的です。長期的に同じ鍵を利用することによる漏洩や解読によるリスクの低減、セキュリティ侵害時の被害範囲の限定、またローテーションが義務づけられているクレジットカード業界の情報セキュリティ基準であるPCI DSSなどへの準拠が目的となります。

MySQLのTDEと、現在提案されているPostgreSQLのパッチは、ともに2層の鍵管理となっています。1つの鍵でTDEを実現しようとするとローテーションのたびに対象の表や表領域全体の再暗号化が必要となり、ディスクIOが発生するため特にデータ量が多い場合には現実的ではありません。

2層の鍵管理は、(1)表や表領域を暗号化する表領域鍵、(2)表領域鍵を暗号化するマスター鍵、の2つを利用します。ローテーションの際はマスター鍵のみを切り替えることでデータ全体の再暗号化を回避できます。MySQLのTDEは暗号化アルゴリズムとしてAES-256を採用しているため、ローテーションされる鍵のサイズは256ビット、つまり32バイトと小さく、システムへの負荷は無視できます。

ファイルシステムや
ストレージ・デバイスの持つ暗号化機能の利用

データベースの機能ではなく、ファイルシステムやストレージ・デバイスの暗号化機能を利用してデータ、より正確にはデータファイルやデータディレクトリを保護することもできます。ストレージ・デバイスによる暗号化はストレージのコントローラで暗号鍵の生成や管理、データの暗号化を行う仕組みとなっています。利用するOSやディストリビューション、またはストレージ・デバイスの機能に依存するため、データベースのバージョンや機能によらず暗号化が実現できるのが利点です。

マネージドサービスの場合には透過的データ暗号化を利用せず、ストレージレイヤーでの暗号化が一般的です。例えば、オラクルのMySQL HeatWaveとOCI Database with PostgreSQLはデフォルトで暗号化が有効で無効化の選択肢はなく、Amazon RDSではインスタンスの作成時などに暗号を有効化を選択することができるようになっています。

おわりに

今回はMySQLとPostgreSQLのセキュリティ関するテーマのうち、データの暗号化について解説しました。アプリケーション目線でのデータを暗号化する関数、データベースの表や表領域、ログを自動的に暗号化する透過的データ暗号化、もしくはデータベース外でデータファイルやログファイルを暗号化する方式を要件に応じて選択してください。場合によっては複数の方式を組み合わせることも考えられます。

次回は両製品のセキュリティ関連の項目のうち、ソフトウェアを安全に利用する観点での解説を予定しています。

この記事をシェアしてください

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored