本ページでは、SQL/Protect プラグインを使用して、SQL インジェクション攻撃からデータベースを保護する方法について説明します。

このタスクについて

開発者は、SQL インジェクション攻撃からデータベースを保護する責任があります。 SQL/Protect を使用して、クエリ要求を調べ、SQL インジェクションをチェックすることができます。 疑わしいクエリ要求が特定されると、SQL/Protect は、クエリの実行をブロックし、即座にデータベース管理者に警告メッセージを発行します。

SQL インジェクション攻撃の種類

攻撃タイプ SQL/Protect でできること
不正なリレーション 管理者はリレーション (たとえば、テーブルやビューなど) へのアクセスを制限できますが、一部の管理者はこの面倒なタスクを実行しません。 SQL/Protect は、ユーザーがアクセスする関係を動的に追跡する学習モードを提供します。 これにより、管理者はアプリケーションのワークロードを調べることができ、SQL/Protect は、ロール内の特定のユーザーまたはユーザーグループがアプリケーションにアクセスできる関係を知ることができます。 SQL/Protect がパッシブモードまたはアクティブモードに切り替えられると、受信したクエリが学習された関係のリストと照合されます。
ユーティリティコマンド SQL インジェクション攻撃で使用される一般的な手法は、ユーティリティコマンドを実行することです。これは通常、SQL データ定義言語 (DDL) 文です。 例として、他のシステムリソースにアクセスする機能を持つユーザー定義関数の作成があります。 SQL/Protect は、すべてのユーティリティコマンドの実行をブロックすることができます。これらのコマンドは、標準のアプリケーション処理では通常必要ありません。
SQL 同語反復 SQL インジェクション攻撃で最も頻繁に使用される手法は、同語反復の WHERE 句条件を発行することです (つまり、常に true である条件を使用します)。 次に例を示します。 WHERE password = 'x' OR 'x'='x'。 攻撃者は通常、この手法を使用してセキュリティの弱点を特定し始めます。 SQL/Protect は、同語反復条件句を使用するクエリをブロックすることができます。
無制限の DML 文 SQL インジェクション攻撃中に行われる危険なアクションは、無制限の DML 文の実行です。 これらは、WHERE 句のない UPDATE および DELETE 文です。 たとえば、攻撃者はすべてのユーザーのパスワードを既知の値に更新したり、キーテーブルのすべてのデータを削除してサービス拒否 (DoS) 攻撃を開始したりする可能性があります。

保護されたロール

保護されたロールは、データベース管理者が SQL/Protect を使用してモニターすることを選択したユーザーまたはグループです。 保護されている各ロールは、モニター対象の SQL インジェクション攻撃の種類に合わせてカスタマイズできるため、ロールごとに異なるレベルの保護を提供することができます。

スーパーユーザー権限を持つロールを保護ロールにすることはできません。 その後、保護された非スーパーユーザーのロールがスーパーユーザーにに変更された場合は、そのスーパーユーザーがコマンドを発行しようとするたびに、特定の動作が示されます。
  • 保護されたスーパーユーザーによって発行されたすべてのコマンドに対して、SQL/Protect によって警告メッセージが発行されます。
  • SQL/Protect がアクティブモードの場合、保護されたスーパーユーザーが発行したすべてのコマンドは実行できなくなります。

スーパーユーザー権限を持つ保護されたロールは、スーパーユーザーでなくなるように変更するか、保護されていないロールに戻す必要があります。

さらに、保護されたロールによって発行されたすべてのコマンドは、統計ビューに段階的に記録されます。 このビューは、ロールに対する潜在的な SQL インジェクション攻撃の開始を識別するのに役立ちます。 統計は、SQL インジェクション攻撃のタイプごとに収集されます。

デフォルトでは、各データベースは最大 64 の保護されたロールと最大 1024 の保護されたテーブルをサポートします。 保護できるロールの最大数は max_protected_roles パラメーターで指定され、保護できるテーブルの最大数は max_protected_relations パラメーターで指定されます。

データベースをモニターする管理者としての SQL/Protect の設定

  1. 以下のパラメーターを編集して、SQL/Protect を開始します。
    edb_sql_protect.enabled = on # (This parameter is set to off by default.)
    edb_sql_protect.level = passive # (SQL/Protect has three modes: learn, active, and passive. The default mode is passive.)
  2. 次の文を実行して、targetdb という名前のテストデータベースと test という名前のテストユーザーを作成します。
    CREATE DATABASE targetdb;
    CREATE ROLE test;
    GRANT ALL ON DATABASE targetdb TO test;
    ALTER ROLE test LOGIN;
  3. テストデータベース targetdb にログインします。 次の文を実行して SQL/Protect を作成し、保護されたロールを追加します。
    CREATE EXTENSION sqlprotect;
    SELECT sqlprotect.protect_role('test');
    次の文を実行して、保護されたロールのリストを表示します。
    SELECT * FROM sqlprotect.list_protected_users;
    SELECT * FROM sqlprotect.edb_sql_protect;
  4. 必要に応じて、SQL/Protect の操作モードを変更します。

    SQL/Protect は、学習 (learn)、アクティブ (active)、パッシブ (passive) の 3 つのモードで動作します。 デフォルトモードでは、パッシブ (passive) が設定されています。 詳細については、「SQL/Protect 操作モードの設定」をご参照ください。

    • SQL/Protect を学習 (learn) モードに切り替えます。
      edb_sql_protect.level = learn; #
      1. テストユーザーとして targetdb データベースにログインします。 次に、company という名前のテストテーブルを作成し、SELECT 文と INSERT 文を実行します。
        CREATE TABLE company(name VARCHAR(100), employee_num INT);
        SELECT * FROM company;
        INSERT INTO company VALUES('new', 1);
        SELECT * FROM company;
      2. 次の文を実行して、テーブルにアクセスするテストユーザーに関する統計を表示します。
        SELECT * FROM sqlprotect.edb_sql_protect_rel;
        SELECT * FROM sqlprotect.list_protected_rels;
    • SQL/Protect をパッシブ (passive) モードに切り替えます。
      edb_sql_protect.level = passive; #
      1. テストユーザーとして targetdb データベースにログインします。
      2. 次の文を実行して、SQL 文を挿入します。
        SELECT * FROM company WHERE 1 = 1;
        DELETE FROM company;
        SQL/Protect は、不正な SQL 文を示唆するメッセージを表示しますが、SQL 文の実行をブロックしません。
    • SQL/Protect をアクティブ (active) モードに切り替えます。
      edb_sql_protect.level = active; #
      1. テストユーザーとして targetdb データベースにログインします。
      2. 次の文を実行して、SQL 文を挿入します。
        SELECT * FROM company WHERE 1 = 1;
        DELETE FROM company;
        SQL/Protect は、不正な SQL 文を示唆するメッセージを表示し、SQL 文の実行をブロックします。

保護されたロールの設定

保護されたロールは、edb_sql_protect テーブルに格納されます。 データベース管理者は、保護するユーザーとユーザーグループを選択して、テーブルに追加することができます。

  • protect_role 関数を呼び出して、ユーザーをテーブルに追加します。
    SELECT sqlprotect.protect_role('userA');
  • 次の文を実行して、保護されたロールをテーブルに表示します。
    select * from sqlprotect.list_protected_users;
    select * from sqlprotect.edb_sql_protect;
  • unprotect_role 関数を呼び出して、保護されたロールを非保護に戻します。
    SELECT sqlprotect.unprotect_role('userA');

SQL/Protect 操作モードの設定

edb_sql_protect.level パラメーターは、SQL/Protect が保護されたロールをモニターするように操作するモードを指定します。 学習 (learn)、パッシブ (passive)、アクティブ (active) の 3 つのモードが使用可能です。 デフォルトモードでは、パッシブ (passive) が設定されています。
操作モード 説明
learn SQL/Protect は、ユーザーがアクセスする関係を追跡して、ロール内の特定のユーザーまたはユーザーグループがアプリケーションにアクセスを許可できる関係を学習します。
passive SQL/Protect は、実行されるすべての SQL 文をモニターします。 保護されたロールが無許可の SQL 文を実行しようとすると、SQL/Protect は警告メッセージを発行しますが、SQL 文の実行をブロックしません。
active SQL/Protect は、実行されるすべての SQL 文をモニターし、攻撃者が攻撃を仕掛け始めたときに、SQL ファイアウォールを使用して、保護されたロールからすべての不正な SQL 文の実行をブロックします。 さらに、SQL/Protect は不正な SQL 文を追跡し、管理者が攻撃者より先にデータベースの弱点を特定できるようにします。
たとえば、SQL/Protect をアクティブ (active) モードに切り替える場合は、次の文を実行します。
 edb_sql_protect.level = active; #

edb_sql_protect テーブルの特定のフィールドを編集して、ロールで保護する必要があるものを指定することができます。

targetdb=# \d sqlprotect.edb_sql_protect;
        Table "sqlprotect.edb_sql_protect"
      Column       |  Type   | Collation | Nullable | Default 
--------------------+---------+-----------+----------+--------- 
dbid               | oid     |           | not null |  
roleid             | oid     |           | not null |  
protect_relations  | boolean |           |          |  
allow_utility_cmds | boolean |           |          |  
allow_tautology    | boolean |           |          |  
allow_empty_dml    | boolean |           |          | 
Indexes: 
   "edb_sql_protect_pkey" PRIMARY KEY, btree (roleid)
たとえば、次の文を実行して、16480 という名前の保護されたロールの allow_utility_cmds パラメーターを TRUE に設定した場合、SQL/Protect は保護されたロール 16480 から発行されたユーティリティコマンドの実行をブロックします。
UPDATE sqlprotect.edb_sql_protect SET allow_utility_cmds = TRUE WHERE roleid = 16480; 

その他の関連業務

  • SQL/Protect を停止するには、次の文を実行します。
    edb_sql_protect.enabled = off
    edb_sql_protect.level = passive #
  • SQL/Protect によってブロックされた SQL 文の統計を表示するには、次の文を実行します。
    SELECT * FROM sqlprotect.edb_sql_protect_stats;
  • 指定されたユーザーの SQL/Protect によってブロックされた SQL 文の統計を削除するには、次の文を実行します。
    SELECT sqlprotect.drop_stats('username');