次の方法で共有


動的データ マスク

適用対象: SQL Server 2016 (13.x) 以降のバージョン Azure SQL DatabaseAzure SQL Managed Instance Azure Synapse Analytics Microsoft Fabric の SQL データベース

動的データ マスクの図。

動的データ マスク (DDM) は、特権のないユーザーに対してデータをマスクすることで、機密データの露出を制限します。 DDM を使用すると、アプリケーションのセキュリティの設計とコーディングを大幅に簡略化することができます。

この記事では、動的データ マスクの一般的な概念と、SQL Server に特有の内容について説明します。 他のプラットフォームに特化した情報については、以下を参照してください。

動的データ マスクの概要

動的データ マスクでは、公開する機密データの量を指定できるようにすることで、機密データに対する未承認のアクセスを防ぎ、アプリケーション レイヤーへの影響を最小限に抑えることができます。 DDM は、指定されたデータベース フィールドで、クエリの結果セットに含まれる機密データを隠蔽するように構成できます。 DDM によって、データベース内のデータが変更されることはありません。 DDM は、クエリの結果にマスク ルールが適用されるため、既存のアプリケーションで簡単に使用できます。 多くのアプリケーションは、既存のクエリを変更せずに、デリケートなデータをマスクすることができます。

  • 中央のデータ マスク ポリシーは、データベースの機密フィールドに対して直接動作します。
  • 機密データに対するアクセス権を持つ特権のあるユーザーまたはロールを指定します。
  • DDM には、フル マスク関数と部分マスク関数、および数値データ用のランダム マスクがあります。
  • 単純な Transact-SQL コマンドで、マスクを定義し、管理します。

動的データ マスクの目的は、アクセスすべきではないユーザーがデータを閲覧することを防ぎ、機密データの公開を制限することにあります。 動的データ マスクは、ユーザーが直接データベースに接続し、徹底的なクエリを実行して、機密データの漏えいを防ぐことを目的とはしていません。 動的データ マスクは、その他の SQL Server セキュリティ機能 (監査、暗号化、行レベルのセキュリティなど) を補完します。データベース内の機密データの保護をより強化するために、これを併用することをお勧めします。

動的データ マスクは SQL Server 2016 (13.x) と Azure SQL データベースで使用できます。 Transact-SQL をコマンドを使用して構成します。 Azure portal で動的データ マスクを構成する方法の詳細については、SQL Database 動的データ マスクの使用 (Azure ポータル)に関するページを参照してください。

Microsoft Entra ID は、従来、Azure Active Directory (Azure AD) と呼ばれていた製品です。

動的データ マスクを定義する

テーブル内の列に対してマスク ルールを定義することで、列のデータを難読化できます。 使用できるマスクは 5 種類あります。

Function 説明
Default 指定のフィールドのデータ型に応じたフル マスク。

文字列データ型 ( (or fewer) if the size of the field is fewer than 4 characters (charncharvarcharnvarchartextntext) の場合、フィールドのサイズが 4 文字未満であれば、XXXX 以下の数の X を使用します。
数値データ型 (bigintbitdecimalintmoneynumericsmallintsmallmoneytinyintfloatreal) の場合は値 0 を使用します。
• 日付/時刻データ型 (datedatetime2datetimedatetimeoffsetsmalldatetimetime) の場合は、1900-01-01 00:00:00.0000000 を使用します。
バイナリ データ型 (binaryvarbinaryimage) の場合は、ASCII 値 0 のシングル バイトを使用します。
列定義の構文例: Phone# varchar(12) MASKED WITH (FUNCTION = 'default()') NULL
ALTER 構文例: ALTER COLUMN Gender ADD MASKED WITH (FUNCTION = 'default()')
Email メール アドレスの最初の 1 文字と定数サフィックスの ".com" をメール アドレスのフォームで公開するマスク方法。 aXXX@XXXX.com 定義の構文例: Email varchar(100) MASKED WITH (FUNCTION = 'email()') NULL

ALTER 構文例: ALTER COLUMN Email ADD MASKED WITH (FUNCTION = 'email()')
ランダム ランダム マスク関数は任意の数字型に使用でき、指定した範囲内で生成したランダムな値でオリジナルの値をマスクします。 定義の構文例: Account_Number bigint MASKED WITH (FUNCTION = 'random([start range], [end range])')

ALTER 構文例: ALTER COLUMN [Month] ADD MASKED WITH (FUNCTION = 'random(1, 12)')
カスタム文字列 間にカスタム埋め込み文字列を追加し、最初と最後の文字を公開するマスク方法。 prefix,[padding],suffix

元の値が短すぎてマスク全体を適用できない場合、プレフィックスまたはサフィックスの一部は表示されません。
定義の構文例: FirstName varchar(100) MASKED WITH (FUNCTION = 'partial(prefix,[padding],suffix)') NULL
ALTER 構文例: ALTER COLUMN [Phone Number] ADD MASKED WITH (FUNCTION = 'partial(1,"XXXXXXX",0)')
これにより、555.123.1234 のような電話番号は、5XXXXXXX のように変換されます。
その他の例:
ALTER COLUMN [Phone Number] ADD MASKED WITH (FUNCTION = 'partial(5,"XXXXXXX",0)')
これにより、555.123.1234 のような電話番号は、555.1XXXXXXX のように変換されます。
Datetime 適用対象: SQL Server 2022 (16.x)

データ型が datetimedatetime2datetimedatetimeoffsetsmalldatetime に設定された列に対するマスキング方法。 これは、year => datetime("Y")month=> datetime("M")day=>datetime("D")hour=>datetime("h")minute=>datetime("m") または 1 日の seconds=>datetime("s") の部分をマスキングするのに役立ちます。
datetime 値 の年をマスクする方法の例:
ALTER COLUMN BirthDay ADD MASKED WITH (FUNCTION = 'datetime("Y")')
値の月をマスクする方法の例:
ALTER COLUMN BirthDay ADD MASKED WITH (FUNCTION = 'datetime("M")')
値の分数をマスクする方法の例:
ALTER COLUMN BirthDay ADD MASKED WITH (FUNCTION = 'datetime("m")')

アクセス許可

テーブルに対して SELECT アクセス許可を持つユーザーは、テーブル データを閲覧できます。 マスク済みとして定義されている列には、マスクされたデータが表示されます。 UNMASK アクセス許可を付与されたユーザーは、マスクが定義された列から、マスクを解除したデータを取得できます。

管理ユーザーおよび管理ロールは、CONTROL 権限 (ALTER ANY MASK 権限と UNMASK 権限の両方を含む) を使用することで、マスクされていないデータを常に表示できます。 管理ユーザーまたは管理ロール (sysadmin や db_owner など) は、設計上データベースにおける CONTROL アクセス許可を持っており、マスクされていないデータを表示できます。

動的データ マスクでテーブルを作成するのに特別なアクセス許可は要りません。スキーマ アクセス許可に対する標準的な CREATE TABLEALTER のみが必要です。

列のマスクを追加、置換、削除するには、 ALTER ANY MASK アクセス許可と、テーブルに対する ALTER アクセス許可が必要です。 セキュリティの責任者には、ALTER ANY MASK を付与するのが適切です。

UNMASK アクセス許可はメタデータの可視性に影響しません。UNMASK のみを付与しても、メタデータは公開されません。 UNMASK が作用するには、常に SELECT 権限が付随する必要があります。 例: データベース スコープで UNMASK を許可し、個々のテーブルで SELECT を許可すると、そのユーザーのみが選択できる個々のテーブルのメタデータのみが表示されるようになります。 「メタデータ表示の構成」も参照してください。

ベスト プラクティスと一般的なユース ケース

  • 列にマスクを作成しても、その列への更新は防止されません。 マスクされた列にクエリを実行すると、ユーザーはマスクされたデータを受け取りますが、書き込みアクセス許可があるユーザーは、データを更新できます。 更新する許可を制限するために、適切なアクセス制御ポリシーを使用する必要があります。

  • SELECT INTOINSERT INTO を使用してマスクされた列のデータを別のテーブルにコピーすると、対象のテーブルにはマスクされたデータが格納されます (UNMASK 権限を持たないユーザーがエクスポートする場合)。

  • SQL Server のインポートおよびエクスポートを実行する際に、動的データ マスクが適用されます。 マスクされた列を含むデータベースは、マスクされたデータを含むエクスポートされたデータ ファイルを生成し (UNMASK 特権がないユーザーがエクスポートしたことを前提とします)、インポートされたデータベースは、マスクされたデータを静的に格納します。

マスクされた列に対してクエリを実行する

sys.masked_columns ビューを使用して、マスク関数が適用されたテーブルの列に対してクエリを実行します。 このビューは、sys.columns を継承しています。 このビューは、sys.columns のすべての列に加えて、is_masked 列および masking_function 列を返し、列がマスクされているかどうか、マスクされている場合はどのマスク関数が定義されているかを示します。 このビューは、マスキング関数が適用されている列のみが表示されます。

SELECT c.name, tbl.name as table_name, c.is_masked, c.masking_function
FROM sys.masked_columns AS c
JOIN sys.tables AS tbl
    ON c.[object_id] = tbl.[object_id]
WHERE is_masked = 1;

制限事項と制約事項

データベース レベルでの CONTROL SERVER 権限または CONTROL 権限を持つユーザーは、マスクされたデータを元の形式で表示できます。 これには、管理者ユーザーや sysadmin、db_owner などのロールが含まれます。

次の列の型には、マスク ルールを定義することはできません。

  • 暗号化された列 (常に暗号化されます)

  • FILESTREAM

  • COLUMN_SET、または列セットの一部であるスパース列

  • 計算列にマスクを構成することはできませんが、その列が MASK が設定された列に依存している場合は、計算列にもマスクされたデータが返されます。

  • データ マスクのある列を FULLTEXT インデックスのキーにすることはできません。

  • PolyBase 外部テーブル内の列。

UNMASK アクセス許可のないユーザーの場合、非推奨の READTEXTUPDATETEXTWRITETEXT ステートメントは、動的データ マスク用に構成された列では適切に機能しません。

動的データ マスクの追加は、基になるテーブルに対するスキーマ変更として実行されるため、依存関係のある列 (計算列で参照されている列など) には適用できません。 依存関係のある列に対して動的データ マスクを追加しようとすると、次のエラーが発生します。”ALTER TABLE ALTER COLUMN _columnname_ failed because one or more objects access this column エラーが発生します。” この制限を回避するには、最初に依存関係を削除してから、動的データ マスクを追加した後、依存関係を再作成します。 たとえば、依存関係がその列に依存するインデックスによるものである場合は、インデックスを削除し、マスクを追加してから、依存するインデックスを再作成します。

マスク関数が定義されている列を参照する式を投影する場合は常に、その式にもマスクが適用されます。 参照される列をマスクするために使用される関数 (既定、電子メール、ランダム、カスタム文字列) に関係なく、結果として得られる式は常に既定の関数でマスクされます。

異なる 2 つの異なる Azure SQL データベースまたは異なる SQL Server インスタンスでホストされているデータベースにまたがる複数のデータベース間クエリでは、MASKED 列に対してどのような種類の比較または結合操作も行われますが、正しい結果は得られません。 リモート サーバーから返される結果は既に MASKED 形式であり、ローカルでのあらゆる比較や結合操作に適していません。

基になるベース テーブルがインデックス付きビューで参照されている場合、動的データ マスクはサポートされません。

セキュリティに関する注意: 推論またはブルートフォース手法を使用してマスクをバイパスする

動的データ マスクは、アプリケーションに使用される事前定義されたクエリ セットのデータ公開を制限することで、アプリケーション開発を単純化するために設計されています。 動的データ マスクは、実稼働データベースに直接アクセスするときに機密データが誤って公開されることを防ぐためにも有効ですが、アドホック クエリ アクセス許可を持つ特権のないユーザーが、実際のデータに対するアクセス権を得る手法を適用する可能性にも注意する必要があります。 このようなアドホック アクセス権を付与する必要がある場合、監査を使用して、すべてのデータベース操作を監視し、このシナリオを軽減するべきです。

たとえば、データベースに対してアドホック クエリを実行する十分な特権を持つデータベース プリンシパルがいて、基になるデータを ’推測’ し、最終的には実際の値を推測しようと試みているとします。 [Employee].[Salary] 列にマスクが定義されており、このユーザーがデータベースに直接接続して値を推測し始めたと仮定すると、最終的に Employees テーブル内の [Salary] の値を推測される可能性があります。

SELECT ID, Name, Salary FROM Employees
WHERE Salary > 99999 and Salary < 100001;
ID (アイディー) 名前 給与
62543 Jane Doe 0
91245 John Smith 0

このことから、動的データ マスクは、データベースでアドホック クエリを実行するユーザーから機密データを完全に保護する手段として単独で使用すべきではないことがわかります。 機密データの偶発的な露出を防ぐには適していますが、基になるデータを推測しようとする悪意ある意図に対しては保護になりません。

データベースのアクセス許可を適切に管理し、必要最小限のアクセス許可の原則に常に従うことが重要です。 また、データベースに対して実行されるすべてのアクティビティを追跡するために、必ず監査を有効にしてください。

SQL Server 2022 で導入された詳細なアクセス許可

SQL Server 2022 (16.x)以降では、機密データへの不正アクセスを防止し、データベースのさまざまなレベルで未承認ユーザーに対してマスクすることで制御することができます。 UNMASK 権限は、データベース レベル、スキーマ レベル、テーブル レベル、または列レベルで、ユーザー、データベース ロール、Microsoft Entra ID、または Microsoft Entra グループに付与または取り消すことができます。 機能拡張により、データベースの格納データへの未承認のアクセスを制御および制御してデータ セキュリティ管理を向上させるための、より詳細な方法が提供されます。

動的データ マスクを作成する

次の例では、3 種類の動的データ マスクでテーブルを作成します。 この例ではテーブルを作成し、結果を表示するように選びます。

-- schema to contain user tables
CREATE SCHEMA Data;
GO

-- table with masked columns
CREATE TABLE Data.Membership (
    MemberID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY CLUSTERED,
    FirstName VARCHAR(100) MASKED WITH (FUNCTION = 'partial(1, "xxxxx", 1)') NULL,
    LastName VARCHAR(100) NOT NULL,
    Phone VARCHAR(12) MASKED WITH (FUNCTION = 'default()') NULL,
    Email VARCHAR(100) MASKED WITH (FUNCTION = 'email()') NOT NULL,
    DiscountCode SMALLINT MASKED WITH (FUNCTION = 'random(1, 100)') NULL
);

-- inserting sample data
INSERT INTO Data.Membership (FirstName, LastName, Phone, Email, DiscountCode)
VALUES
('Roberto', 'Tamburello', '555.123.4567', 'RTamburello@contoso.com', 10),
('Janice', 'Galvin', '555.123.4568', 'JGalvin@contoso.com.co', 5),
('Shakti', 'Menon', '555.123.4570', 'SMenon@contoso.net', 50),
('Zheng', 'Mu', '555.123.4569', 'ZMu@contoso.net', 40);
GO

新しいユーザーが作成され、テーブルが属しているスキーマに対する SELECT アクセス許可が付与されます。 MaskingTestUser ビューのマスクされたデータとして、クエリが実行されます。

CREATE USER MaskingTestUser WITHOUT LOGIN;

GRANT SELECT ON SCHEMA::Data TO MaskingTestUser;

-- impersonate for testing:
EXECUTE AS USER = 'MaskingTestUser';

SELECT * FROM Data.Membership;

REVERT;

次のようにデータが変更された結果によって、マスクの効果が確認できます。

1 Roberto Tamburello 555.123.4567 RTamburello@contoso.com 10

変更前:

1 Rxxxxxo Tamburello xxxx RXXX@XXXX.com 91

DiscountCode内の数値は、クエリ結果ごとにランダムです。

既存の列のマスクを追加または編集する

テーブル内の既存の列にマスクを追加する場合、またはその列のマスクを編集する場合は、ALTER TABLE ステートメントを使用します。
次の例では、LastName 列にマスク関数を追加します。

ALTER TABLE Data.Membership
ALTER COLUMN LastName ADD MASKED WITH (FUNCTION = 'partial(2,"xxxx",0)');

次の例では、 LastName 列のマスク関数を変更します。

ALTER TABLE Data.Membership
ALTER COLUMN LastName VARCHAR(100) MASKED WITH (FUNCTION = 'default()');

アクセス許可を付与して、マスクが解除されたデータを表示する

UNMASK アクセス許可が付与されると、 MaskingTestUser は、マスクが解除されたデータを閲覧できるようになります。

GRANT UNMASK TO MaskingTestUser;

EXECUTE AS USER = 'MaskingTestUser';

SELECT * FROM Data.Membership;

REVERT;

-- Removing the UNMASK permission
REVOKE UNMASK TO MaskingTestUser;

動的データ マスクを削除する

次のステートメントは、先ほどの例で作成された LastName 列のマスクをドロップします。

ALTER TABLE Data.Membership
ALTER COLUMN LastName DROP MASKED;

詳細なアクセス許可の例

  1. ユーザー テーブルを含むスキーマを作成します。

    CREATE SCHEMA Data;
    GO
    
  2. マスキングされた列を含むテーブルを作成します。

    CREATE TABLE Data.Membership (
        MemberID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY CLUSTERED,
        FirstName VARCHAR(100) MASKED WITH (FUNCTION = 'partial(1, "xxxxx", 1)') NULL,
        LastName VARCHAR(100) NOT NULL,
        Phone VARCHAR(12) MASKED WITH (FUNCTION = 'default()') NULL,
        Email VARCHAR(100) MASKED WITH (FUNCTION = 'email()') NOT NULL,
        DiscountCode SMALLINT MASKED WITH (FUNCTION = 'random(1, 100)') NULL,
        BirthDay DATETIME MASKED WITH (FUNCTION = 'default()') NULL
    );
    
  3. サンプル データを挿入します。

    INSERT INTO Data.Membership (FirstName, LastName, Phone, Email, DiscountCode, BirthDay)
    VALUES
    ('Roberto', 'Tamburello', '555.123.4567', 'RTamburello@contoso.com', 10, '1985-01-25 03:25:05'),
    ('Janice', 'Galvin', '555.123.4568', 'JGalvin@contoso.com.co', 5, '1990-05-14 11:30:00'),
    ('Shakti', 'Menon', '555.123.4570', 'SMenon@contoso.net', 50, '2004-02-29 14:20:10'),
    ('Zheng', 'Mu', '555.123.4569', 'ZMu@contoso.net', 40, '1990-03-01 06:00:00');
    
  4. サービス テーブルを含むスキーマを作成します。

    CREATE SCHEMA Service;
    GO
    
  5. マスキングされた列を含むサービス テーブルを作成します。

    CREATE TABLE Service.Feedback (
        MemberID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY CLUSTERED,
        Feedback VARCHAR(100) MASKED WITH (FUNCTION = 'default()') NULL,
        Rating INT MASKED WITH (FUNCTION = 'default()'),
        Received_On DATETIME
        );
    
  6. サンプル データを挿入します。

    INSERT INTO Service.Feedback(Feedback, Rating, Received_On)
    VALUES
    ('Good', 4, '2022-01-25 11:25:05'),
    ('Excellent', 5, '2021-12-22 08:10:07'),
    ('Average', 3, '2021-09-15 09:00:00');
    
  7. データベースに別のユーザーを作成します。

    CREATE USER ServiceAttendant WITHOUT LOGIN;
    GO
    
    CREATE USER ServiceLead WITHOUT LOGIN;
    GO
    
    CREATE USER ServiceManager WITHOUT LOGIN;
    GO
    
    CREATE USER ServiceHead WITHOUT LOGIN;
    GO
    
  8. データベース内のユーザーに読み取りアクセス許可を付与します。

    ALTER ROLE db_datareader ADD MEMBER ServiceAttendant;
    
    ALTER ROLE db_datareader ADD MEMBER ServiceLead;
    
    ALTER ROLE db_datareader ADD MEMBER ServiceManager;
    
    ALTER ROLE db_datareader ADD MEMBER ServiceHead;
    
  9. ユーザーに異なる UNMASK アクセス許可を付与します。

    --Grant column level UNMASK permission to ServiceAttendant
    GRANT UNMASK ON Data.Membership(FirstName) TO ServiceAttendant;
    
    -- Grant table level UNMASK permission to ServiceLead
    GRANT UNMASK ON Data.Membership TO ServiceLead;
    
    -- Grant schema level UNMASK permission to ServiceManager
    GRANT UNMASK ON SCHEMA::Data TO ServiceManager;
    GRANT UNMASK ON SCHEMA::Service TO ServiceManager;
    
    --Grant database level UNMASK permission to ServiceHead;
    GRANT UNMASK TO ServiceHead;
    
  10. ユーザー ServiceAttendant のコンテキストでデータのクエリを実行します。

    EXECUTE AS USER = 'ServiceAttendant';
    
    SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay
    FROM Data.Membership;
    
    SELECT MemberID, Feedback, Rating
    FROM Service.Feedback;
    
    REVERT;
    
  11. ユーザー ServiceLead のコンテキストでデータのクエリを実行します。

    EXECUTE AS USER = 'ServiceLead';
    
    SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay
    FROM Data.Membership;
    
    SELECT MemberID, Feedback, Rating
    FROM Service.Feedback;
    
    REVERT;
    
  12. ユーザー ServiceManager のコンテキストでデータのクエリを実行します。

    EXECUTE AS USER = 'ServiceManager';
    
    SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay
    FROM Data.Membership;
    
    SELECT MemberID, Feedback, Rating
    FROM Service.Feedback;
    
    REVERT;
    
  13. ユーザー ServiceHead のコンテキストでデータのクエリを実行する

    EXECUTE AS USER = 'ServiceHead';
    
    SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay
    FROM Data.Membership;
    
    SELECT MemberID, Feedback, Rating
    FROM Service.Feedback;
    
    REVERT;
    
  14. UNMASK アクセス許可を取り消すには、次の T-SQL ステートメントを使用します。

    REVOKE UNMASK ON Data.Membership(FirstName) FROM ServiceAttendant;
    
    REVOKE UNMASK ON Data.Membership FROM ServiceLead;
    
    REVOKE UNMASK ON SCHEMA::Data FROM ServiceManager;
    
    REVOKE UNMASK ON SCHEMA::Service FROM ServiceManager;
    
    REVOKE UNMASK FROM ServiceHead;