Firebird 3.0を実行するデータベース暗号化

現代の情報世界では、情報は人間の生活、社会、国家において重要な役割を果たしています。 蓄積および処理されたデータのサイズの増加は、それらのストレージおよび機密性の確保について疑問を提起します。 そのような問題を解決するための技術的な解決策と提案はすでにたくさんあります。 もちろん、保存されたデータの暗号化をサポートするデータベース管理システム(DBMS)もあります。 これは、これらのソリューションの1つです。







2016年4月、 Firebird DBMSの新しいバージョンが3番でリリースされました。とりわけ、保存および送信されたデータを保護するための多くのメカニズムが登場しました。 データ伝送チャネルの保護、ユーザー管理があり、データベース自体の暗号化もあります。これは、データページのレベルで透過的な暗号化として実装されます。 これはすべて、Firebird用の特別な拡張機能を作成することで実現されます。 もちろん、自分でそれを理解してこれらの拡張機能を書くこともできますが、 既存の拡張機能を使用してはいけません さらに、少なくとも、暗号化を理解し、暗号化パッケージの知識を備え、新しいC ++ Firebird APIに対処する必要があります。



Windows x64プラットフォーム用のこのリンクをダウンロードすることにより、既存の既製のソリューションを使用できます。 無料試用版では、使用される暗号化アルゴリズムに制限されます-Triple DES(3DES)がサポートされています。 ただし、データベースを保護するにはこれで十分です。 このパッケージには、インターフェースの説明を含む4つのライブラリとファイルが含まれています。

ファイル名 説明
CiKeyHolder.dll Firebird拡張-秘密キーパー
CiDbCrypt.dll Firebird拡張-データ暗号化
CiFbEnc_x86.dll 32ビット暗号化キーアクティベーションモジュール。
CiFbEnc_x86-64.dll 64ビットプラットフォーム用の暗号化キーアクティベーションモジュール。
ICiFbEncActivator.h C ++のモジュールインターフェイスの説明
CI.ICiFbEncActivator.pas Delphiのモジュールインターフェイスの説明
例として、特定のディレクトリ(条件付きで機密データを含む)を使用するアプリケーションを作成できます。これは、更新時にグローバルネットワークのリンクを介して利用できます。 誰でもダウンロードできますが、同時に解読できるのはアプリケーションだけです。



キーが取得され、データベースファイルが更新されることを保証する必要がある、このようなタスクの実装の不必要な詳細で記事を乱雑にしないために、キーがプログラム内の配列変数として、データベースファイル自体を使用して暗号化されると想定します。



プラットフォームとしてWindows 10 x64を使用し、タスクを実装するためのツールとしてIDE Embarcadero RAD Studio(現在10.2 Tokyoは30日間の試用版として入手可能)を使用します。アプリケーションソリューションの開発用(試用版はリンクからダウンロードできます)およびFirebird 3.0.2 x64は 、プラットフォームのリンクhttps://www.firebirdsql.org/en/firebird-3-0-2からダウンロードできます。 開発モードで常に実行されているサーバーを必要とせず、数回再起動する必要がある場合があるため、インストール中にサーバーをアプリケーションとして起動する方法を選択します。



Firebirdをインストールする






古いmasterkey



SYSDBA



のパスワードを実行し、インストール後にサーバーを起動するためのボックスをオフにします-まだ必要ありません。



Firebirdパッケージをインストールしたら、構成する必要があります。 Firebirdを埋め込みモードで使用する場合、使用するライブラリクライアントfbclient.dllが配置されるディレクトリで同じ設定を行う必要があります。 基本設定ファイルは、インストールされているFirebirdのルートディレクトリ- %ProgramW6432%\Firebird\Firebird_3_0



ます。



databases.confファイルにデータベースエイリアス(エイリアス)を登録し、将来のデータベースへのフルパスを示す行を追加します。



 TESTDB = C:\TESTAPP\DB\TESTDB.FDB
      
      





Firebirdがキーを探す場所を知るには、 KeyHolderPlugin



パラメーターを定義する必要があります。 上記のエイリアス専用に指定するか、firebird.confファイルで指定できます。 firebird.confファイルの構成パラメーターを追加または変更して、プラグインを秘密鍵の管理者として定義します。



 KeyHolderPlugin = CiKeyHolder
      
      





プラグインを探す場所Firebirdは構成ファイルからも学習します。 次の行を追加して、plugins.confファイルを変更します。



 Plugin = CiKeyHolder { #      Module = $(dir_plugins)/CiKeyHolder } Plugin = CiDbCrypt { #      Module = $(dir_plugins)/CiDbCrypt }
      
      





エイリアス$(dir_plugins)の下のディレクトリは、Firebirdルートディレクトリ内のプラグインディレクトリを参照します。 以前にダウンロードしたプラグインCiKeyHolder.dllおよびCiDbCrypt.dllをそこにコピーします。



すでにデータベースガイドがあることを前提としているため、Firebirdパッケージを使用して、つまりisqlアプリケーションを使用して作成します。 Win + R



をクリックして、次のコマンドを実行します。



 %ProgramW6432%\Firebird\Firebird_3_0\isql -q -user SYSDBA -password masterkey
      
      





または、何らかの方法で、たとえばFarプログラムを使用してisqlを異なる方法で起動します。



以下のコマンドは、設定でエイリアスが以前に指定されたTESTDBデータベースを作成し、作成されたデータベースに関する情報を表示します。



 SQL> create database 'TESTDB'; SQL> create table t_1 (i1 int, s1 varchar(15), s2 varchar(15)); SQL> insert into t_1 values (1,'value 1-1','value 1-2'); SQL> insert into t_1 values (2,'value 2-1','value 2-2'); SQL> commit; SQL> select * from t_1; I1 S1 S2 ============ =============== =============== 1 value 1-1 value 1-2 2 value 2-1 value 2-2 SQL> show db; Database: TESTDB Owner: SYSDBA PAGE_SIZE 8192 Number of DB pages allocated = 196 Number of DB pages used = 184 Number of DB pages free = 12 Sweep interval = 20000 Forced Writes are ON Transaction - oldest = 4 Transaction - oldest active = 5 Transaction - oldest snapshot = 5 Transaction - Next = 9 ODS = 12.0 Database not encrypted Default Character set: NONE SQL> quit;
      
      





show db;



コマンドで受信した情報からわかるようにshow db;



、作成されたデータベースは現在暗号化されていません- Database not encrypted







これですべてが設定され、アプリケーションの作成を開始できます。



Embarcadero RAD Studio IDEで新しいVCLフォームアプリケーションプロジェクトを作成しています。 たとえば、プロジェクトをディレクトリC:\ TESTAPPにtestappとして保存します。



まず、アプリケーションをデータベースに関連付けるだけで、データベースへの接続と切断を提供できます。 テストデータベースには1つのテーブルがあり、接続時にデータを表示できます。 視覚的なデザインから、ボタン、テーブル、データ管理機能付きのナビゲーターがあれば十分です。 Firebirdデータベースにアクセスするには、FireDACコンポーネントを使用します。 以下は、コンポーネントとそのカスタマイズ可能なパラメーターを含む表です。

テストアプリケーションフォームに配置されたコンポーネント
コンポーネントクラス コンポーネント名 パラメータ パラメータ値
TFDPhysFBDriverLink FDPhysFBDriverLink1 - -
TFDConnection Fdconnection1 ドライバー名 Fb
LoginPrompt
パラメータ\データベース testdb
Params \ UserName シスバ
パラメータ\パスワード マスターキー
パラメータ\プロトコル ipTCPIP
パラメータ\サーバー ローカルホスト
TFDGUIxWaitCursor FDGUIxWaitCursor1 - -
TFDTransaction FDTransaction1 - -
TFDTable FDTable1 テーブル名 T_1
TDataSource DataSource1 データセット FDTable1
TDBGrid DBGrid1 データソース DataSource1
TDBNavigator DBNavigator1 データソース DataSource1
TButton Button1 キャプション つなぐ
TButton Button2 キャプション 切断する
その結果、フォームは次のようになります。



開発環境のデザイナーのフォーム






[接続]ボタンをクリックする処理を記述しましょう。



 FDConnection1->Connected = true; FDTable1->Active = true;
      
      





「切断」の場合:



 FDTable1->Active = false; FDConnection1->Connected = false;
      
      





Delphiを使用する場合、すべてが類似しています:



 FDConnection1.Connected := True; FDTable1.Active := True; . . . FDConnection1.Connected := False; FDTable1.Active := False;
      
      





データベースに接続する前に、サーバーを起動する必要があります。 これを行うには、adminコマンドラインを呼び出します。



Win + X → ()







そして、コマンドを実行します:



“%ProgramW6432%\Firebird\Firebird_3_0\firebird” –a







実行中のサーバーのアイコンがトレイに表示されます。 このアイコンで呼び出されたコンテキストメニューから、作業を終了したり、実行中のサーバーのプロパティを表示したりできます。



これで、アプリケーションをビルドして実行し、データベースへの接続を確認できます。 データベースに接続すると、データがテーブルに表示されます。



データベースへの正常な接続






キーアクティベーションおよび暗号化管理モジュールをアプリケーションに接続します。 これを行うには、ファイルCiFbEnc_x86.dllおよびICiFbEncActivator.h、CI.ICiFbEncActivator.pasをディレクトリC:\ TESTAPPにコピーします。 デフォルトでは32ビットWindows用のプロジェクトが開発環境で作成され、開発環境の試用版ではターゲットプラットフォームを変更できないため、アプリケーションにはCiFbEnc_x86.dllファイルモジュールが必要です。



ヘッダーファイルとアクティベーションモジュールインターフェイスの説明をアプリケーションファイルに接続します。



 #include "ICiFbEncActivator.h"
      
      





または、Delphiの場合はCi.ICiFbEncActivator.pasファイル。



 uses . . . , CI.ICiFbEncActivator;
      
      





「暗号化」、「復号化」、「状態の取得」の3つのボタンをフォームに追加します。



モジュール操作を開始するための追加ボタン






最初に、「状態の取得」ボタンハンドラを検討します。 名前に由来するものは、データベースの現在の状態を取得する機会を与えてくれます。



最も重要なことは、アクティベーションモジュールのインターフェイスにアクセスすることです。 オペレーションごとに受信することも、グローバルに、または特定のオブジェクトに集約して受信することもできます。 ラッパークラスを圧倒しないために、各操作に対してアクティベーションモジュールオブジェクトを取得することを想定します。 以下は、これを行う1つの可能な方法です。



 // C++ Builder //   std::unique_ptr<HINSTANCE__, decltype(&::FreeLibrary)> mHandle( ::LoadLibraryEx(L"C:\\TESTAPP\\CiFbEnc_x86.dll",0,LOAD_WITH_ALTERED_SEARCH_PATH), &::FreeLibrary); if (!mHandle) { MessageBox( NULL, L" CiFbEnc_x86.dll        fbclient.dll", L" ", MB_OK|MB_ICONERROR); return; } //   typedef CALL_CONV int(__stdcall *CREATEFUNCPTR)(CI::ICiFbEncActivator**); CREATEFUNCPTR GetActivator = (CREATEFUNCPTR)::GetProcAddress(mHandle.get(), "createCiFBEncActivator"); if (!GetActivator) { MessageBox( NULL, L"     CiFbEnc_x86.dll " "createCiFBEncActivator" " -  ,   tdump.", L" ", MB_OK|MB_ICONERROR); return; } CI::ICiFbEncActivator* pActivator = NULL; GetActivator(&pActivator); if (!pActivator) { ShowMessage("ERROR GetActivator!"); return; } // . . . // //      // // . . . //    pActivator->Destroy(); pActivator = NULL;
      
      





 // Delphi var pActivator : ICiFbEncActivator; res : Integer; CreateActivator: TActivatorFunction; mHandle : HINST; . . . begin //   mHandle := LoadLibraryEx( PChar('C:\TESTAPP\CiFbEnc_x86.dll'), 0, LOAD_WITH_ALTERED_SEARCH_PATH); if mHandle = 0 then begin MessageBox( Application.Handle, ' CiFbEnc_x86.dll        fbclient.dll', ' ', MB_OK OR MB_ICONERROR); Exit; end; //   CreateActivator := GetProcAddress(mHandle, 'createCiFBEncActivator'); if not Assigned(CreateActivator) then begin MessageBox( Application.Handle, '     CiFbEnc_x86.dll  createCiFBEncActivator' + ' -  ,   tdump.', ' ', MB_OK OR MB_ICONERROR); Exit; end; pActivator := nil; res := CreateActivator(pActivator); if not Assigned(pActivator) then begin ShowMessage('ERROR CreateActivator!'); Exit; end; // . . . // //      // // . . . //    pActivator.Destroy; pActivator := nil; FreeLibrary(mHandle); end;
      
      





さらに、ボタンをクリックするための各ハンドラーに対して、上記のコードが追加されると想定します。



これで、データベースの状態を取得できます。



 // C++ Builder . . . //      pActivator->SetDBAccess("localhost:TESTDB", "SYSDBA", "masterkey"); // ,       Firebird char stat_buf[1024] = { 0 }; size_t bufsize = sizeof(stat_buf); int res = pActivator->GetStateSVC(stat_buf, bufsize); String sStatMsg = (String)stat_buf; if (Err_OK == res) { MessageBox(NULL, sStatMsg.c_str(), L" ", MB_OK|MB_ICONINFORMATION); } else { String sErrMsg = L"ERROR GetStateSVC: " + sStatMsg; MessageBox( NULL, sErrMsg.c_str(), L" ", MB_OK|MB_ICONERROR); } . . .
      
      





 // Delphi var . . . stat_buf : array[0..1023] of AnsiChar; bufsize : NativeUInt; . . . //      res := pActivator.SetDBAccess('localhost:TESTDB', 'SYSDBA', 'masterkey'); // ,       Firebird bufsize := SizeOf(stat_buf); ZeroMemory(@stat_buf, bufsize); res := pActivator.GetStateSVC(stat_buf, bufsize); if Err_OK = res then begin MessageBox(Application.Handle, PChar(String(stat_buf)), ' ', MB_OK OR MB_ICONINFORMATION); end else begin MessageBox(Application.Handle, PChar(String(stat_buf)), '', MB_OK OR MB_ICONERROR); end; . . .
      
      





データベースに接続して情報を取得できた場合、現在の状態に関する詳細情報を含むメッセージが表示されます。



現在のデータベースステテの取得に成功しました






ご覧のとおり、データベースはまだ暗号化されていません。 それを修正する時が来ました。 ただし、暗号化にはキーが必要です。 そして、例のフレームワークでグローバル定数として定義します。



 // C++ Builder //  -     192  const uint8_t key[24] = { 0x06,0xDE,0x81,0xA1,0x30,0x55,0x1A,0xC9, 0x9C,0xA3,0x42,0xA9,0xB6,0x0F,0x54,0xF0, 0xB6,0xF9,0x70,0x18,0x85,0x04,0x83,0xBF };
      
      





 // Delphi const key : array [0..23] of Byte = ( $06,$DE,$81,$A1,$30,$55,$1A,$C9, $9C,$A3,$42,$A9,$B6,$0F,$54,$F0, $B6,$F9,$70,$18,$85,$04,$83,$BF );
      
      





データベースの現在の状態を取得することに加えて、暗号化、復号化、暗号化されたデータへのアクセスなどの他のすべての操作には、秘密鍵のアクティベーションが必要です。 これを行うには、アクティベーションモジュールオブジェクトを受け取った後に次のコードを追加します。



 // C++ Builder . . . //      pActivator->SetDBAccess("localhost:TESTDB", "SYSDBA", "masterkey"); //    int res = pActivator->SetKey(&key, sizeof(key)); if (Err_OK != res) { ShowMessage("ERROR SetKey!"); pActivator->Destroy(); return; } //     res = pActivator->Activate(); if (Err_OK != res) { //   char errmsg[512] = {0}; size_t esize = sizeof(errmsg); pActivator->GetFBStat(errmsg, esize); String sErrMsg = "ERROR Activate: " + String(errmsg); MessageBox( NULL, sErrMsg.w_str(), L"   ", MB_OK|MB_ICONERROR); pActivator->Destroy(); return; } . . .
      
      





 // Delphi . . . //      res := pActivator.SetDBAccess('localhost:TESTDB', 'SYSDBA', 'masterkey'); //    res := pActivator.SetKey(@key, Length(key)); if Err_OK <> res then begin ShowMessage('ERROR SetKey!'); pActivator.Destroy; Exit; end; //     res := pActivator.Activate; if Err_OK <> res then begin bufsize := SizeOf(errmsg); ZeroMemory(@errmsg, bufsize); pActivator.GetFBStat(errmsg, bufsize); MessageBox( Application.Handle, PChar('ERROR Activate: ' + String(errmsg)), '   ', MB_OK OR MB_ICONERROR); pActivator.Destroy; Exit; end; . . .
      
      





ご覧のとおり、キーはアクティベーターに転送され、アクティベーション関数が呼び出されます。 この場合、モジュールは、キーキーパーの拡張機能を使用してキーにアクセスするためのコールバック関数を登録します。 また、Firebirdの動作モードに依存しません。 また、キー送信のセキュリティは、セッションキーの暗号化によって保証されます。 上記のコードでは、アクティベーション関数を呼び出した後、Firebirdライブラリレベルで発生する可能性のあるエラーの処理例を示しています。 同様に、Firebird機能にアクセスできる操作の完了したタスクの現在のステータスを読み取ることができます。



これで、「暗号化」ボタンと「復号化」ボタンのハンドラーを作成できます。 完了したタスクのステータスとキーの予備アクティベーションのチェックを省略する場合、同じ機能のアクティベーションオブジェクトへの呼び出しを追加するだけです。



 // C++ Builder //  res = pActivator->Encrypt(); . . . //  res = pActivator->Decrypt();
      
      





 // Delphi //  res := pActivator.Encrypt; . . . //  res := pActivator.Decrypt;
      
      





その結果、1回の呼び出しを除き、同一のハンドラーを取得します。



これで、データベースを暗号化できます。 彼女のステータスを呼び出すと、彼女はすでに暗号化されていることがわかります。



暗号化されたデータベースの状態






その後、「接続」ボタンのハンドラを変更せずにデータベースに接続しようとすると、エラーが発生します。



キーをアクテイブ化せずに暗号化されたデータベースに接続しようとする






最後のステップは、データベース接続ボタンのハンドラーを変更することです。 そこで、モジュールインターフェイスオブジェクトの受信とアクティベーションキー呼び出しを追加する必要があります。 以下は、暗号化されたデータベースへの接続を処理するための完全なコードです。



C ++ Builderの場合
 // C++ Builder void __fastcall TForm1::Button1Click(TObject *Sender) { //   std::unique_ptr<HINSTANCE__, decltype(&::FreeLibrary)> mHandle( ::LoadLibraryEx(L"C:\\TESTAPP\\CiFbEnc_x86.dll", 0, LOAD_WITH_ALTERED_SEARCH_PATH), &::FreeLibrary); if (!mHandle) { MessageBox( NULL, L" CiFbEnc_x86.dll        fbclient.dll", L" ", MB_OK|MB_ICONERROR); return; } //   typedef CALL_CONV int(__stdcall *CREATEFUNCPTR)(CI::ICiFbEncActivator**); CREATEFUNCPTR GetActivator = (CREATEFUNCPTR)::GetProcAddress(mHandle.get(), "createCiFBEncActivator"); if (!GetActivator) { MessageBox( NULL, L"     CiFbEnc_x86.dll" "  createCiFBEncActivator" " -  ,   tdump.", L" ", MB_OK|MB_ICONERROR); return; } CI::ICiFbEncActivator* pActivator = NULL; GetActivator(&pActivator); if (!pActivator) { ShowMessage("ERROR GetActivator!"); return; } //      pActivator->SetDBAccess("localhost:TESTDB", "SYSDBA", "masterkey"); //    int res = pActivator->SetKey(&key, sizeof(key)); if (Err_OK != res) { ShowMessage("ERROR SetKey!"); pActivator->Destroy();return; } //     res = pActivator->Activate(); if (Err_OK != res) { //   char errmsg[512] = {0}; size_t esize = sizeof(errmsg); pActivator->GetFBStat(errmsg, esize); String sErrMsg = "ERROR Activate: " + String(errmsg); MessageBox( NULL, sErrMsg.w_str(), L"   ", MB_OK|MB_ICONERROR); pActivator->Destroy(); return; } //    try { FDConnection1->Connected = true; FDTable1->Active = true; } catch(EFDDBEngineException &e) { String sErrMsg = L"    . " + e.Message; MessageBox( NULL, sErrMsg.w_str(), L"  ", MB_OK|MB_ICONERROR); } //    pActivator->Destroy(); pActivator = NULL; }
      
      







Delphiの場合
 // Delphi procedure TForm2.Button1Click(Sender: TObject); var pActivator : ICiFbEncActivator; res : Integer; CreateActivator: TActivatorFunction; mHandle : HINST; errmsg : array[0..511] of AnsiChar; bufsize : NativeUInt; begin //   mHandle := LoadLibraryEx(PChar('C:\TESTAPP\CiFbEnc_x86.dll'), 0, LOAD_WITH_ALTERED_SEARCH_PATH); if mHandle = 0 then begin MessageBox( Application.Handle, ' CiFbEnc_x86.dll        fbclient.dll', ' ', MB_OK OR MB_ICONERROR); Exit; end; //   CreateActivator := GetProcAddress(mHandle, 'createCiFBEncActivator'); if not Assigned(CreateActivator) then begin MessageBox( Application.Handle, '     CiFbEnc_x86.dll  createCiFBEncActivator' + ' -  ,   tdump.', ' ', MB_OK OR MB_ICONERROR); Exit; end; pActivator := nil; res := CreateActivator(pActivator); if not Assigned(pActivator) then begin ShowMessage('ERROR CreateActivator!');Exit; end; //      res := pActivator.SetDBAccess('localhost:TESTDB', 'SYSDBA', 'masterkey'); //    res := pActivator.SetKey(@key, Length(key)); if Err_OK <> res then begin ShowMessage('ERROR SetKey!'); pActivator.Destroy;Exit; end; //     res := pActivator.Activate; if Err_OK <> res then begin bufsize := SizeOf(errmsg); ZeroMemory(@errmsg, bufsize); pActivator.GetFBStat(errmsg, bufsize); MessageBox( Application.Handle, PChar('ERROR Activate: ' + String(errmsg)), '   ', MB_OK OR MB_ICONERROR); pActivator.Destroy; Exit; end; //    try FDConnection1.Connected := True; FDTable1.Active := True; except on E: EFDDBEngineException do begin MessageBox( Application.Handle, PChar('    . ' + String(E.Message)), '  ', MB_OK OR MB_ICONERROR); end; end; //    pActivator.Destroy; pActivator := nil; FreeLibrary(mHandle); end;
      
      







したがって、暗号化されたデータベースを操作するのは非常に簡単です。



完全なプロジェクトはここで取得できます



デモパッケージはこちらです。



All Articles