Oracle TDE 表領域暗号化①|設計と基本構築:盗まれたデータファイルを読ませない

【連載】Oracle TDE 表領域暗号化
  1. 設計と基本構築(この記事)
  2. 守れる範囲・守れない範囲
  3. 鍵の管理
  4. SYSTEM・SYSAUX・UNDO・TEMPを暗号化

暗号化していないデータベースのデータファイル(.dbf)は、DBへログインする必要も、特別な解析ツールもなく、Linux標準の strings コマンドを通すだけで中身が見えてしまいます。

実際にやってみると——

$ strings /u01/app/oracle/oradata/ORCL19U/plain_ts01.dbf | grep -E 'PLAINTEXT-LEAK|4111-1111'
PLAINTEXT-LEAK-0614
4111-1111-1111-1111

このように氏名もカード番号も、そのまま読めます。

暗号化していないテーブルのデータは、ディスクの上では“ただのテキスト”として並んでいるからです。つまり、ファイルさえ手に入れば誰でも読めます

たとえば——

  • 退役したHDDの廃棄漏れ
  • バックアップメディアの紛失
  • ストレージ機器の持ち出し
  • データファイルのコピー流出

こうした「物理的にファイルを抜かれる」その1点だけで、データは丸裸になります。

これを防ぐのが TDE(Transparent Data Encryption / 透過的データ暗号化) です。この連載では、Oracle Database 19c で表領域を暗号化し、上の grep何も出てこなくなるところまでを実機で検証します。


この記事について

本記事は、Oracle Database 19c の TDE 表領域暗号化を、攻撃される前と後を実際に見せて検証する連載の第1回です。設計の考え方と、暗号化の基本構築(ウォレット〜マスター鍵〜暗号化表領域)までを扱います。

連載の全体マップ:

記事タイトル内容
第1回(本記事)設計と基本構築——盗まれたデータファイルを読ませない脅威モデル・方式設計・盗難実証(before)・ウォレット/鍵構築・守られる実証(after)
第2回守れる範囲・守れない範囲——ユーザー表領域が暗号化済みなのに平文が残る場所はどこかUNDO/TEMP・統計(SYSTEM)・AWR(SYSAUX)への平文コピーの検証
第3回鍵の管理——失えばデータは二度と戻らない既存表領域のオンライン暗号化移行・ウォレットファイルはいつ必要か・鍵バックアップとDR
第4回SYSTEM・SYSAUX・UNDO・TEMPを暗号化——統計・AWR経由の平文漏洩を実機で塞ぐ統計・AWRの平文漏洩を防ぐbefore/after・UNDO/TEMPの暗号化・REDOに平文が残る検証

想定読者:

  • Oracle Database 19c を運用していて、保存データの暗号化(at-rest encryption)を検討している方
  • 「TDEは聞いたことがあるが、実際に何をどこまで守るのか」を手を動かして確かめたい方
  • セキュリティ要件(PCI DSS・個人情報保護など)でデータ暗号化を求められた方

前提知識:

  • SQL*Plus の基本操作(sqlplus / as sysdba での接続)
  • Oracle の表領域・データファイルの基本概念
  • Linux の基本コマンド

第2回以降は、TDEが守らない範囲鍵運用のリアルに踏み込みます。本記事はその土台です。


検証環境

項目
VMdb-node(Oracle Linux 8.9)
DBバージョンOracle Database 19c Enterprise Edition 19.28.0.0.0
構成非CDB(non-multitenant)
ORACLE_SIDorcl19u
データファイル格納先/u01/app/oracle/oradata/ORCL19U
キーストア方式ソフトウェアキーストア(WALLET_ROOT + TDE_CONFIGURATION)

原状復帰の備え: TDE のウォレット構成(キーストア作成・WALLET_ROOT 設定)は、TDE未構成の状態へ完全には戻せません。検証前に VMスナップショット(RAM込み) を取得しておくのが唯一確実な巻き戻し手段です。表領域単位の暗号化自体は DECRYPT / DROP で可逆です。

ライセンス前提: TDE(表領域暗号化)は Oracle Enterprise Edition + Advanced Security オプションの機能です。Standard Edition (SE2) では利用できません。本連載はこの前提で構築しています。


なぜTDEなのか — 「何から守るか」を先に決める

セキュリティ機能は「何から守るのか」を決めないと、やりすぎにも・足りなさすぎにもなります。TDE 表領域暗号化が守る脅威守らない脅威を、最初に線引きします。

#脅威シナリオTDE表領域暗号化
Aデータファイル/ディスクの物理窃取(盗難・退役HDD・コピー流出)→ strings/grep で直接読む守る
Bバックアップ・エクスポートの流出守る(鍵がなければ復元不可)
C認可ユーザーのSELECT・SQLインジェクション・認証情報窃取❌ 守らない
Dメモリ(バッファキャッシュ)からの読み取り❌ 守らない
Eネットワーク盗聴❌ 守らない

TDEが守るのはここ: TDEは「保存時(at-rest)の暗号化」です。ディスクを盗まれても読めないを保証しますが、正規の経路でDBにアクセスできる相手は防ぎません(それは別途アクセス制御・監査・暗号化通信の役割)。本記事では脅威 A を before / after で実証します。守らない範囲(C・D)は第2回で実際に「漏れる」ところを見せます。


設計の要点 — どの方式・どのアルゴリズムを選ぶか

実機に入る前に、設計の判断を書いておきます。「動いたからOK」で済ませず、なぜそれを選んだかを残すのが、構築の値打ちだと思います。

方式選定:ソフトウェアキーストア(FILE方式)

TDEのマスター鍵をどこに保管するかで、主に3つの選択肢があります。

  • FILE(ソフトウェアキーストア) … 鍵をOS上の暗号化ファイル(ewallet.p12)として保管する方式。追加費用ゼロで、今回採用する方式です。
  • HSM(Hardware Security Module) … 鍵を専用の耐タンパ性ハードウェアに格納する方式。堅牢だが高価。
  • OKV(Oracle Key Vault) … 鍵を専用サーバで集中管理する方式。多数のDB・多数の鍵をまとめて運用・監査できる。

用語の使い分け: 本記事では、鍵の保管方式の総称と作成・開閉コマンド(CREATE KEYSTORE など)を「キーストア」、その FILE 方式でできる実体ファイル ewallet.p12 とその状態を「ウォレット(ウォレットファイル)」と呼びます。Oracle 自身、コマンドは KEYSTORE・ビューは v$encryption_wallet と両語を使うため、役割で使い分けます。

この3つを、評価軸ごとに採点(◎3/○2/△1/✕0)して比較します。

評価軸FILE(ソフトキーストア)HSMOracle Key Vault(OKV)
コスト◎3 無償✕0 高価な専用HW△1 専用サーバ要
鍵の保護強度△1 OS権限頼み◎3 専用HWで堅牢◎3 集中・堅牢
多数DBの鍵集中管理✕0 DB個別○2◎3
可用性・冗長化△1 自前コピー○2◎3
導入/運用の手軽さ◎3△1○2
合計11813

点数トップ=採用、ではない: 合計点トップは OKV(13) ですが、今回の事情(追加コスト不可・DBは1台・短期の検証)ではコストと手軽さの比重が大きく、FILE 方式を採用します。

ただし FILE 方式には、本番では見過ごせない弱点があります。

  • 鍵の保護がOS権限頼みewallet.p12 を読めるOSユーザー(root・oracle)は、ウォレットファイルごと持ち出せる。HSM/OKVのような「鍵をハードや専用サーバから出さない」保護がない
  • 鍵の集中管理ができない … DBごとにファイルが分散。DBが増えるほど、鍵のバックアップ・ローテーション・棚卸しが手作業で破綻しやすい
  • 監査の証跡が弱い … 「誰がいつ鍵にアクセスしたか」をDB外で追えない(OKVは集中ログを持つ)

ただし、FILE方式が無防備というわけではありません。データを復号するには 3つの要素が揃う必要があります

  1. データファイル(.dbf — 暗号文と、暗号化された表領域キー
  2. ウォレットファイル(ewallet.p12 — パスワードで暗号化されたマスター鍵
  3. ウォレットのパスワードewallet.p12 を開くためのパスワード

攻撃者が .dbfewallet.p12両方を持ち出しても、パスワード(3つ目)がなければウォレットを開けず、マスター鍵を取り出せません。FILE方式の「OS権限頼み」という弱点は、このパスワードが最後の砦になることで、ある程度緩和されています。

⚠️ ただしこれはパスワード方式のウォレットの場合です。自動ログイン(cwallet.sso)を導入すると、パスワードがファイルに埋め込まれ、ewallet.p12 を盗まれた時点で守りが崩れます。この「可用性 × 窃取耐性」のトレードオフは第3回で実証します。

設計は「一番強い技術」を選ぶことではなく、「その場面で効いてくる軸」で選ぶことです。DBが1台・検証目的なら FILE で十分ですが、本番で複数DBの鍵をまとめて管理・監査するなら OKV が定番です。

アルゴリズム:AES256

まず前提として、AES128も現時点で破られていません。128bit鍵の総当たりは現実的に不可能で、実務上は128でも安全です(注1)。そのうえで本記事は AES256 を選びます。理由は「128が危ないから」ではありません。

観点判断
安全マージン計算機の進歩や量子計算(実効強度が半減する)を見込んでも、256なら128bit相当が残る。将来への余裕が大きい
コンプライアンスNSAのSuite Bは元々「AES-128=SECRETまで/AES-256=TOP SECRET」と規定し、2015年に「全機密をAES-256相当で守るべき」と更新した(注2)。256なら要件で揉めない
性能コスト暗号単体では256が128より約1割遅い(ラウンド数14対10)が、AES-NIにより絶対速度はGB/s級。TDEはディスクI/Oが律速なので、実用上の差はさらに小さい(注3)

192bitは標準でも実務でもほとんど使われない中間値で、選択肢は実質 128か256の二択。「1割の性能差と引き換えに、将来への余裕とコンプライアンス適合が手に入る」ので256にします。

なお、Oracleで暗号化アルゴリズムを省略すると既定はAES128です。意図せず128で作られるのを防ぐため、USING 'AES256' を必ず明示します。

鍵の階層 — なぜ「鍵を失う=データ永久喪失」なのか

TDEの鍵は2段構造で、データを読むには上から順に「鍵で次の鍵を開けていく」必要があります。

① ウォレットのパスワード
     ↓ で開く
② ウォレット(ewallet.p12)
     ↓ の中にある
③ マスター鍵(MEK)        ← ★ウォレットの中だけに存在
     ↓ で復号する
④ 表領域キー(Tablespace Key) ← データファイルの中にある(ただし施錠済み)
     ↓ で復号する
⑤ 実データ

上から下へ「パスワードでウォレットを開け、中のマスター鍵で表領域キーを解錠し、その表領域キーで実データを復号する」という一本の鎖です。

ここで効いてくるのが ④ の位置。表領域キーはデータファイルの中に入っていますが、③のマスター鍵で施錠された状態です。いわば「金庫(データファイル)の中に、施錠された小箱(表領域キー)が入っている」。小箱を開ける鍵(マスター鍵)は金庫の中ではなく、ウォレットの中だけにあります。

だから——

  • データファイルを丸ごと盗まれても、③のマスター鍵が無ければ小箱(④)を開けられず、データは読めない(=脅威Aを防げる理由)
  • マスター鍵を失うと、二度と小箱を開けられず、データは永久に復号できない(=鍵バックアップが生命線の理由)

脅威Aを防げる理由も、鍵を失うと終わる理由も、すべて「マスター鍵だけが別の場所(ウォレット)にある」というこの構造から来ています(鍵バックアップは第3回で実証)。


ここからは実機 — before / after で効果を「証明」する

設計が決まったので、ここから実際に手を動かします。本記事の検証は、「暗号化したから安全」と言葉で主張するのではなく、同じ攻撃手法の結果が変わることで証明するという方針で進めます。手順は3段階です。

段階やること狙い
① before暗号化していない表領域のデータファイルを strings/grep で覗く「守られていない状態」を証拠として記録
② 構築ウォレット〜マスター鍵を作り、TDEの基盤を整える暗号化できる状態にする
③ after暗号化した表領域を、①とまったく同じ手法で覗く結果が変わる=効果の一次証拠

ポイントは ①と③で攻撃手法を完全に揃えること。条件を同じにして結果だけが変われば、「変化はTDEによるもの」と言い切れます。まずは ① の「漏れている証拠」から押さえます。


【before】暗号化前は、ディスクから平文が抜ける

まず「守られていない状態」を証拠として残します。暗号化していない表領域 plain_ts に機密データを置き、データファイルを直接 grep します。

平文表領域と機密テーブルを作成

検証用の“被害者”を用意します。暗号化していない表領域 plain_ts を作り、その中に後で grep で探せる目印を仕込んだ機密データ(氏名 PLAINTEXT-LEAK-0614 +テスト用カード番号 4111-...)を入れます。目印を特徴的な文字列にしておくのは、後でデータファイルの中からピンポイントに検索するためです。

$ sqlplus / as sysdba

SQL> CREATE TABLESPACE plain_ts DATAFILE '/u01/app/oracle/oradata/ORCL19U/plain_ts01.dbf' SIZE 50M;
SQL> CREATE TABLE hr_secret_plain (id NUMBER, name VARCHAR2(40), card VARCHAR2(30)) TABLESPACE plain_ts;
SQL> INSERT INTO hr_secret_plain VALUES (1,'PLAINTEXT-LEAK-0614','4111-1111-1111-1111');
SQL> COMMIT;
SQL> ALTER SYSTEM CHECKPOINT;   -- バッファ上でなくディスクへ確実に書き出す
SQL> SELECT tablespace_name, encrypted FROM dba_tablespaces WHERE tablespace_name='PLAIN_TS';

TABLESPACE_NAME                ENC
------------------------------ ---
PLAIN_TS                       NO

ENCRYPTED=NO。暗号化されていない普通の表領域です。

なぜ CHECKPOINT するのか: INSERT直後のデータは、まだメモリ(バッファキャッシュ)上にあり、ディスクのデータファイルには書かれていないことがあります。その状態で grep してヒットしなくても、それは「暗号化されたから」ではなく「まだ書かれていないだけ」。CHECKPOINT で変更を強制的にディスクへ書き出し、「ディスク上に平文が存在する」状態を確実にしてから覗きます。この一手間が、before/after比較の前提を保証します。

攻撃者の視点でデータファイルを覗く

ここからは「データファイルだけを手に入れた攻撃者」になりきります。DBへのログインは一切しません。OS上で、生のデータファイルに strings(バイナリから可読文字列を抜き出す)を通し、先ほど仕込んだ目印を grep で探すだけです。これは脅威A(物理窃取)そのものの再現です。

$ strings /u01/app/oracle/oradata/ORCL19U/plain_ts01.dbf | grep -E 'PLAINTEXT-LEAK|4111-1111'
PLAINTEXT-LEAK-0614
4111-1111-1111-1111

氏名もカード番号も、そのまま読めました。 これが「ディスクを盗まれたら終わり」の状態です。

⚠️ バイナリファイルは strings | grep で読みます。.dbf に直接 grep -a を打つと、1行が巨大になりターミナルが溢れることがあります。


TDEの基本構築 — ウォレットからマスター鍵まで

ここから暗号化の基盤を作ります。手順は「①鍵の置き場所を決める → ②方式を宣言する → ③鍵を作る」の3段です。

Step 1: WALLET_ROOT を設定(静的パラメータ・要再起動)

マスター鍵を保管するウォレットのルートディレクトリを指定します。これは静的パラメータなので DB再起動が必要です。変更前に pfile を退避しておきます。

SQL> CREATE PFILE='/tmp/pfile_orcl19u_before_tde.ora' FROM SPFILE;   -- 変更前バックアップ(差分確認用)
SQL> ALTER SYSTEM SET WALLET_ROOT='/u01/app/oracle/admin/orcl19u/wallet' SCOPE=SPFILE;
SQL> SHUTDOWN IMMEDIATE
SQL> STARTUP
SQL> SHOW PARAMETER wallet_root

NAME          TYPE    VALUE
------------- ------- ------------------------------------------
wallet_root   string  /u01/app/oracle/admin/orcl19u/wallet

Step 2: TDE_CONFIGURATION を設定(動的)+ tde ディレクトリ作成

キーストアの方式を「FILE(ソフトウェアキーストア)」と宣言します。こちらは動的パラメータなので再起動は不要です。実体の格納先 tde ディレクトリも先に作っておきます。

$ mkdir -p /u01/app/oracle/admin/orcl19u/wallet/tde
SQL> ALTER SYSTEM SET TDE_CONFIGURATION="KEYSTORE_CONFIGURATION=FILE" SCOPE=BOTH;
SQL> SELECT wrl_type, wrl_parameter, status FROM v$encryption_wallet;

WRL_TYPE  WRL_PARAMETER                                  STATUS
--------- ---------------------------------------------- --------------
FILE      /u01/app/oracle/admin/orcl19u/wallet/tde/      NOT_AVAILABLE

WALLET_ROOT/tde がキーストアの場所として解決されました。STATUS=NOT_AVAILABLE は「場所は決まったが、キーストア本体がまだ無い」状態です。次で作ります。

Step 3: キーストア作成 → オープン → マスター鍵設定

ここがTDEの心臓部です。3つのコマンドを1つずつ実行し、そのたびにウォレットの状態(v$encryption_wallet)を確認して、CLOSED → OPEN_NO_MASTER_KEY → OPEN と段階的に変わるのを実際に観察します。

① ソフトウェアキーストア(ewallet.p12)を作成

SQL> ADMINISTER KEY MANAGEMENT CREATE KEYSTORE IDENTIFIED BY "********";
SQL> SELECT wrl_type, status, wallet_type FROM v$encryption_wallet;

WRL_TYPE   STATUS    WALLET_TYPE
---------- --------- -----------
FILE       CLOSED    UNKNOWN

キーストアの実体(ewallet.p12)はできましたが、まだ開いていないので CLOSED。鍵をまだ何も入れていないため WALLET_TYPEUNKNOWN です。

② パスワードでオープン

SQL> ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY "********";
SQL> SELECT wrl_type, status, wallet_type FROM v$encryption_wallet;

WRL_TYPE   STATUS               WALLET_TYPE
---------- -------------------- -----------
FILE       OPEN_NO_MASTER_KEY   PASSWORD

開きましたが、まだマスター鍵を入れていないので OPEN_NO_MASTER_KEY。この状態ではまだ暗号化はできません。

③ マスター暗号鍵を設定(鍵バックアップ付き)

SQL> ADMINISTER KEY MANAGEMENT SET KEY IDENTIFIED BY "********" WITH BACKUP;
SQL> SELECT wrl_type, status, wallet_type FROM v$encryption_wallet;
SQL> SELECT con_id, key_id, creator FROM v$encryption_keys;

WRL_TYPE   STATUS    WALLET_TYPE
---------- --------- -----------
FILE       OPEN      PASSWORD

   CON_ID KEY_ID                                                 CREATOR
---------- ------------------------------------------------------ -------
        0 AQmeYE7HE09Av3gCXb5GALI...                              SYS

マスター鍵が入って STATUS=OPENWALLET_TYPE=PASSWORD に。v$encryption_keys にもマスター鍵が1件(CREATOR=SYS)。ウォレットが開き、鍵が使える状態になりました。

状態遷移のポイント: OPEN_NO_MASTER_KEY は「鍵を一度も設定していない、まっさらなキーストア」でしか現れません。一度マスター鍵を設定すると、以降は CLOSE→再OPEN してもいきなり OPEN に戻ります(②の状態は再現されません)。

このとき、ディスク上にウォレットの実体ファイルが作られ、サイズも変化します。

$ ls -l /u01/app/oracle/admin/orcl19u/wallet/tde/
-rw-------. 1 oracle oinstall 3993 ... ewallet.p12
-rw-------. 1 oracle oinstall 2553 ... ewallet_<timestamp>.p12
  • ewallet.p12 … 稼働用キーストア。マスター鍵を格納したことで 2553 → 3993 バイトに肥大しました。このファイルがバックアップすべき本体です(第3回で扱います)。
  • ewallet_<timestamp>.p12WITH BACKUP が自動生成した、鍵設定の控え。

WITH BACKUP の意味: マスター鍵を設定・変更する操作は、直前のウォレットを自動でバックアップしてから実行されます。鍵運用で「都度バックアップ」が基本になる理由がここに表れています。


【after】暗号化後は、ディスクから抜けない

いよいよ本題です。暗号化表領域 enc_ts を作り、plain_tsまったく同じ手法grep してみます。

SQL> CREATE TABLESPACE enc_ts DATAFILE '/u01/app/oracle/oradata/ORCL19U/enc_ts01.dbf' SIZE 50M
  2    ENCRYPTION USING 'AES256' ENCRYPT;
SQL> CREATE TABLE hr_secret_enc (id NUMBER, name VARCHAR2(40), card VARCHAR2(30)) TABLESPACE enc_ts;
SQL> INSERT INTO hr_secret_enc VALUES (1,'ENCRYPTED-SAFE-0614','4222-2222-2222-2222');
SQL> COMMIT;
SQL> ALTER SYSTEM CHECKPOINT;   -- before同様、ディスクへ確実に書き出してから覗く
SQL> SELECT tablespace_name, encrypted FROM dba_tablespaces WHERE tablespace_name IN ('PLAIN_TS','ENC_TS');
SQL> SELECT ts#, encryptionalg, encryptedts FROM v$encrypted_tablespaces;

TABLESPACE_NAME                ENC
------------------------------ ---
ENC_TS                         YES
PLAIN_TS                       NO

       TS# ENCRYPT ENC
---------- ------- ---
         8 AES256  YES

enc_tsENCRYPTED=YESAES256 になりました。ではディスクを覗きます。

$ strings /u01/app/oracle/oradata/ORCL19U/enc_ts01.dbf | grep -E 'ENCRYPTED-SAFE|4222-2222'   # beforeとまったく同じ手法
(何も表示されない=ヒットゼロ)
$ strings /u01/app/oracle/oradata/ORCL19U/plain_ts01.dbf | grep -E 'PLAINTEXT-LEAK|4111-1111'   # 対比:平文表領域はまだ見える
PLAINTEXT-LEAK-0614
4111-1111-1111-1111

同じ strings | grep でも、暗号化表領域からは何も出てきません。 一方、暗号化していない plain_ts は相変わらず丸見えです。

before / after の対比

表領域暗号化ディスクへの grep
plain_ts(平文)NO氏名・カード番号がヒット(漏洩)
enc_ts(AES256)YESヒットなし(暗号文のみ)

同一手法で結果が割れる——これが「TDE表領域暗号化は、ディスク窃取(脅威A)を確かに防ぐ」という一次証拠です。


まとめ

本記事で実証したこと:

  • 暗号化前:データファイルを strings | grep するだけで、氏名もカード番号も平文で読めた(脅威A=物理窃取が成立)
  • 基本構築:WALLET_ROOT(静的・要再起動)→ TDE_CONFIGURATION(動的)→ キーストア作成・オープン・マスター鍵設定、の3段でTDE基盤を構築
  • 暗号化後:同じ手法で暗号化表領域からは何も抜けない。plain_ts との対比で効果がくっきり

ここまでで「ディスクを盗まれても読めない」は達成できました。

ただし、TDEを過信するのは危険です。「ユーザーの表を暗号化したのに、別の場所から平文が漏れる」道が残っています。UNDO・TEMP・統計情報(SYSTEM)・AWRのSQLテキスト(SYSAUX)。次回(第2回)は、この「暗号化済みなのに情報漏洩する」を実機で再現し、TDEが守れる範囲と守れない範囲を整理します。

第2回:守れる範囲・守れない範囲:ユーザー表領域が暗号化済みなのに平文が残る場所はどこか


参考・脚注

  • (注1) AES-128 は現時点で破られておらず、実務上は安全とされる。128bit鍵の総当たりは現実的に不可能。
  • (注2) NSA Suite B Cryptography(CNSSP-15)。当初は「AES-128=SECRETまで/AES-256=TOP SECRET」と規定し、2015年8月にTOP SECRET強度(AES-256)への一本化を表明。出典: NSA Suite B Cryptography – Wikipedia
  • (注3) AES-256 は AES-128 よりラウンド数が多く(14 対 10)、暗号処理単体では約1割遅い。ただし AES-NI(CPUの暗号支援命令)により絶対速度は GB/s 級で、AES-NI 環境のベンチマークでは両者の差は単桁〜約1割程度(例:AES-256 ≈ 8.6 GB/s、AES-128 ≈ 9.7 GB/s)。