Azure SQL Databaseで「メールアドレスはドメインだけ残したい」「電話番号は国番号だけ表示したい」「可変長の識別子から一部だけ見せたい」と考えても、従来のDynamic Data Masking(DDM)では柔軟なマスクが難しい場面がありました。
Microsoftは2026年7月31日、Azure Update 568139として、Azure SQL Databaseの正規表現ベースDynamic Data Maskingをパブリックプレビューで公開しました。新しいマスク関数としてREGEXP_REPLACEを利用でき、文字列の形式に応じて残す部分と隠す部分を細かく指定できます。マスクはデータベース側で適用されるため、既存アプリケーションのSQLを大きく変更せず、機密情報の表示ルールを一元管理できます。
ただし、現時点では本番利用を前提としないプレビュー機能です。また、正規表現に一致しなかった値はマスクされず、そのまま表示されるという重要な注意点があります。導入時は、正規表現を書くことよりも、既存データの形式調査と権限設計を優先する必要があります。
Azure SQLの正規表現ベースDDMとは
Dynamic Data Maskingは、データベースに保存されている元データを変更せず、クエリ結果を返す段階で機密部分をマスクする機能です。
SELECT権限を持つ一般ユーザーにはマスク後の値を返し、UNMASK権限を持つユーザーやdb_ownerなどの管理者には元の値を返します。データの書き換えや匿名化を行う機能ではなく、表示時の露出を抑える仕組みです。(Microsoft Learn)
従来のDDMとの違い
Azure SQL Databaseには、以前からdefault()、email()、partial()、random()などのマスク関数が用意されています。しかし、これらは出力形式が固定されているため、可変長データや複数の書式が混在する列には対応しにくいという課題がありました。
| マスク方法 | 向いているケース | 主な制約 |
|---|---|---|
default() | 値を全面的に隠したい | 文字列はXXXXなどの固定値になる |
email() | メールアドレスらしい形式で隠したい | ドメインを保持できず、固定形式になる |
partial() | 先頭や末尾を一定文字数だけ残したい | 文字数を固定で指定する必要がある |
REGEXP_REPLACE | メール、電話番号、会員番号などをパターン別に隠したい | 正規表現に一致しない値はマスクされない |
たとえば、従来のemail()ではメールアドレスが[email protected]のような固定形式になります。正規表現ベースDDMなら、ユーザー名だけを*****に置き換え、example.jpなどのドメインを残す設定が可能です。(Microsoft Learn)
2026年7月更新で追加された内容
今回のAzure SQL更新の要点は次のとおりです。
| 項目 | 内容 |
|---|---|
| 発表日 | 2026年7月31日 |
| Azure Update ID | 568139 |
| 対象サービス | Azure SQL Database |
| 提供状況 | パブリックプレビュー |
| 追加されたマスク関数 | REGEXP_REPLACE |
| 設定方法 | T-SQLのみ |
| Azureポータルでの設定 | 現時点では非対応 |
| 権限モデル | 既存DDMと同じ |
| 対象データ型 | char、nchar、varchar、nvarchar |
| LOB型 | varchar(max)、nvarchar(max)を最大2MBまでサポート |
| 正規表現の長さ | 最大8,000バイト |
正規表現DDMで指定できる引数は、検索パターンと置換文字列の2つです。通常のREGEXP_REPLACE関数にある開始位置、置換回数、フラグは変更できません。マスク時は、開始位置が1、すべての一致箇所を置換、大文字と小文字を区別する設定で固定されます。(Microsoft Learn)
つまり、大文字と小文字の両方を対象にする場合は、[A-Za-z]のように正規表現側で明示的に指定する必要があります。
また、Microsoftはプレビュー機能をサービスレベル契約や限定保証の対象外としており、正規表現DDMについても非本番環境での利用を案内しています。2026年8月時点では、本番データベースへの即時適用ではなく、検証環境での評価を優先すべきです。(Microsoft Learn)
Azure SQLの正規表現DDMでメール・電話番号・識別子をマスクする方法
ここでは、次のルールを持つ顧客連絡先テーブルを作成します。
| 列 | マスク内容 |
|---|---|
| メールアドレス | @より前を*****に置換し、ドメインを残す |
| 電話番号 | 国番号を残し、それ以降を隠す |
| 外部識別子 | 先頭3文字と末尾2文字を残し、中央の番号を隠す |
以下は、公式の構文を基にした検証用サンプルです。正規表現は実際のデータ形式に合わせて変更してください。(Microsoft Learn)
テーブル作成時にマスクを設定する
IF SCHEMA_ID('Data') IS NULL
EXEC('CREATE SCHEMA Data');
GO
DROP TABLE IF EXISTS Data.CustomerContact;
GO
CREATE TABLE Data.CustomerContact
(
CustomerId int IDENTITY(1,1) PRIMARY KEY,
DisplayName nvarchar(100) NOT NULL,
Email varchar(255)
MASKED WITH
(
FUNCTION = 'REGEXP_REPLACE(
"^([^@]+)(@.+)$",
"*****\2")'
) NULL,
PhoneNumber varchar(30)
MASKED WITH
(
FUNCTION = 'REGEXP_REPLACE(
"^(\+\d{1,3})(?:[ -.]?\d){7,14}$",
"(\1)-xxxx")'
) NULL,
ExternalId varchar(30)
MASKED WITH
(
FUNCTION = 'REGEXP_REPLACE(
"^([A-Za-z]{3})-([0-9]{6})-([A-Za-z]{2})$",
"\1-******-\3")'
) NOT NULL
);
GO
メールアドレスでは、最初のキャプチャグループに@より前の文字列、2番目のグループに@以降を取り込みます。置換文字列を*****\2とすることで、ユーザー名を隠しながらドメインを残しています。
識別子では、\1が先頭3文字、\3が末尾2文字です。中央の6桁を固定文字列の******に置き換えています。
サンプルデータを登録する
INSERT INTO Data.CustomerContact
(
DisplayName,
Email,
PhoneNumber,
ExternalId
)
VALUES
(
N'田中 洋',
'[email protected]',
'+81 90 1234 5678',
'CUS-123456-JP'
);
GO
非特権ユーザーでマスク結果を確認する
テーブルに対するSELECT権限だけを持ち、UNMASK権限を持たないユーザーを作成します。
CREATE USER SupportOperator WITHOUT LOGIN;
GO
GRANT SELECT ON Data.CustomerContact TO SupportOperator;
GO
EXECUTE AS USER = 'SupportOperator';
SELECT
CustomerId,
DisplayName,
Email,
PhoneNumber,
ExternalId
FROM Data.CustomerContact;
REVERT;
GO
想定される表示結果は次のとおりです。
| 列 | 保存されている値 | 非特権ユーザーから見える値 |
|---|---|---|
[email protected] | *****@example.jp | |
| PhoneNumber | +81 90 1234 5678 | (+81)-xxxx |
| ExternalId | CUS-123456-JP | CUS-******-JP |
マスクはクエリ結果に対して適用され、テーブル内の元データは変更されません。(Microsoft Learn)
UNMASK権限で元データの閲覧範囲を制御する
UNMASK権限は、データベース、スキーマ、テーブル、列の各単位で付与できます。
たとえば、サポート担当者にメールアドレスだけを開示し、電話番号と外部識別子は引き続きマスクしたい場合は、列単位で権限を付与します。
GRANT UNMASK
ON Data.CustomerContact (Email)
TO SupportOperator;
GO
この状態で再度クエリを実行すると、Emailだけが元の値で表示されます。
EXECUTE AS USER = 'SupportOperator';
SELECT
Email,
PhoneNumber,
ExternalId
FROM Data.CustomerContact;
REVERT;
GO
権限を取り消す場合は、次のように実行します。
REVOKE UNMASK
ON Data.CustomerContact (Email)
FROM SupportOperator;
GO
UNMASK単独ではテーブルを参照できません。元データを表示するには、対象オブジェクトへのSELECT権限も必要です。一方、db_ownerやデータベースのCONTROL権限を持つユーザーは、設計上マスク前のデータを閲覧できます。(Microsoft Learn)
アプリケーションの接続ユーザーをdb_ownerにしている環境では、DDMを設定してもアプリ側には元データが返ります。正規表現の設定だけでなく、接続ユーザーの権限を最小化することが重要です。
既存列に正規表現マスクを追加する
既存テーブルの列には、ALTER TABLEでマスクを追加できます。
ALTER TABLE dbo.Customers
ALTER COLUMN ExternalId
ADD MASKED WITH
(
FUNCTION = 'REGEXP_REPLACE(
"^([A-Za-z]{3})-([0-9]{6})-([A-Za-z]{2})$",
"\1-******-\3")'
);
GO
既存列にマスクを追加、変更、削除するには、対象テーブルへのALTER権限とALTER ANY MASK権限が必要です。テーブル作成時にマスク列を定義する場合は、通常のCREATE TABLE権限とスキーマへのALTER権限が必要になります。(Microsoft Learn)
設定済みのマスクを確認する
マスクの設定状況は、sys.masked_columnsシステムビューで確認できます。
SELECT
SCHEMA_NAME(t.schema_id) AS schema_name,
t.name AS table_name,
c.name AS column_name,
c.is_masked,
c.masking_function
FROM sys.masked_columns AS c
INNER JOIN sys.tables AS t
ON c.object_id = t.object_id
WHERE c.is_masked = 1
ORDER BY
schema_name,
table_name,
column_name;
GO
masking_function列には、設定したREGEXP_REPLACEの内容も表示されます。デプロイ後の確認だけでなく、マスク定義の棚卸しにも利用できます。(Microsoft Learn)
マスクを削除する
ALTER TABLE dbo.Customers
ALTER COLUMN ExternalId DROP MASKED;
GO
プレビュー検証では、追加用SQLだけでなく、元に戻すSQLも事前に用意しておくと安全です。
マスク用正規表現を設計するときの判断基準
マスクの正規表現をデータ検証に使わない
メールアドレスを厳密に検証する正規表現は複雑になりやすく、正しいメールアドレスでも特殊な形式が原因で一致しないことがあります。
正規表現DDMでは、一致しない値が元のまま返されます。そのため、マスク用パターンを必要以上に厳しくすると、機密値が露出する原因になります。(Microsoft Learn)
マスク用パターンでは、次のように考えるのが実務的です。
- 残したい部分を明確にする
- 実データに存在する表記を広くカバーする
- 形式の妥当性確認は、入力時の検証や
CHECK制約で別に行う - マスクに一致しない行を定期的に検出する
「正しい形式だけをマスクする」のではなく、実際に保存されている機密値を漏れなくマスクすることを優先します。
大文字と小文字を正規表現内で指定する
マスク関数では大文字と小文字を区別する設定が固定で使用されます。
次のパターンは大文字しか対象にしません。
[A-Z]{3}
大文字と小文字の両方が保存される可能性がある場合は、次のように指定します。
[A-Za-z]{3}
データ登録時に大文字へ統一する運用も有効です。
\dと\wは全角文字や日本語を含まない
Azure SQLの正規表現実装はRE2ベースです。\dはASCII数字の0から9、\wは半角英数字とアンダースコアを対象とします。全角数字や日本語文字まで自動的に一致するわけではありません。(Microsoft Learn)
たとえば、次の2つは別の値として考える必要があります。
123456
123456
全角数字が混在する可能性がある場合は、登録時に半角へ正規化するか、実データに合わせて文字クラスを設計してください。
また、他のプログラミング言語やWebサイト向けに作られた正規表現を、そのままAzure SQLへ移植しない方が安全です。RE2ベースの構文としてAzure SQL Database上で動作確認する必要があります。(Microsoft Learn)
一致しないデータを事前に検出する
正規表現DDM導入時の最大のリスクは、マスク対象列に想定外の形式が含まれていることです。
たとえば、電話番号のパターンを国際形式だけに対応させた場合、次のような国内形式は一致しない可能性があります。
090-1234-5678
その状態でマスクを適用すると、一致しなかった電話番号は非特権ユーザーにもそのまま表示されます。
REGEXP_LIKEを利用できる環境では、マスクを設定する前に不一致データを抽出できます。
SELECT
CustomerId,
Email
FROM Data.CustomerContact
WHERE Email IS NOT NULL
AND NOT REGEXP_LIKE
(
Email,
'^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'
);
GO
REGEXP_LIKEを利用するには、データベース互換性レベル170以上が必要です。現在の設定は次のSQLで確認できます。互換性レベルの変更はアプリケーションの動作に影響する可能性があるため、この確認だけを理由に即時変更せず、別途回帰テストを行ってください。(Microsoft Learn)
SELECT
name,
compatibility_level
FROM sys.databases
WHERE name = DB_NAME();
GO
メールだけでなく、電話番号や識別子についても同様の不一致確認を行います。件数だけを確認する場合は、COUNT(*)で集計すると移行判断がしやすくなります。
導入時に失敗しやすいポイント
| 失敗しやすいポイント | 起こる問題 | 対策 |
|---|---|---|
| 想定外の形式が存在する | 一致しない値がそのまま表示される | 本番相当データで不一致件数を確認する |
アプリ接続ユーザーがdb_owner | マスクされず元データが返る | 専用ユーザーを作り最小権限にする |
| メールや電話番号の表記が混在する | 一部の行だけマスクされない | 登録時に形式を正規化する |
| マスク列を式や関数で加工する | 期待した正規表現マスクと異なる結果になる | 実際のアプリSQLで表示結果を確認する |
| 列にインデックスや計算列などの依存関係がある | ALTER COLUMNが失敗する | 依存オブジェクトを調査し、必要に応じて再作成する |
| 大量データを一括取得する | 正規表現処理の負荷が増える可能性がある | 代表的な検索・帳票・エクスポートで性能を測定する |
一般的なDDMでは、マスク列を参照する式の結果に、元のマスク関数ではなく既定のマスクが適用される場合があります。また、マスク追加はスキーマ変更として扱われ、列に依存するオブジェクトがあると失敗することがあります。(Microsoft Learn)
正規表現処理の性能は、パターンの複雑さ、文字列の長さ、処理する行数によって変わります。単純な画面表示だけでなく、CSV出力、帳票生成、バッチ処理など、取得件数が多い処理も検証対象に含めてください。(Microsoft Learn)
アプリ側を変更せずに導入できる条件
DDMはクエリ結果に対して適用されるため、既存のSELECT文を変更せずに導入できるケースがあります。ただし、「アプリを一切変更しなくてよい」とは限りません。
特に確認すべきなのは、アプリケーションがマスク後の値を単に表示するだけなのか、後続処理に使うのかという点です。
| 処理 | 推奨する権限設計 |
|---|---|
| サポート画面で連絡先を表示する | SELECTのみ付与し、UNMASKは付与しない |
| メール送信処理 | 送信専用IDにEmail列だけのUNMASKを付与する |
| 電話発信処理 | 発信専用IDにPhoneNumber列だけのUNMASKを付与する |
| 管理者向け検索 | 承認されたロールに限定してUNMASKを付与する |
| 開発者の調査用接続 | マスクされた読み取り専用ユーザーを利用する |
| データエクスポート | 専用IDと専用ジョブを用意し、実行履歴を監査する |
たとえば、サポート画面とメール送信バッチが同じ高権限ユーザーで接続している場合、サポート画面にも元のメールアドレスが返ります。用途ごとに接続IDを分離し、必要な列にだけUNMASKを付与する方が安全です。
正規表現DDMをセキュリティ対策の代わりにしない
DDMは、機密情報の偶発的な表示や、通常のアプリ画面での過剰な露出を抑える機能です。悪意のあるユーザーによる推測や総当たりを完全に防止するセキュリティ境界ではありません。
アドホッククエリを自由に実行できるユーザーは、検索条件を細かく変えることで、マスク前の値を推測できる可能性があります。Microsoftも、DDMを単独で機密データ保護に利用せず、最小権限、監査、暗号化、行レベルセキュリティなどと組み合わせることを推奨しています。(Microsoft Learn)
なお、Always Encryptedで暗号化された列にはDDMを設定できません。機密度が非常に高い列では、DDMで表示を整えるのか、暗号化によってデータベース管理者からも値を保護するのかを、要件に応じて選択する必要があります。(Microsoft Learn)
Azure SQLの正規表現DDMを導入する流れ
正規表現ベースDDMを評価するときは、次の順序で進めると安全です。
- メール、電話番号、識別子などの対象列を洗い出す
- 実データから書式の種類と不一致件数を確認する
- どの部分を残し、どの部分を隠すか決める
- 非本番環境で
REGEXP_REPLACEマスクを設定する UNMASKなし、列単位UNMASK、管理者の各ユーザーで結果を確認する- 実際のアプリSQL、帳票、エクスポート処理をテストする
sys.masked_columnsで設定内容を確認し、削除用SQLも準備する- 一般提供後に、SLAや最新の制約を再確認して本番導入を判断する
Azure SQLの正規表現DDMは、従来の固定的なマスクでは対応しにくかった可変長データを、データベース層で柔軟に保護できる機能です。一方で、パターンに一致しない値がマスクされないため、正規表現の巧さだけでは安全性を確保できません。
まずは非本番環境で対象列のデータ形式を調査し、非特権ユーザーから想定外の値が見えないことを確認してください。そのうえで、アプリケーションの接続権限とUNMASKの付与範囲を見直すことが、実用的な第一歩です。

コメント