Azure SQLの正規表現DDMとは?メール・電話番号をマスクする設定方法

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 ID568139
対象サービス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[email protected]*****@example.jp
PhoneNumber+81 90 1234 5678(+81)-xxxx
ExternalIdCUS-123456-JPCUS-******-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を評価するときは、次の順序で進めると安全です。

  1. メール、電話番号、識別子などの対象列を洗い出す
  2. 実データから書式の種類と不一致件数を確認する
  3. どの部分を残し、どの部分を隠すか決める
  4. 非本番環境でREGEXP_REPLACEマスクを設定する
  5. UNMASKなし、列単位UNMASK、管理者の各ユーザーで結果を確認する
  6. 実際のアプリSQL、帳票、エクスポート処理をテストする
  7. sys.masked_columnsで設定内容を確認し、削除用SQLも準備する
  8. 一般提供後に、SLAや最新の制約を再確認して本番導入を判断する

Azure SQLの正規表現DDMは、従来の固定的なマスクでは対応しにくかった可変長データを、データベース層で柔軟に保護できる機能です。一方で、パターンに一致しない値がマスクされないため、正規表現の巧さだけでは安全性を確保できません。

まずは非本番環境で対象列のデータ形式を調査し、非特権ユーザーから想定外の値が見えないことを確認してください。そのうえで、アプリケーションの接続権限とUNMASKの付与範囲を見直すことが、実用的な第一歩です。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次