動的データ マスク
適用対象: SQL Server 2016 (13.x) 以降のバージョン Azure SQL Database Azure SQL Managed Instance Azure Synapse Analytics SQL データベース
動的データ マスキング (DDM) では、特権のないユーザーに対して機密データをマスキングすることでデータの公開を制限します。 DDM を使用すると、アプリケーションのセキュリティの設計とコーディングを大幅に簡略化することができます。
このコンテンツは、一般的な動的データ マスクの概念および、SQL Server に適用されます。 他のプラットフォームに固有のコンテンツも利用できます。
- Azure SQL Database、Azure SQL Managed Instance、および Azure Synapse Analytics での動的データ マスクについては、「SQL Database の動的データ マスク概要」をご覧ください。
- Microsoft Fabric での動的データ マスクについては、「Fabric データ ウェアハウスでの動的データ マスク」を参照してください。
動的データ マスク (プレビュー) の概要
動的データ マスキングでは、公開する機密データの量を指定できるようにすることで、機密データに対する未承認のアクセスを防ぎ、アプリケーション レイヤーへの影響を最小限に抑えることができます。 DDM は、指定されたデータベース フィールドで、クエリの結果セットに含まれる機密データを隠蔽するように構成できます。 DDM によって、データベース内のデータが変更されることはありません。 DDM は、クエリの結果にマスク ルールが適用されるため、既存のアプリケーションで簡単に使用できます。 多くのアプリケーションは、既存のクエリを変更せずに、デリケートなデータをマスクすることができます。
- 中央のデータ マスク ポリシーは、データベースの機密フィールドに対して直接動作します。
- 機密データに対するアクセス権を持つ特権のあるユーザーまたはロールを指定します。
- DDM には、フル マスク関数と部分マスク関数、および数値データ用のランダム マスクがあります。
- 単純な Transact-SQL コマンドで、マスクを定義し、管理します。
動的データ マスクの目的は、アクセスすべきではないユーザーがデータを閲覧することを防ぎ、機密データの公開を制限することにあります。 動的データ マスクは、ユーザーが直接データベースに接続し、徹底的なクエリを実行して、機密データの漏えいを防ぐことを目的とはしていません。 動的データ マスクは、その他の SQL Server セキュリティ機能 (監査、暗号化、行レベルのセキュリティなど) を補完します。データベース内の機密データの保護をより強化するために、これを併用することをお勧めします。
動的データ マスクは SQL Server 2016 (13.x) と Azure SQL データベースで使用できます。 Transact-SQL をコマンドを使用して構成します。 Azure portal で動的データ マスクを構成する方法の詳細については、SQL Database 動的データ マスクの使用 (Azure ポータル)に関するページを参照してください。
Note
Microsoft Entra ID は以前に Azure Active Directory(Azure AD)として知られていました。
動的データ マスクを定義する
マスク ルールは、列のデータを難読化するために、テーブル内の列で定義することができます。 5 種類のマスクを利用できます。
関数 | 説明 | 例 |
---|---|---|
既定値 | 指定のフィールドのデータ型に応じたフル マスク。 文字列データ型 (char、nchar、varchar、nvarchar、text、ntext) のフィールドのサイズが 4 文字未満の場合は、 XXXX (またはそれ未満) を使用します。数値データ型 (bigint、 bit、 decimal、 int、 money、 numeric、 smallint、 smallmoney、 tinyint、 float、 real) の場合は値 0 を使用します。 日付/時刻データ型 (date、datetime2、datetime、datetimeoffset、smalldatetime、time) の場合は、 1900-01-01 00:00:00.0000000 を使います。バイナリ データ型 (binary、 varbinary、 image) の場合は、ASCII 値 0 のシングル バイトを使用します。 |
列定義の構文例: Phone# varchar(12) MASKED WITH (FUNCTION = 'default()') NULL ALTER 構文例: ALTER COLUMN Gender ADD MASKED WITH (FUNCTION = 'default()') |
電子メール | メール アドレスの最初の 1 文字と定数サフィックスの ".com" をメール アドレスのフォームで公開するマスク方法。 aXXX@XXXX.com . |
定義の構文例: Email varchar(100) MASKED WITH (FUNCTION = 'email()') NULL ALTER 構文例: ALTER COLUMN Email ADD MASKED WITH (FUNCTION = 'email()') |
Random | ランダム マスク関数は任意の数字型に使用でき、指定した範囲内で生成したランダムな値でオリジナルの値をマスクします。 | 定義の構文例: 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 に変わります。 |
日時 | 適用対象: SQL Server 2022 (16.x) データ型 datetime、datetime2、date、time、datetimeoffset、smalldatetime で定義された列のマスク方法。 これは、 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")') datetime の値の月をマスクする方法の例: ALTER COLUMN BirthDay ADD MASKED WITH (FUNCTION = 'datetime("M")') datetime の値の分をマスクする方法の例: ALTER COLUMN BirthDay ADD MASKED WITH (FUNCTION = 'datetime("m")') |
アクセス許可
テーブルに対して SELECT アクセス許可を持つユーザーは、テーブル データを閲覧できます。 マスク済みとして定義されている列には、マスクされたデータが表示されます。 UNMASK アクセス許可を付与されたユーザーは、マスクが定義された列から、マスクを解除したデータを取得できます。
管理ユーザーとロールは常に、ALTER ANY MASK および UNMASK アクセス許可の両方を持つ CONTROL アクセス許可を使用して、マスクされていないデータを閲覧できます。 sysadmin、db_owner などの管理ユーザーまたはロールには、仕様により、データベースに対する CONTROL 権限が付与されており、マスクされていないデータを閲覧できます。
動的データ マスクでテーブルを作成するのに特別なアクセス許可は要りません。スキーマ アクセス許可に対する標準的な CREATE TABLE と ALTER のみが必要です。
列のマスクを追加、置換、削除するには、 ALTER ANY MASK アクセス許可と、テーブルに対する ALTER アクセス許可が必要です。 セキュリティの責任者には、ALTER ANY MASK を付与するのが適切です。
Note
UNMASK の権限は、メタデータの可視性に影響しません。UNMASK だけを許可しても、メタデータは開示されません。 UNMASK が作用するには、常に SELECT 権限が付随する必要があります。 例: データベース スコープに対する UNMASK の許可と個々のテーブルに対する SELECT の許可によって、そのユーザーのみが選択できる個々のテーブルのメタデータのみが表示されるようになります。 「メタデータ表示の構成」も参照してください。
ベスト プラクティスと一般的なユース ケース
列にマスクを作成しても、その列への更新は防止されません。 マスクされた列にクエリを実行すると、ユーザーはマスクされたデータを受け取りますが、書き込みアクセス許可があるユーザーは、データを更新できます。 更新する許可を制限するために、適切なアクセス制御ポリシーを使用する必要があります。
SELECT INTO
またはINSERT 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 アクセス許可のないユーザーの場合、非推奨の READTEXT、UPDATETEXT、WRITETEXT ステートメントは、動的データ マスク用に構成された列では適切に機能しません。
動的データ マスクの追加は、基になっているテーブルでのスキーマ変更として実装されるため、依存関係を持つ列 (計算列によって参照される列など) では実行できません。 依存関係のある列に対して動的データ マスクを追加しようとすると、 ALTER TABLE ALTER COLUMN _columnname_ failed because one or more objects access this column
エラーが発生します。 この制限を回避するには、最初に依存関係を削除してから、動的データ マスクを追加した後、依存関係を再作成します。 たとえば、依存関係がその列に依存するインデックスによるものである場合は、インデックスを削除し、マスクを追加してから、依存するインデックスを再作成します。
データ マスキング関数が定義されている列を参照する式を射影するたびに、式もマスクされます。 参照される列をマスクするために使用される関数 (既定、電子メール、ランダム、カスタム文字列) に関係なく、結果として得られる式は常に既定の関数でマスクされます。
2 つの異なる Azure SQL データベース、または異なる SQL Server インスタンスでホストされているデータベースにまたがるデータベース間クエリ、および MASKED 列でのあらゆる種類の比較または結合操作を伴う場合、正しい結果が得られません。 リモート サーバーから返される結果は既に MASKED 形式であり、ローカルでのあらゆる比較や結合操作に適していません。
Note
基になるベース テーブルがインデックス付きビューで参照されている場合、動的データ マスクはサポートされません。
セキュリティに関する注意: 推論またはブルートフォース手法を使用してマスクをバイパスする
動的データ マスクは、アプリケーションに使用される事前定義されたクエリ セットのデータ公開を制限することで、アプリケーション開発を簡素化するために設計されています。 動的データ マスクは、運用データベースに直接アクセスするときに機密データが誤って公開されることを防ぐためにも有効ですが、アドホック クエリ アクセス許可を持つ特権のないユーザーが、実際のデータに対するアクセス権を得る手法を適用する可能性にも注意する必要があります。 このようなアドホック アクセス権を付与する必要がある場合、監査を使用して、すべてのデータベース操作を監視し、このシナリオを軽減するべきです。
たとえば、データベースに対してアドホック クエリを実行する十分な特権を持つデータベース プリンシパルがいて、基になるデータを '推測' し、最終的には実際の値を推測しようと試みているとします。 管理者は [Employee].[Salary]
列に対してマスクを定義しましたが、このユーザーはデータベースに直接接続し、値を推測した結果、[Salary]
テーブルの Employees
を推論したと仮定します。
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;
詳細なアクセス許可の例
ユーザー テーブルを含むスキーマを作成します。
CREATE SCHEMA Data; GO
マスキングされた列を含むテーブルを作成します。
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 );
サンプル データを挿入します。
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');
サービス テーブルを含むスキーマを作成します。
CREATE SCHEMA Service; GO
マスキングされた列を含むサービス テーブルを作成します。
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 );
サンプル データを挿入します。
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');
データベースに別のユーザーを作成します。
CREATE USER ServiceAttendant WITHOUT LOGIN; GO CREATE USER ServiceLead WITHOUT LOGIN; GO CREATE USER ServiceManager WITHOUT LOGIN; GO CREATE USER ServiceHead WITHOUT LOGIN; GO
データベース内のユーザーに読み取りアクセス許可を付与します。
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;
ユーザーに異なる 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;
ユーザー
ServiceAttendant
のコンテキストでデータのクエリを実行します。EXECUTE AS USER = 'ServiceAttendant'; SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay FROM Data.Membership; SELECT MemberID, Feedback, Rating FROM Service.Feedback; REVERT;
ユーザー
ServiceLead
のコンテキストでデータのクエリを実行します。EXECUTE AS USER = 'ServiceLead'; SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay FROM Data.Membership; SELECT MemberID, Feedback, Rating FROM Service.Feedback; REVERT;
ユーザー
ServiceManager
のコンテキストでデータのクエリを実行します。EXECUTE AS USER = 'ServiceManager'; SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay FROM Data.Membership; SELECT MemberID, Feedback, Rating FROM Service.Feedback; REVERT;
ユーザー
ServiceHead
のコンテキストでデータのクエリを実行するEXECUTE AS USER = 'ServiceHead'; SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay FROM Data.Membership; SELECT MemberID, Feedback, Rating FROM Service.Feedback; REVERT;
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;