Enmascaramiento de datos dinámicos

Se aplica a: SQL Server 2016 (13.x) y versiones posteriores Azure SQL DatabaseAzure SQL Managed InstanceAzure Synapse Analytics

Diagrama del enmascaramiento dinámico de datos.

El enmascaramiento dinámico de datos (DDM) limita la exposición de datos confidenciales enmascarándolos a usuarios sin privilegios. Se puede usar para simplificar considerablemente el diseño y la codificación de la seguridad en la aplicación.

Este contenido se aplica a los conceptos de enmascaramiento dinámico de datos generalmente y específicos de SQL Server. El contenido específico de otras plataformas está disponible:

Información general sobre el enmascaramiento dinámico de datos

El enmascaramiento dinámico de datos evita el acceso no autorizado a información confidencial al permitir que los clientes especifiquen la cantidad de información confidencial que se debe revelar, con un efecto mínimo en la capa de aplicación. DDM se puede configurar en los campos de la base de datos designada para ocultar información confidencial en los conjuntos de resultados de consultas. Con DDM no se modifican los datos en la base de datos. DDM resulta fácil de usar con las aplicaciones existentes, ya que las reglas de enmascaramiento se aplican en los resultados de la consulta. Muchas aplicaciones pueden enmascarar información confidencial sin modificar las consultas existentes.

  • Una directiva de enmascaramiento de datos central actúa directamente en los campos confidenciales de la base de datos.
  • Designe roles o usuarios con privilegios que tienen acceso a la información confidencial.
  • DDM cuenta con funciones de enmascaramiento total y parcial, además de una máscara aleatoria para datos numéricos.
  • Los comandos Transact-SQL simples definen y administran las máscaras.

La finalidad del enmascaramiento dinámico de datos es limitar la exposición de la información confidencial, impidiendo que los usuarios vean datos a los que no deberían poder acceder. El enmascaramiento dinámico de datos no pretende evitar que los usuarios de la base de datos se conecten directamente a ella y ejecuten consultas exhaustivas que expongan información confidencial. El enmascaramiento dinámico de datos es complementario de otras características de seguridad de SQL Server (auditoría, cifrado, seguridad de nivel de fila...). Es muy recomendable que se use junto a esas características para proteger mejor la información confidencial en la base de datos.

El enmascaramiento dinámico de datos está disponible en SQL Server 2016 (13.x) y en Azure SQL Database, y se configura con comandos Transact-SQL. Para obtener más información sobre cómo configurar el enmascaramiento dinámico de datos con el Portal de Azure, vea Introducción al enmascaramiento dinámico de datos de SQL Database (Portal de Azure).

Nota:

Microsoft Entra ID conocido anteriormente como Azure Active Directory (Azure AD).

Definir el enmascaramiento dinámico de datos

Es posible definir una regla de enmascaramiento en una columna de una tabla, con el objetivo de ofuscar los datos de esa columna. Existen cinco tipos de máscaras.

Función Descripción Ejemplos
Valor predeterminado Enmascaramiento completo de acuerdo con los tipos de datos de los campos designados.

Para los tipos de datos de cadena, use XXXX (o menos) si el tamaño del campo es inferior a 4 caracteres (char, nchar, varchar, nvarchar, text, ntext).

Para los tipos de datos numéricos, use un valor cero (bigint, bit, decimal, int, money, numeric, smallint, smallmoney, tinyint, float, real).

Para los tipos de datos de fecha y hora, use 1900-01-01 00:00:00.0000000 (date, datetime2, datetime, datetimeoffset, smalldatetime, time).

En lo que respecta a los tipos de datos binarios, use un solo byte de valor 0 de ASCII (binary, varbinary, image).
Ejemplo de sintaxis de definición de columna: Phone# varchar(12) MASKED WITH (FUNCTION = 'default()') NULL

Sintaxis modificada de ejemplo: ALTER COLUMN Gender ADD MASKED WITH (FUNCTION = 'default()')
Email Método de enmascaramiento que expone la primera letra de una dirección de correo electrónico y el sufijo constante ".com", en el formato de una dirección de correo electrónico. aXXX@XXXX.com. Ejemplo de sintaxis de definición: Email varchar(100) MASKED WITH (FUNCTION = 'email()') NULL

Sintaxis modificada de ejemplo: ALTER COLUMN Email ADD MASKED WITH (FUNCTION = 'email()')
Random Una función de enmascaramiento aleatorio que se puede usar con cualquier tipo numérico a fin de enmascarar el valor original con uno aleatorio dentro de un intervalo especificado. Ejemplo de sintaxis de definición: Account_Number bigint MASKED WITH (FUNCTION = 'random([start range], [end range])')

Sintaxis modificada de ejemplo: ALTER COLUMN [Month] ADD MASKED WITH (FUNCTION = 'random(1, 12)')
Cadena personalizada Método de enmascaramiento que expone la primera y última letra y agrega una cadena de relleno personalizada en el medio. prefix,[padding],suffix

Si el valor original es demasiado corto para completar toda la máscara, parte del prefijo o sufijo no se expone.
Ejemplo de sintaxis de definición: FirstName varchar(100) MASKED WITH (FUNCTION = 'partial(prefix,[padding],suffix)') NULL

Sintaxis modificada de ejemplo: ALTER COLUMN [Phone Number] ADD MASKED WITH (FUNCTION = 'partial(1,"XXXXXXX",0)')

Esto convierte un número de teléfono como 555.123.1234 en 5XXXXXXX.

Ejemplo adicional:

ALTER COLUMN [Phone Number] ADD MASKED WITH (FUNCTION = 'partial(5,"XXXXXXX",0)')

Esto convierte un número de teléfono como 555.123.1234 en 555.1XXXXXXX.
Datetime Se aplica a: SQL Server 2022 (16.x)

Método de enmascaramiento para columna definida con tipo de datos datetime, datetime2, date, time, datetimeoffset, smalldatetime. Ayuda a enmascarar la parte del día year => datetime("Y"), month=> datetime("M"), day=>datetime("D"), hour=>datetime("h"), minute=>datetime("m") o la parte del día seconds=>datetime("s").
Ejemplo de cómo enmascarar el año del valor datetime:

ALTER COLUMN BirthDay ADD MASKED WITH (FUNCTION = 'datetime("Y")')

Ejemplo de cómo enmascarar el mes del valor datetime:

ALTER COLUMN BirthDay ADD MASKED WITH (FUNCTION = 'datetime("M")')

Ejemplo de cómo enmascarar el minuto del valor datetime:

ALTER COLUMN BirthDay ADD MASKED WITH (FUNCTION = 'datetime("m")')

Permisos

Los usuarios con el permiso SELECT en una tabla, podrán ver los datos de esta. Las columnas que estén definidas como enmascaradas muestran datos enmascarados. Conceda el permiso UNMASK a un usuario para permitir que recupere datos sin enmascarar de las columnas para las que se ha definido una regla de enmascaramiento.

Los usuarios y roles administrativos siempre pueden ver los datos desenmascarados mediante el permiso CONTROL, que incluye el permiso ALTER ANY MASK y UNMASK. Los usuarios administrativos o roles como administrador del sistema, serveradmin o db_owner tienen permiso de CONTROL sobre la base de datos por diseño y pueden ver los datos no enmascarados.

No se necesita ningún permiso especial para crear una tabla con una máscara dinámica de datos, solo los permisos estándar de esquema CREATE TABLE y ALTER.

Para agregar, reemplazar o quitar la máscara de una columna, se precisan los permisos ALTER ANY MASK y ALTER (este último, en la tabla). Se recomienda otorgar ALTER ANY MASK a un responsable de seguridad.

Nota:

El permiso UNMASK no influye en la visibilidad de los metadatos: la concesión de UNMASK por sí sola no revela ningún metadato. Para que tenga efecto, UNMASK tendrá que ir acompañado de un permiso SELECT. Por ejemplo, si se concede UNMASK en el ámbito de la base de datos y se concede SELECT en una tabla individual, el usuario solo podrá ver los metadatos de la tabla individual en la que puede realizar una selección, no de otras. Consulte también Configuración de visibilidad de los metadatos.

Procedimientos recomendados y casos de uso habituales

  • La creación de una máscara en una columna no impide que se efectúen actualizaciones en ella. De modo que, aunque los usuarios recibirán datos enmascarados cuando realicen una consulta en una columna enmascarada, ellos mismos podrán actualizar los datos si cuentan con permisos de escritura. Aun así, se debe usar una directiva de control de acceso adecuada para limitar los permisos de actualización.

  • El uso de SELECT INTO o INSERT INTO para copiar datos de una columna enmascarada en otra tabla da como resultado datos enmascarados en la tabla de destino (suponiendo que la exporte un usuario sin privilegios UNMASK).

  • El enmascaramiento dinámico de datos se aplica al ejecutar la importación y exportación de SQL Server. Una base de datos que contiene columnas enmascaradas da como resultado un archivo de datos exportado con datos enmascarados (suponiendo que lo exporte un usuario sin privilegios UNMASK), y la base de datos importada contendrá datos enmascarados estáticamente.

Consulta de columnas enmascaradas

Use la vista sys.masked_columns para consultar las columnas de la tabla a las que se ha aplicado una función de enmascaramiento. Esta vista hereda de la vista sys.columns. Devuelve todas las columnas de la vista sys.columns, además de las columnas is_masked y masking_function, indicando si la columna está enmascarada y, en caso afirmativo, qué función de enmascaramiento está definida. Esta vista solo muestra las columnas en las que se ha aplicado la función de enmascaramiento.

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;

Limitaciones y restricciones

Los usuarios con CONTROL SERVER o CONTROL a nivel de base de datos podían ver los datos enmascarados en su forma original. Esto incluye usuarios administradores o roles como administrador del sistema, serveradmin, db_owner, etc.

No se puede definir una regla de enmascaramiento para los siguientes tipos de columnas:

  • Columnas cifradas (siempre cifradas)

  • FILESTREAM

  • COLUMN_SET o una columna dispersa que forme parte de un conjunto de columnas.

  • No se puede configurar un enmascaramiento en una columna calculada, pero si la columna calculada depende de una columna con MASK, entonces la columna calculada devuelve datos enmascarados.

  • Una columna con enmascaramiento de datos no puede ser una clave para un índice FULLTEXT.

  • Columna de una tabla externade PolyBase.

Para los usuarios sin el permiso UNMASK, las instrucciones en desuso READTEXT, UPDATETEXT y WRITETEXT no funcionan adecuadamente en una columna configurada para el enmascaramiento dinámico de datos.

Agregar una máscara dinámica de datos se implementa como un cambio de esquema en la tabla subyacente y, por lo tanto, no puede realizarse en una columna con dependencias (por ejemplo, una columna a la que hace referencia una columna calculada). Si se intenta agregar máscara de datos dinámica en columnas con dependencia, se producirá un error, ALTER TABLE ALTER COLUMN _columnname_ failed because one or more objects access this column. Para trabajar en torno a esta restricción, primero puede quitar la dependencia y, después, agregar la máscara dinámica de datos y volver a crear la dependencia. Por ejemplo, si la dependencia se debe a un índice que depende de esa columna, puede quitar el índice, después agregar la máscara y, luego, volver a crear el índice dependiente.

Siempre que proyecte una expresión que haga referencia a una columna para la que se haya definido una función de enmascaramiento de datos, la expresión también se enmascarará. Independientemente de la función (valor predeterminado, correo electrónico, cadena aleatoria o cadena personalizada) utilizada para enmascarar la columna a la que se hace referencia, la expresión resultante siempre se enmascarará con la función predeterminada.

No proporcionan resultados correctos las consultas cruzadas entre bases de datos que abarcan dos bases de datos Azure SQL diferentes ni bases de datos hospedadas en instancias diferentes de SQL Server y que impliquen cualquier tipo de operación de comparación o de combinación en columnas MASKED. Los resultados devueltos desde el servidor remoto ya están en formato MASKED y no son adecuados para cualquier tipo de operación de comparación o de combinación localmente.

Nota:

No se admite el enmascaramiento dinámico de datos cuando se hace referencia a la tabla base subyacente en una vista indizada.

Nota de seguridad: Omisión del enmascaramiento con técnicas de fuerza bruta o inferencia

El enmascaramiento dinámico de datos está diseñado para simplificar el desarrollo de aplicaciones limitando la exposición de datos en un conjunto de consultas predefinidas usadas por la aplicación. A pesar de que el enmascaramiento dinámico de datos también puede ser útil para evitar la exposición accidental de información confidencial cuando se obtiene acceso directo a una base de datos de producción, es importante tener en cuenta que los usuarios sin privilegios y que tienen permisos de consulta ad hoc pueden aplicar técnicas para obtener acceso a los datos. Si fuera necesario conceder este tipo de acceso ad hoc, debería usarse la auditoría para supervisar toda la actividad de la base de datos y mitigar este escenario.

Por ejemplo, considere una entidad de seguridad de base de datos con los privilegios suficientes para ejecutar consultas ad hoc en la base de datos y que intenta "adivinar" los datos subyacentes y, en última instancia, inferir los valores reales. Suponga que tenemos una máscara definida en la columna [Employee].[Salary], este usuario se conecta directamente a la base de datos, comienza a adivinar los valores y, a la larga, infiere el valor [Salary] en la tabla Employees:

SELECT ID, Name, Salary FROM Employees
WHERE Salary > 99999 and Salary < 100001;
Identificador Nombre Salario
62543 Jane Doe 0
91245 John Smith 0

Esto demuestra que el enmascaramiento dinámico de datos no se debe usar por sí sola para proteger completamente la información confidencial frente a los usuarios que ejecutan consultas ad hoc en la base de datos. Es adecuado para evitar la exposición accidental de datos confidenciales, pero no protege contra las intenciones maliciosas de deducir los datos subyacentes.

Es importante administrar adecuadamente los permisos en la base de datos y seguir el principio de mínimos permisos requeridos. Además, recuerde tener habilitada la auditoría para hacer seguimiento de todas las actividades que se realizan en la base de datos.

Permisos granulares introducidos en SQL Server 2022

A partir de SQL Server 2022 (16.x), puede evitar el acceso no autorizado a datos confidenciales y obtener el control enmascarándolo a un usuario no autorizado en diferentes niveles de la base de datos. Puede conceder o revocar el permiso UNMASK a nivel de base de datos, a nivel de esquema, a nivel de tabla o a nivel de columna a un usuario, rol de base de datos, identidad de Microsoft Entra o grupo de Microsoft Entra. Esta mejora proporciona una manera más granular de controlar y limitar el acceso no autorizado a los datos almacenados en la base de datos, y de mejorar la administración de la seguridad de los datos.

Ejemplos

Crear un enmascaramiento dinámico de datos

En el siguiente ejemplo se crea una tabla con tres tipos distintos de máscaras dinámicas de datos. En el ejemplo se rellena la tabla y se selecciona que se muestre el resultado.

-- 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

Se crea un nuevo usuario, a quien se le otorga el permiso SELECT en el esquema donde reside la tabla. En las consultas ejecutadas como el usuario MaskingTestUser , los datos se mostrarán enmascarados.

CREATE USER MaskingTestUser WITHOUT LOGIN;

GRANT SELECT ON SCHEMA::Data TO MaskingTestUser;
  
-- impersonate for testing:
EXECUTE AS USER = 'MaskingTestUser';

SELECT * FROM Data.Membership;

REVERT;

El resultado demuestra que las máscaras funcionan, ya que cambia los datos de esto:

1 Roberto Tamburello 555.123.4567 RTamburello@contoso.com 10

en:

1 Rxxxxxo Tamburello xxxx RXXX@XXXX.com 91

donde el número de DiscountCode es aleatorio para los resultados de cada consulta.

Agregar o editar una máscara en una columna existente

Utilice la instrucción ALTER TABLE para agregar una máscara a una columna existente de la tabla o a fin de editarla en dicha columna.
En el siguiente ejemplo, se agrega la función de enmascaramiento a la columna LastName:

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

En el siguiente ejemplo se cambia la función de enmascaramiento en la columna LastName :

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

Conceder permisos para ver datos no enmascarados

Si se otorga el permiso UNMASK , MaskingTestUser podrá ver los datos sin enmascarar.

GRANT UNMASK TO MaskingTestUser;

EXECUTE AS USER = 'MaskingTestUser';

SELECT * FROM Data.Membership;

REVERT;
  
-- Removing the UNMASK permission
REVOKE UNMASK TO MaskingTestUser;

Eliminar un Enmascaramiento dinámico de datos

La siguiente instrucción anula la máscara de la columna LastName creada en el ejemplo anterior:

ALTER TABLE Data.Membership
ALTER COLUMN LastName DROP MASKED;

Ejemplos de permiso granular

  1. Creación de un esquema que contenga tablas de usuario:

    CREATE SCHEMA Data;
    GO
    
  2. Creación de una tabla con columnas enmascaradas:

    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. Inserción de datos de ejemplo:

    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. Creación de un esquema que contenga tablas de servicio:

    CREATE SCHEMA Service;
    GO
    
  5. Creación de una tabla de servicios con columnas enmascaradas:

    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. Inserción de datos de ejemplo:

    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. Creación de diferentes usuarios en la base de datos:

    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. Concesión de permisos de lectura a los usuarios de la base de datos:

    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. Concesión de diferentes permisos UNMASK a los usuarios:

    --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. Consulta de los datos en el contexto del usuario ServiceAttendant:

    EXECUTE AS USER = 'ServiceAttendant';
    
    SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay
    FROM Data.Membership;
    
    SELECT MemberID, Feedback, Rating
    FROM Service.Feedback;
    
    REVERT;
    
  11. Consulta de los datos en el contexto del usuario ServiceLead:

    EXECUTE AS USER = 'ServiceLead';
    
    SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay
    FROM Data.Membership;
    
    SELECT MemberID, Feedback, Rating
    FROM Service.Feedback;
    
    REVERT;
    
  12. Consulta de los datos en el contexto del usuario ServiceManager:

    EXECUTE AS USER = 'ServiceManager';
    
    SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay
    FROM Data.Membership;
    
    SELECT MemberID, Feedback, Rating
    FROM Service.Feedback;
    
    REVERT;
    
  13. Consulta de los datos en el contexto del usuario ServiceHead

    EXECUTE AS USER = 'ServiceHead';
    
    SELECT MemberID, FirstName, LastName, Phone, Email, BirthDay
    FROM Data.Membership;
    
    SELECT MemberID, Feedback, Rating
    FROM Service.Feedback;
    
    REVERT;
    
  14. Para revocar permisos UNMASK, use las siguientes instrucciones 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;