動的なデータ マスキング
適用対象: SQL Server 2016 (13.x) 以降
Azure SQL Database
Azure SQL Managed Instance
Azure Synapse Analytics
動的データ マスク (DDM) では、機密データをマスクすることにより、特権のないユーザーへの機密データの公開を制限します。 DDM を使用すると、アプリケーションのセキュリティの設計とコーディングを大幅に簡略化することができます。
動的データ マスクでは、公開する機密データの量を指定することで、そのようなデータに対する未承認のアクセスを防ぎ、アプリケーション レイヤーへの影響が最小限に抑えられます。 DDM は、指定されたデータベース フィールドで、クエリの結果セットに含まれる機密データを隠蔽するように構成できます。 DDM によって、データベース内のデータが変更されることはありません。 DDM は、クエリの結果にマスク ルールが適用されるため、既存のアプリケーションで簡単に使用できます。 多くのアプリケーションは、既存のクエリを変更せずに、デリケートなデータをマスクすることができます。
- 中央のデータ マスク ポリシーは、データベースの機密フィールドに対して直接動作します。
- 機密データに対するアクセス権を持つ特権のあるユーザーまたはロールを指定します。
- DDM には、フル マスク関数と部分マスク関数、および数値データ用のランダム マスクがあります。
- 単純な Transact-SQL コマンドで、マスクを定義し、管理します。
動的データ マスクの目的は、アクセスすべきではないユーザーがデータを閲覧することを防ぎ、機密データの公開を制限することにあります。 動的データ マスクは、ユーザーが直接データベースに接続し、徹底的なクエリを実行して、機密データの漏えいを防ぐことを目的とはしていません。 動的データ マスクは、その他の SQL Server セキュリティ機能 (監査、暗号化、行レベルのセキュリティなど) を補完します。データベース内の機密データの保護をより強化するために、これを併用することをお勧めします。
動的データ マスクは SQL Server 2016 (13.x) と Azure SQL データベースで使用できます。 Transact-SQL をコマンドを使用して構成します。 Azure portal で動的データ マスクを構成する方法の詳細については、SQL Database 動的データ マスクの使用 (Azure ポータル)に関するページを参照してください。
動的データ マスクを定義する
マスク ルールは、列のデータを難読化するために、テーブル内の列で定義することがあります。 4 種類のマスクを利用できます。
機能 | 説明 | 例 |
---|---|---|
Default | 指定のフィールドのデータ型に応じたフル マスク。 文字列データ型 (char、nchar、varchar、nvarchar、text、ntext) のフィールドのサイズが 4 文字未満の場合は、XXXX またはそれ未満の数の X を使用します。 数値データ型 (bigint、 bit、 decimal、 int、 money、 numeric、 smallint、 smallmoney、 tinyint、 float、 real) の場合は値 0 を使用します。 日付/時刻のデータ型 (date、 datetime2、 datetime、 datetimeoffset、 smalldatetime、 time) の場合は、01.01.1900 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()') |
|
ランダム | ランダム マスク関数は任意の数字型に使用でき、指定した範囲内で生成したランダムな値でオリジナルの値をマスクします。 | 定義の構文例: 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)') その他の例: ALTER COLUMN [Phone Number] ADD MASKED WITH (FUNCTION = 'partial(5,"XXXXXXX",0)') |
Datetime | 適用対象: 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")') |
アクセス許可
動的データ マスクでテーブルを作成するのに特別なアクセス許可は要りません。スキーマ アクセス許可に対する標準的な CREATE TABLE と ALTER のみが必要です。
列のマスクを追加、置換、削除するには、 ALTER ANY MASK アクセス許可と、テーブルに対する ALTER アクセス許可が必要です。 セキュリティの責任者には、ALTER ANY MASK を付与するのが適切です。
テーブルに対して SELECT アクセス許可を持つユーザーは、テーブル データを閲覧できます。 マスク済みとして定義されている列には、マスクされたデータが表示されます。 UNMASK アクセス許可を付与されたユーザーは、マスクが定義された列から、マスクを解除したデータを取得できます。
データベースに対する CONTROL アクセス許可には、 ALTER ANY MASK と UNMASK の両方のアクセス許可が含まれます。
注意
UNMASK の権限は、メタデータの可視性に影響しません。UNMASK だけを許可しても、メタデータは開示されません。 UNMASK が作用するには、常に SELECT 権限が付随する必要があります。 例: データベース スコープに対する UNMASK の許可と個々のテーブルに対する SELECT の許可によって、そのユーザーのみが選択できる個々のテーブルのメタデータのみが表示されるようになります。 「メタデータ表示の構成」も参照してください。
ベスト プラクティスと一般的なユース ケース
列にマスクを作成しても、その列への更新は防止されません。 マスクされた列にクエリを実行すると、ユーザーはマスクされたデータを受け取りますが、書き込みアクセス許可があるユーザーは、データを更新できます。 更新する許可を制限するために、適切なアクセス制御ポリシーを使用する必要があります。
SELECT INTO
またはINSERT INTO
を使用して、マスクされた列を別のテーブルにコピーすると、対象のテーブルにマスクされたデータが表示されます。動的データ マスクは、 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;
制限事項と制約事項
次の列の型には、マスク ルールを定義することはできません。
暗号化された列 (常に暗号化されます)
FILESTREAM
COLUMN_SET、または列セットの一部であるスパース列
計算列にマスクを構成することはできませんが、計算列が MASK のある列に依存している場合は、マスクされたデータが計算列から返されます。
データ マスキングのある列を FULLTEXT インデックスのキーにすることはできません。
PolyBase 外部テーブル内の列。
UNMASK アクセス許可のないユーザーの場合、非推奨の READTEXT、UPDATETEXT、WRITETEXT ステートメントは、動的データ マスク用に構成された列では適切に機能しません。
動的データ マスクの追加は基になっているテーブルでのスキーマ変更として実装されるため、依存関係を持つ列では実行できません。 この制限を回避するには、最初に依存関係を削除してから、動的データ マスクを追加した後、依存関係を再作成します。 たとえば、依存関係がその列に依存するインデックスによるものである場合は、インデックスを削除し、マスクを追加してから、依存するインデックスを再作成します。
データ マスキング関数が定義されている列を参照する式を射影するたびに、式もマスクされます。 参照される列をマスクするために使用される関数 (既定、電子メール、ランダム、カスタム文字列) に関係なく、結果として得られる式は常に既定の関数でマスクされます。
2 つの異なる Azure SQL データベース、または異なる SQL Server インスタンスでホストされているデータベースにまたがるデータベース間クエリ、および MASKED 列でのあらゆる種類の比較または結合操作を伴う場合、正しい結果が得られません。 リモート サーバーから返される結果は既に MASKED 形式であり、ローカルでのあらゆる比較や結合操作に適していません。
セキュリティに関する注意:推論またはブルートフォース手法を使用してマスクをバイパスする
動的データ マスクは、アプリケーションに使用される事前定義されたクエリ セットのデータ公開を制限することで、アプリケーション開発を単純化するために設計されています。 動的データ マスクは、運用データベースに直接アクセスするときに機密データが誤って公開されるのを防ぐのにも役立ちますが、アドホック クエリアクセス許可を持つ特権のないユーザーは、実際のデータにアクセスするための手法を適用できることに注意することが重要です。 このようなアドホック アクセスを許可する必要がある場合は、監査を使用してすべてのデータベース アクティビティを監視し、このシナリオを軽減する必要があります。
たとえば、データベースに対してアドホック クエリを実行するのに十分な特権を持ち、基になるデータを "推測" し、最終的に実際の値を推論しようとするデータベース プリンシパルを考えてみましょう。 管理者は [Employee].[Salary]
列に対してマスクを定義しましたが、このユーザーはデータベースに直接接続し、値の推測を開始し、最終的には従業員セットの [Salary]
値を推測します。
SELECT ID, Name, Salary FROM Employees
WHERE Salary > 99999 and Salary < 100001;
Id 名前 Salary 62543 Jane Doe 0 91245 John Smith 0
これは、データベースでアドホック クエリを実行しているユーザーからの機密データを完全にセキュリティで保護するための分離されたメジャーとして動的データ マスクを使用しないことを示しています。 動的データ マスクは偶発的な機密データの公開を防ぐ場合に適していますが、基になるデータを推測する悪意のある攻撃を防ぐためのものではありません。
データベースのアクセス許可を適切に管理し、必要最小限のアクセス許可の原則に常に従うことが重要です。 また、データベースに対して実行されるすべてのアクティビティを追跡するために、必ず監査を有効にしてください。
SQL Server 2022 で導入された詳細なアクセス許可
SQL Server 2022 (16.x) 以降では、機密データへの不正アクセスを防ぎ、データベースのさまざまなレベルで承認されていないユーザーにマスクすることで制御を得ることができます。 UNMASK 権限は、データベース レベル、スキーマ レベル、テーブル レベル、または列レベルでユーザーまたはデータベース ロールに付与または取り消すことができます。 機能拡張により、データベースの格納データへの未承認のアクセスを制御および制御してデータ セキュリティ管理を向上させるための、より詳細な方法が提供されます。
例
動的データ マスクを作成する
次の例では、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);
新しいユーザーが作成され、テーブルが属しているスキーマに対する 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 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;
関連項目
CREATE TABLE (Transact-SQL)
ALTER TABLE (Transact-SQL)
column_definition (Transact-SQL)
sys.masked_columns (Transact-SQL)
SQL Database 動的データ マスクの使用 (Azure portal)