ciberseguridad

TDE, Always Encrypted, TLS y DDM: cuándo usar cada uno

TDE, Always Encrypted, TLS y DDM: cuándo usar cada uno

Lo sé, llevo más de un mes sin publicar artículos en el blog. No ha sido precisamente porque se me haya olvidado escribir. He estado metido hasta el cuello preparando cursos y sacando adelante otros proyectos. Parece que no pero estas cosas consumen las horas con una eficacia admirable y una compasión nula. El canal de YouTube también lleva cerca de dos meses parado por lo mismo. Así que vamos a retomar ambas cosas poco a poco, con algo que además creo que merece la pena.

Hace unos días me dejaron un comentario bastante sensato en un vídeo antíguo donde explicaba cómo funciona TDE en SQL Server. @eadames2 venía a decir que el vídeo era demasiado básico y que faltaban ejemplos de vida real, contexto y, sobre todo, criterio para decidir qué método de cifrado conviene según el caso. Y sí, la observación es buena. En el vídeo enseñé el cómo. Hoy, aquí, toca hablar del cuándo y del para qué.

Sobre cifrado ya había publicado en el blog el artículo “Cifrado de datos en SQL Server”, donde repasaba TLS, TDE, Always Encrypted y DDM, y también otro texto sobre qué pasa con la inicialización instantánea de ficheros al habilitar TDE, que entra en una consecuencia operativa muy concreta. No voy a repetir aquí lo que ya está explicado allí. Lo que quiero hacer en este artículo es completar esa parte que muchas veces se queda fuera: cómo elegir bien según la amenaza real, el tipo de datos y el precio operativo que estamos dispuestos a pagar.

Antes de entrar en tecnologías concretas, conviene poner orden en una idea que suele venir torcida de fábrica.

El error habitual: elegir tecnología antes de definir la amenaza

Cuando alguien dice que quiere “cifrar la base de datos”, casi nunca está describiendo un requisito. Está describiendo una intuición. Y las intuiciones, en seguridad, suelen ser un punto de partida aceptable y un punto de llegada desastroso.

No es lo mismo proteger datos frente al robo de backups que impedir que un DBA vea una información concreta. Tampoco es lo mismo ocultar información sensible a usuarios funcionales que proteger el tráfico entre aplicación y servidor. Meter todo eso en la misma cesta y resolverlo con una sola tecnología suele acabar como acaban estas cosas: con un checkbox marcado, una falsa sensación de seguridad y una reunión desagradable más adelante.

TDE, Always Encrypted, TLS y DDM no compiten entre sí en todos los escenarios. A veces se complementan y a veces uno no sirve absolutamente para nada si el problema real está en otra parte. Por eso la pregunta correcta no es “qué método cifra más”. La pregunta correcta es “de qué quiero protegerme exactamente y quién es el adversario aquí”.

Ese matiz cambia bastante la conversación, así que vamos con casos reales.

Caso real 1: alguien roba un backup o se lleva los ficheros de la base de datos

Aquí es donde TDE encaja muy bien. Si tu preocupación principal es que alguien coja un .bak, un .mdf, un .ndf o un .ldf y se lo lleve alegremente a otro servidor para restaurarlo sin permiso, TDE es una solución razonable y bastante transparente.

La gran ventaja de TDE es precisamente esa, protege los datos en reposo sin obligarte a rediseñar la aplicación ni a reescribir consultas. El usuario legítimo sigue trabajando igual, y el motor cifra y descifra por debajo. En entornos corporativos donde el riesgo está en el acceso físico a discos, en copias de seguridad mal custodiadas o en procedimientos de restauración fuera de control, TDE tiene muchísimo sentido.

Ahora bien, conviene no pedirle milagros. TDE no evita que alguien con acceso lógico a la base de datos y permisos suficientes consulte los datos. No te protege de un SELECT bien autorizado, ni de un desarrollador con más privilegios de los que debería, ni de ese clásico “es solo para una prueba” que termina con un usuario leyendo más de la cuenta. TDE protege archivos y backups. No arregla un modelo de permisos chapucero, que es otra afición muy extendida.

Además, TDE tiene peaje. Ya conté en el artículo sobre inicialización instantánea de ficheros que al activarlo perdemos ciertas ventajas operativas y podemos notar impacto en crecimientos, restauraciones y tiempos de ciertas operaciones. Y hay otro punto que en las demos parece un detalle y en producción no lo es, el certificado. Si no haces backup del certificado y de su clave privada, el día que necesites restaurar en otro servidor te puedes ahorrar el café, porque no vas a restaurar nada. Si cifras con TDE y no haces copia de seguridad del certificado y de su clave privada, tu backup queda protegido incluso contra ti mismo. Muy seguro todo. Muy poco práctico también.

No todos los escenarios exigen llegar tan lejos. A veces el problema no es que alguien robe un backup, sino que ciertos usuarios ven más de lo que deberían ver en el día a día.

Caso 2: algunos usuarios no deberían ver los datos completos

Aquí entra DDM, y aquí conviene hablar sin maquillaje, porque bastante tiene la tecnología con el suyo propio. Dynamic Data Masking no es cifrado. Sirve para ocultar parcialmente datos cuando los consulta un usuario que no tiene permiso para verlos completos, pero el dato sigue estando almacenado tal cual en la base de datos.

Eso puede ser útil. En entornos de soporte, atención al cliente, explotación o consultas operativas, muchas veces necesitamos que ciertos perfiles trabajen con datos reales sin exponerles el valor completo de una columna sensible. Mostrar parte de un correo, ocultar tramos de un teléfono o limitar la visualización de un identificador puede tener bastante sentido. Reduce la exposición innecesaria y evita errores humanos bastante previsibles.

El problema viene cuando alguien intenta vender DDM como si resolviera necesidades de seguridad de alto nivel. No. DDM no protege un backup robado, no impide que el motor lea el dato y no sustituye ni a TDE ni a Always Encrypted. Lo que hace es modificar la presentación del dato para determinados usuarios. Nada más. Nada menos. Y mientras entendamos eso, puede ser perfectamente válido.

En otras palabras: si tu requisito es “que el personal de soporte no vea el valor completo del documento de identidad”, DDM puede encajar. Si tu requisito es “que nadie pueda extraer el dato real de la base si accede a los ficheros” o “que ni siquiera ciertos administradores puedan verlo”, entonces DDM no te sirve. Ahí ya estarías usando una cortina para parar un incendio, que tiene un punto optimista, pero poca eficacia.

A veces, sin embargo, el nivel de exigencia sube bastante más. Y en ese punto ya no basta con ocultar visualmente una parte del dato.

Caso 3: ni siquiera el DBA debería ver ciertos datos

Cuando el requisito es que ni siquiera un administrador de base de datos pueda consultar ciertos valores en claro, TDE y DDM se quedan cortos por definición. TDE porque el motor necesita descifrar la información para trabajar con ella. DDM porque solo maquilla la salida para algunos usuarios. Si el objetivo es separar de verdad quién puede ver el dato y quién solo puede administrarlo, entonces toca mirar Always Encrypted.

Always Encrypted está pensado para columnas concretas y para escenarios donde los datos son especialmente sensibles. Hablamos de información médica, datos financieros, salarios, identificadores personales o cualquier campo donde el requisito no sea simplemente proteger discos y copias de seguridad, sino impedir que ciertos perfiles con acceso a la infraestructura puedan leer el valor real. Es una diferencia importante.

La gracia de Always Encrypted está precisamente en esa separación. Las claves no se gestionan como en TDE y el modelo de confianza cambia bastante. Eso hace que el nivel de protección sea superior en algunos escenarios, pero también introduce complejidad técnica. No todas las consultas pueden hacerse igual, no todas las operaciones son cómodas y el desarrollo de la aplicación tiene que convivir con esas limitaciones. Vamos, que no es una opción para activar con alegría y descubrir el lunes que media aplicación ya no hace lo que hacía.

¿Merece la pena? Cuando el requisito lo exige, sí. Sin duda. Pero si solo quieres proteger backups o discos, meter Always Encrypted porque suena más serio es un error clásico. Aún hay quien cree que la mejor solución de seguridad es siempre la más compleja. 

Hasta ahora hemos hablado de datos en reposo o de visibilidad dentro de la propia base. Pero queda una capa distinta, y conviene separarla para no mezclar churras con certificados.

Caso real 4: el problema está en la red, no en el disco

Si los datos viajan entre cliente y servidor, o entre servicios, y tu preocupación es que alguien intercepte ese tráfico, entonces lo que necesitas mirar es TLS. Ni TDE ni DDM ni Always Encrypted sustituyen el cifrado del canal de comunicación.

Esto es importante porque sigue habiendo entornos donde alguien activa TDE y se queda tan tranquilo, como si eso protegiera automáticamente el tráfico por red. No. Cifrar el archivo de base de datos no convierte mágicamente en segura una conexión mal configurada. Son capas distintas y problemas distintos.

TLS es el mecanismo adecuado para proteger datos en tránsito. Si tienes aplicaciones conectadas por red, servicios hablando entre sí, réplicas, integraciones o accesos remotos, necesitas que el canal vaya cifrado y, si puede ser, bien configurado. Lo contrario es confiar en que nadie mire. Una estrategia audaz, desde luego, aunque no especialmente profesional.

En muchos sistemas reales, de hecho, la respuesta correcta no es elegir una sola opción, sino combinar varias con un poco de sentido común.

Lo normal en producción: combinar tecnologías según el riesgo real

La mayoría de entornos serios no viven de absolutos. Viven de compromisos bien pensados. Y eso significa que muchas veces la solución buena no es “TDE o Always Encrypted”, sino “TDE y además TLS”, o “TLS para todo el tráfico y DDM para ciertos usuarios de soporte”, o incluso “TDE para la base completa y Always Encrypted en columnas concretas especialmente sensibles”.

Un ERP corporativo puede necesitar TDE para proteger backups y discos, TLS para las conexiones y un modelo de permisos competente. Un sistema de recursos humanos probablemente necesite además evaluar Always Encrypted en campos muy concretos. Una herramienta de soporte interno puede apoyarse en DDM para limitar lo que ciertos perfiles ven en pantalla, sin vender eso como la octava maravilla de la seguridad.

La decisión, por tanto, no depende tanto del “tipo de base de datos” en abstracto como del tipo de dato, del modelo de acceso y del riesgo que quieres mitigar. Una base de datos de facturación interna y una de analítica pueden tener tamaños parecidos y una necesidad de protección totalmente distinta. El nombre del sistema importa menos que la exposición del dato y las personas que pueden tocarlo.

Con todo esto encima de la mesa, ya se puede responder de forma más útil a la pregunta del comentario.

Entonces, ¿qué método conviene según el caso?

Si lo que te preocupa es el robo de copias de seguridad o de archivos físicos, empieza por TDE. Es la opción natural, tiene un impacto asumible en muchos entornos y protege precisamente ese escenario. Si además activas TDE, haz bien el trabajo completo: gestiona certificados, documenta el procedimiento de recuperación y prueba restauraciones. Porque un TDE sin backup del certificado es una bomba de relojería con modales.

Si el problema es que determinados datos no deberían estar visibles ni para personal con privilegios altos en la infraestructura, entonces TDE no basta y hay que mirar Always Encrypted. Aquí la complejidad sube, sí, pero también lo hace el nivel de aislamiento real.

Si lo que necesitas es limitar lo que ven ciertos usuarios operativos sin cambiar la aplicación de arriba abajo, DDM puede ser útil, sabiendo perfectamente que no estás cifrando nada. Y si la preocupación es el tráfico entre cliente y servidor, no des más rodeos y configura TLS como corresponde.

Dicho de otra manera: TDE protege datos en reposo a nivel de archivos y backups. Always Encrypted protege columnas frente a accesos que no deberían ver el valor real. DDM limita exposición visual en consultas para ciertos perfiles. TLS protege el canal de comunicación. Confundirlos es bastante común. Elegirlos bien ya no debería serlo tanto.

Conclusión

El comentario de @eadames2 iba bien encaminado: enseñar a activar TDE está bien, pero no basta si no explicamos cuándo tiene sentido usarlo y cuándo no. En seguridad, la tecnología correcta no es la más llamativa ni la más compleja, sino la que responde a la amenaza real sin convertir la operación diaria en una penitencia.

Ya tenemos en el blog el artículo general sobre cifrado en SQL Server y el análisis del impacto de TDE sobre la inicialización instantánea de ficheros. Este texto viene a completar esa parte que faltaba: el criterio. Porque cifrar por cifrar sirve de poco. Lo útil es saber qué proteges, de quién lo proteges y cuánto te va a costar mantenerlo. Lo demás es decorar el problema con terminología bonita y esperar que nadie haga demasiadas preguntas.

Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de Telegram y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

Publicado por Roberto Carrancio en Cloud, SQL Server, 0 comentarios

Nueva caché de seguridad en SQL Server 2025

Llevamos ya tiempo con la preview de SQL Server 2025 probando todas las novedades. La lista es larga y, a veces, cuesta distinguir entre lo realmente útil y lo puramente decorativo. Entre tanto brillo marketiniano, hay una mejora de la que no se ha hablado, que muchos pasarán por alto sin comprender las implicaciones, pero que a mi me ha hecho sonreír y decir: “Ya era hora”. Os hablo de la nueva capacidad de invalidar cachés de seguridad de forma específica por inicio de sesión en SQL Server 2025. Y sí, es tan buena como suena.

¿Qué es esto de la caché de seguridad?

Antes de meternos en harina, conviene recordar qué es exactamente esa “caché de seguridad” que ahora Microsoft ha afinado. Cuando un usuario se conecta a SQL Server, el motor evalúa qué permisos tiene para acceder a objetos, ejecutar procedimientos, ver datos… ya sabéis, lo básico para evitar que todo sea un buffet libre de SELECT * FROM SensitiveTable.

Como no somos tontos (y SQL Server tampoco), esta validación no se repite cada vez que alguien lanza una consulta. Sería un suicidio en términos de rendimiento. En su lugar, SQL Server guarda esa información en memoria (en la famosa security cache) y la reutiliza mientras no haya cambios que invaliden su contenido.

¿El problema? Hasta ahora era muy sensible. Si cambiabas cualquier permiso de cualquier usuario (cambio de permisos, modificación de roles, o revocar un acceso), se eliminaban todas las entradas DE TODOS LOS USUARIOS. Esto, por supuesto, tiene efectos inmediatos en el rendimiento de cualquier sesión abierta, aunque no tuviera nada que ver con el cambio.

Vamos, que tirábamos la caché como quien reinicia un servidor por si acaso: por pura desesperación.

SQL Server 2025 trae cordura: invalidación específica por login

Con la llegada de SQL Server 2025, se acabó el “todo o nada”. Ahora, cuando se invalidan entradas de la caché de seguridad debido a un cambio en los permisos, el sistema es lo bastante listo como para borrar solo las entradas correspondientes al login afectado. El resto permanece intacto.

Esto supone una mejora directa en varios frentes. Para empezar, reduce el impacto de cualquier cambio de seguridad. No hay invalidaciones masivas innecesarias, no se resienten las sesiones de otros usuarios, y la CPU no se dispara validando de nuevo cientos o miles de entradas de permisos para conexiones que no han cambiado ni una coma de sus privilegios.

¿Por qué esto importa? Rendimiento, escalabilidad y menos sustos

Puede parecer que un cambio de estas características no tiene mucha importancia, y así es entornos con pocos usuarios y permisos bastante genericos. Pero cuando el volumen de usuarios y la granularidad de los permisos son considerables, la diferencia entre invalidar toda la caché de seguridad y hacerlo de forma selectiva puede marcar la diferencia. En entornos con cientos o miles de sesiones concurrentes, la diferencia es tan evidente como entre ejecutar SELECT con un índice… o sin él.

Antes, un cambio puntual en los permisos podía convertirse en una mini tormenta de validaciones. La CPU subía, la latencia aumentaba, y tú te encontrabas explicando por qué un GRANT a las 9:30 había dejado la aplicación más lenta que un Access con macros durante unos minutos. Todo eso queda en el pasado con esta nueva implementación.

Ahora, si revocas un permiso a un usuario que ya estaba conectado, SQL Server se limita a eliminar sus entradas específicas de la caché. El resto de usuarios ni se enteran. Y tú tampoco tendrás que revisar gráficos de rendimiento preguntándote qué demonios ha pasado.

Cambios de roles, miembros de grupos y lo que siempre duele

Uno de los escenarios donde esto brilla especialmente es cuando se hace una modificación en roles o membresías de grupos. Añadir o quitar a alguien de un db_datareader, por ejemplo, solía ser sinónimo de purgar toda la caché de seguridad.

Con SQL Server 2025, eso se acabó. La limpieza de la caché se ciñe a ese login concreto, incluso si el cambio afecta a una membresía en roles de servidor o roles personalizados. Menos interrupciones, menos recompilaciones internas, y más estabilidad.

Que sí, que aún quedan muchos elementos que provocan recompilaciones y limpiezas de caché que no siempre tienen sentido, pero al menos aquí han puesto orden en una de las áreas más olvidadas por el motor en versiones anteriores.

¿Cómo saber si está funcionando?

No hay un nuevo DMV mágico que diga “estás disfrutando de la nueva caché de seguridad personalizada”, pero si monitorizas el uso de CPU y el acceso concurrente durante cambios de permisos, deberías notar una mejora clara. Sobre todo en sistemas con mucha actividad concurrente y una gestión de seguridad activa.

Y si eso no te vale y quieres verlo con tus propios ojos siempre nos quedarán los eventos extendidos, esa magnífica herramienta que lo captura todo. Puedes crear una sesión que capture los nuevos eventos “login_token_cache_hit” que se producen cuando el token de la caché de seguridad sigue activo y el evento “login_token_cache_miss” que es cuando el token de la caché no es válido y hay que generar una nueva entrada.

Demo caché de seguridad 

Vamos a comprobar que esto realmente funciona. Para ello tenemos nuestros logins con ID 267 y 268 y vamos a crear una sesión de xEvents que capture los eventos que hemos comentado antes:

Lo primero que vamos a hacer es borrar la caché de seguridad:

Como hemos borrado la caché, estas dos primeras entradas generan un evento “login_token_cache_miss”, no existe registro en la caché. 

Pero, si volvemos a conectarnos veremos ya los hit, es decir ha utilizado el token existente en caché

Ahora vamos a cambiar los permisos de uno de los logins

Y al volver a conectar veremos solo uno de los dos logins tiene el miss y el otro mantiene su token válido (evento hit). Además veís en la captura que yo he añadido tambien los eventos “security_cache_login_timestamp_increment” a mi captura de eventos, que me indica cuando se ha producido un cambio de permisos.

¿Qué implicaciones tiene para nosotros como DBAs?

Básicamente, nos devuelve un poco de control. Ahora podemos aplicar cambios de seguridad sin tener miedo a provocar un alud de recompilaciones y penalizaciones de rendimiento. Se acabó el tener que programar revocaciones de permisos fuera del horario laboral o acompañarlas de una explicación de daños colaterales.

También nos da más seguridad en entornos de desarrollo y pruebas. Podemos simular escenarios de cambios de permisos sin el temor a que medio entorno colapse por culpa de una caché global destruida innecesariamente.

Eso sí, no todo es perfecto. La documentación oficial todavía no entra en muchos detalles sobre cómo se comporta esta nueva caché con escenarios complejos de impersonación (EXECUTE AS), certificados o permisos a nivel de esquema. Habrá que investigar (y ya lo haré en otro artículo si me lo pedís) si este comportamiento selectivo se extiende también a esos casos.

Conclusión

La invalidación selectiva de la caché de seguridad en SQL Server 2025 es una mejora tan lógica que sorprende que no estuviera ya implementada hace años. Pero aquí está, y funciona como debe. Nos da más precisión, menos impacto colateral y permite cambios de seguridad sin temor a convertir el servidor en una verbena de validaciones.

Como siempre, no es magia. Si haces cambios absurdos o con prisas, te seguirás metiendo en líos. Pero al menos, ahora, el motor te lo pone un poco menos difícil. Y eso, en este mundo de permisos, roles y DBA que no duermen, ya es bastante.

Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de Telegram y un canal de YouTube a los que te puede unir. ¡Hasta la próxima! 

Publicado por Roberto Carrancio en Rendimiento, SQL Server, 0 comentarios

Canalizaciones por nombre (Named Pipes) en SQL Server

Durante años, las canalizaciones por nombre (Named Pipes) han sido uno de esos protocolos de red que viven en las sombras de TCP/IP. Están ahí, aparecen en las configuraciones del SQL Server Configuration Manager, y de vez en cuando algún alma valiente pregunta si debería activarlas “por si acaso”. Y no, por si acaso no es un argumento válido en administración de sistemas, y mucho menos en bases de datos. Vamos a analizar qué son exactamente, cómo funcionan y en qué escenarios podrían tener sentido… si es que alguno queda en 2025.

¿Qué demonios son las canalizaciones por nombre?

Antes de decidir si las activamos o las dejamos durmiendo el sueño de los justos, conviene entender qué son. Las canalizaciones con nombre son un mecanismo de comunicación interprocesos (IPC) heredado del glorioso mundo de Windows NT. Permiten que dos procesos, incluso en máquinas diferentes, se comuniquen a través de una ruta virtual. En SQL Server, representan uno de los protocolos disponibles para aceptar conexiones de cliente.

Mientras que TCP/IP utiliza direcciones IP y puertos, Named Pipes utiliza una sintaxis como \\.\pipe\sql\query, y en red sería algo tipo \\Servidor\pipe\sql\query. Esta vía de comunicación puede ser más rápida en entornos muy controlados y locales (léase: conexión directa entre un cliente y un servidor dentro de la misma LAN y sin cuellos de botella), pero en la práctica actual… hay que hilar muy fino para justificar su uso.

TCP/IP vs Canalizaciones por nombre: ¿por qué seguimos hablando de esto?

La realidad es que TCP/IP es el protocolo estándar y recomendado para conexiones SQL Server, tanto en producción como en desarrollo. Es más robusto, más flexible, y más preparado para escenarios reales con múltiples capas de red, firewalls, balanceadores, NATs y demás fauna moderna.

Entonces, ¿por qué SQL Server sigue ofreciendo Named Pipes como opción? Por compatibilidad. Porque aún hay sistemas legacy que las usan. Y porque a Microsoft le cuesta soltar lastre tanto como a cualquiera que aún mantiene SQL Server 2008 en alguna esquina de su datacenter “temporal”.

Hay entornos donde, por motivos históricos o arquitecturas muy específicas, se configuraron conexiones a SQL Server utilizando Named Pipes. En esos casos, sí, deshabilitarlas podría romper algo. Pero esa es la excepción, no la norma.

¿Cuándo tienen sentido las Named Pipes?

Vale, no todo es blanco o negro. Hay escenarios, pocos pero existentes, donde las canalizaciones por nombre pueden tener cierta ventaja:

  • Conexiones locales (cliente y servidor en la misma máquina): En algunos benchmarks internos de Microsoft (de hace más de una década nada menos), se observó que el rendimiento de Named Pipes en conexiones locales era ligeramente superior al de TCP/IP. Pero, francamente, si ese es tu cuello de botella, tienes problemas mayores.
  • Autenticación integrada en entornos Windows puros: Las canalizaciones por nombre pueden simplificar ciertos escenarios de autenticación integrada en entornos totalmente controlados por Active Directory. Pero otra vez: TCP/IP también lo hace sin problemas.
  • Entornos legacy que no quieres (o puedes) tocar: Si tienes una aplicación que explícitamente se conecta usando np: o configuraciones hardcoded de canalizaciones con nombre, y no puedes modificarla… entonces no queda otra que habilitarlas.
  • Solución de problemas puntuales: En algunos casos, cuando el acceso por TCP/IP falla misteriosamente (DNS, puertos bloqueados, fuegos en el CPD…), usar Named Pipes puede servir para diagnosticar si SQL Server sigue vivo y coleando.

Pero si tu escenario no cae en alguno de estos puntos, las Named Pipes sobran.

Cómo funcionan realmente las canalizaciones por nombre

Cuando habilitas Named Pipes en SQL Server, el motor escucha en una canalización concreta: \\.\pipe\sql\query por defecto. El cliente debe conectarse utilizando ese nombre. Lo que muchos no saben es que esto no solo requiere que el cliente conozca la sintaxis, sino también que la resolución de nombres esté bien configurada (en red), y que no haya firewalls bloqueando el tráfico correspondiente.

Además, en entornos remotos, el protocolo puede comportarse de forma bastante torpe: mayor latencia en la negociación, más complejidad en el tráfico de red, y más exposición a errores difíciles de diagnosticar. Si te suena a dolor de cabeza… es porque lo es.

¿Qué pasa si dejo las canalizaciones por nombre activadas “por si acaso”?

Esto es como dejar todas las ventanas de casa abiertas por si te olvidas las llaves. En teoría podría ayudarte, pero en la práctica te estás exponiendo innecesariamente. Habilitar las canalizaciones por nombre sin necesitarlas abre un vector de ataque innecesario (sí, también hablamos de superficie de ataque), complica el troubleshooting de conexiones, y puede provocar que clientes mal configurados intenten conectar usando este protocolo en lugar de TCP/IP.

Por si fuera poco, cuando están activadas, SQL Server puede priorizarlas en la cadena de protocolos, lo que lleva a situaciones surrealistas como que un cliente tarde más de la cuenta en conectarse porque está intentando usar Named Pipes antes que TCP/IP.

Lo peor de todo es que, en redes modernas, usar Named Pipes puede ralentizar la conexión en lugar de mejorarla. Así que eso de activarlas para “ganar velocidad” es un mito que ya deberíamos haber dejado atrás con el disquete.

¿Y si las necesito, cómo las activo (o desactivo)?

Si a pesar de todo necesitas activar Named Pipes, el proceso es sencillo, pero no inmediato. Desde SQL Server Configuration Manager, accede al protocolo correspondiente bajo SQL Server Network Configuration, y ahí puedes habilitarlas o deshabilitarlas. Necesitarás reiniciar el servicio SQL Server para que los cambios tengan efecto.

Además, si vas a usarlas, asegúrate de configurar también correctamente la cadena de conexión en el cliente, usando el prefijo np: para forzar que se utilicen Named Pipes.

Y, por supuesto, monitoriza. No asumas que todo va mejor solo porque te conectaste. Comprueba latencias, errores, y la experiencia real del usuario. Porque los milagros no vienen de las canalizaciones.

¿Qué protocolo prioriza SQL Server?

El orden de los protocolos es importante. SQL Server Native Client (o el driver OLE DB / ODBC que uses) sigue un orden al intentar conectar, salvo que lo fuerces. Ese orden se define también en SQL Server Configuration Manager, y puedes modificarlo.

Si dejas Named Pipes activado y en primer lugar, el cliente intentará primero por ahí antes de probar TCP/IP. Si Named Pipes no está disponible o hay problemas de red, el tiempo de espera puede incrementarse de forma absurda. ¿Te suenan esas conexiones que tardan 20 segundos solo en conectar? Pues eso.

Conclusión

Las canalizaciones por nombre son como el fax, aún existen, aún funcionan, y hay quien defiende que tienen utilidad. Pero en la mayoría de escenarios modernos con SQL Server, no hay ninguna razón técnica sólida para tenerlas activadas si no se están usando.

No aportan ventaja real frente a TCP/IP, complican el diagnóstico, abren superficie de ataque, y pueden ralentizar la conexión. Si tu entorno las requiere, adelante, pero hazlo con conocimiento de causa. Si no sabes para qué las necesitas, es que no las necesitas.

Apaga las Named Pipes, reinicia tu SQL Server y duerme tranquilo sabiendo que has reducido complejidad innecesaria.

Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de LinkedIn y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

Publicado por Roberto Carrancio en SQL Server, 0 comentarios

El libro de SQL Server que estabas esperando

Después de más de una década trabajando con SQL Server y ahora compartiendo contenido en SoyDBA, estoy escribiendo un libro pensado para profesionales que quieren ir más allá de la documentación oficial. Un libro técnico y muy didáctico.

Más de 40 capítulos en 7 partes, desde los fundamentos del modelo relacional hasta las herramientas de diagnóstico más avanzadas. Un recorrido completo, pensado para DBAs, analistas y desarrolladores que quieren entender cómo funciona SQL Server de verdad.

Portada Libro

El prólogo lo firma Fernando G. Guerrero, pionero y referente en nuestra comunidad. La contraportada, Juanjo Luna, MVP de Access y más apasionado de SQL de lo que quiere reconocer. Os dejo aquí el texto de la contraportada:

Si quieres conseguirlo corre a Amazón.

El libro está disponible en Amazon en formato papel y Kindle en todo el mundo.

Mantente al día de las novedades con mi newsletter gratuita

Logo SoyDBA

Únete a la newsletter de SoyDBA

Regístrate gratis para no perderte ninguna novedad. Te avisaré de noticias y eventos importantes

¡No hacemos spam! Lee nuestra política de privacidad para obtener más información.

Publicado por Roberto Carrancio en Alta Disponibilidad, Cloud, Índices, Rendimiento, SQL Server, 0 comentarios

Backups en SQL Server Always On y novedades en SQL Server 2025

Llevamos años con Always On sobre la mesa, vendiéndolo como la solución de alta disponibilidad y recuperación ante desastres por excelencia en entornos SQL Server. Cuando alguien monta un Availability Group por primera vez, suele pensar que ya tiene resuelta la alta disponibilidad, la recuperación ante desastres, los backups, el estrés y la hipoteca. Y no es mentira, pero tampoco es magia. Quienes lo gestionamos sabemos que montar un AG (Availability Group) es fácil en demos, pero bastante más delicado en producción. Always On resuelve cosas, sí, pero también introduce otras que hay que entender, especialmente cuando hablamos de estrategias de backup.

Y es que, hasta ahora, hacer backups en réplicas secundarias era poco más que un “parche”. Con SQL Server 2025, Microsoft ha introducido una mejora que, aunque llega tarde, se agradece: la posibilidad de hacer backups completos, diferenciales y de logs directamente sobre una réplica secundaria. Vamos a ver qué cambia exactamente y cómo podemos (por fin) diseñar estrategias de backup decentes en entornos Always On.

¿Dónde se hacen los backups en un Availability Group?

Empecemos con lo básico, que no es tan obvio como parece. En un AG, todas las réplicas tienen una copia de la base de datos, pero no todas son iguales ni sirven para todo. A la hora de hacer backups, SQL Server nos permite controlar el comportamiento a través de dos configuraciones clave:

AUTOMATED_BACKUP_PREFERENCE: una propiedad del Availability Group que indica en qué réplica se deben lanzar los backups automáticos (es decir, los lanzados mediante SQL Server Agent, Maintenance Plans, etc.). Esta propiedad puede tomar los valores:

  • PRIMARY: sólo se hacen backups en la réplica primaria.
  • SECONDARY_ONLY: sólo se hacen en las réplicas secundarias.
  • SECONDARY: se prefiere una secundaria, pero se usa la primaria si no hay otra disponible.
  • NONE: no hay preferencia definida, el agente decide.

BACKUP_PRIORITY: una propiedad individual de cada réplica que define su peso relativo a la hora de ser elegida para realizar los backups, si hay varias candidatas disponibles según la preferencia anterior.

Con estas dos configuraciones combinadas, SQL Server decide en qué réplica ejecutar los backups cuando se utilizan herramientas automatizadas. Pero ojo: si ejecutas el backup manualmente (T-SQL, PowerShell, etc.), se lanza en la réplica donde estés conectado. Lo de la preferencia solo aplica en los automatismos.

Logo SoyDBA

Únete a la newsletter de SoyDBA

Regístrate gratis para no perderte ninguna novedad. Te avisaré de noticias y eventos importantes

¡No hacemos spam! Lee nuestra política de privacidad para obtener más información.

Tipos de backups permitidos hasta SQL Server 2022

Ahora bien, no todos los tipos de backup están permitidos en todas las réplicas. Hasta SQL Server 2022 (incluido), las reglas eran bastante limitantes.

Los backups completos (FULL) sólo están permitidos en la réplica primaria, salvo que sean COPY_ONLY, en cuyo caso sí se pueden hacer en réplicas secundarias. Los backups diferenciales (DIFFERENTIAL) tienen el mismo “problema”, únicamente se pueden hacer en la primaria. Por el contrario, los backups de log (TRANSACTION LOG) si se pueden hacer en cualquier réplica (primaria o secundaria), siempre que esté en estado sincronizado o aceptable. Y son válidos como parte de la cadena de recuperación.

En resumen, solo los logs son realmente “migrables” a réplicas secundarias de forma productiva. El resto, si no es COPY_ONLY, requiere pasar por la primaria. Y como ya sabemos, los COPY_ONLY no afectan a la cadena de backups, por lo que no sirven como parte del plan de recuperación principal.

Este escenario genera el clásico problema, la carga de los backups importantes (full y diff) sigue recayendo en la réplica primaria, justo la que está ejecutando cargas de producción críticas. Y claro, luego vienen los lloros por I/O, CPU y ventanas de mantenimiento.

¿Qué cambiará en los backups de AG con SQL Server 2025?

Aquí llega la buena noticia. A partir de SQL Server 2025 (en preview), Microsoft amplía por fin el soporte de backups en réplicas secundarias. Y esta vez de verdad: Ya se podrán hacer backups FULL, DIFFERENTIAL y LOG en réplicas secundarias. Y no en modo COPY_ONLY, sino como parte activa de la cadena de recuperación.

Esto significa que podremos rediseñar completamente nuestra estrategia de backups en entornos Always On. Por ejemplo, podremos mover el backup completo diario a una secundaria, programar los diferenciales en otra y dejar los logs en una tercera. Todo sin tocar la primaria.

Y lo mejor es que no habrá que cambiar nada en la configuración actual del AG. Si ya tenemos configurado AUTOMATED_BACKUP_PREFERENCE = SECONDARY_ONLY y hemos definido prioridades con BACKUP_PRIORITY, esas mismas reglas se aplicarán también a full y diferenciales. Lo único que cambia es lo que SQL Server permitirá hacer técnicamente en cada réplica.

Cómo configurarlo (y cómo comprobarlo)

La configuración es la misma de siempre, para ver el valor actual de la preferencia de backups del AG podemos usar:

Para ver la prioridad de backup por réplica:

Y, si necesitas modificar la preferencia:

Y podrás seguir usando la vista sys.dm_hadr_backup_is_preferred_replica para determinar en tiempo real cuál es la réplica preferida según la configuración actual. Ideal para integrarlo en scripts de backup personalizados.

Consideraciones importantes y limitaciones

Como todo cambio de este tipo, hay que tener claro qué implica antes de correr a modificar tus scripts. La réplica secundaria debe estar sincronizada y en estado ONLINE. No sirve una réplica desactualizada o en SUSPENDED. Por supuesto, el backup de log seguirá necesitando una cadena coherente. Como hasta ahora, puedes hacer logs desde réplicas secundarias, pero asegúrate de que tu estrategia de restauración tiene en cuenta su procedencia.

El restaurado no cambiará, si haces un FULL en una secundaria, un DIFF en otra y LOGs en una tercera, tendrás que restaurarlos todos en orden, desde sus respectivas ubicaciones. Esto requiere un buen control del sistema de almacenamiento y del catálogo de backups.

Por último, el rendimiento de las réplicas secundarias importa. No pienses que es buena idea mandar todos los backups a una secundaria con discos lentos y CPU de museo. Es posible, sí. Recomendable, no.

¿Cómo adaptar tu estrategia de backups?

Con esta mejora, por fin podremos plantear una estrategia de backups moderna para Always On, que de verdad aproveche la arquitectura del AG. Algunas ideas:

  • Mueve los FULL y DIFF a réplicas secundarias bien dimensionadas.
  • Mantén los LOGs distribuidos según disponibilidad, pero con control estricto del histórico.
  • Diseña tus planes de mantenimiento con tolerancia a failover: si una réplica cae, otra puede asumir su rol.

Eso sí, no pierdas de vista que toda esta flexibilidad requiere más disciplina. El seguimiento de los backups, la monitorización y la política de retención deben estar muy claros. Porque ahora no hay excusas: puedes repartir la carga, pero también puedes complicarte la vida si no lo haces bien.

Conclusión

SQL Server 2025 traerá una mejora largamente esperada. Por fin podremos hacer backups completos y diferenciales en réplicas secundarias, de forma nativa y como parte del plan de recuperación. No es un parche ni una opción limitada, es un cambio real en cómo el motor entiende las responsabilidades de cada réplica.

Y si aún haces todos los backups desde la primaria, empieza a preguntarte por qué. Porque a partir de ahora, no es que se vaya a poder evitar: es que deberías.

Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de LinkedIn y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

Publicado por Roberto Carrancio en Alta Disponibilidad, SQL Server, 0 comentarios

Casos de uso comunes de Row-Level Security (RLS)

Ya sabemos qué es Row-Level Security (RLS) y cómo se configura. Sabemos que se basa en funciones, en contexto y en algo muy parecido al sentido común. Pero el verdadero reto no es activarlo: es aplicarlo bien según el escenario real que tienes delante.

Aquí no vamos a hablar de casos teóricos ni de pruebas de laboratorio. Vamos a entrar en los tres escenarios más comunes que nos encontramos en proyectos reales, de esos con datos de verdad, usuarios impacientes y arquitecturas heredadas.

RLS interno en la organización: seguridad basada en Active Directory

Este es el caso más limpio y agradecido: una empresa con usuarios autenticados en Active Directory, accediendo a la base de datos con sus propias credenciales de Windows (sí, esto existe y funciona cuando se hace bien). Aquí el RLS puede aprovechar directamente la identidad del usuario para filtrar datos.

El patrón habitual consiste en mapear usuarios o grupos de AD con permisos o ámbitos de acceso, normalmente usando el ORIGINAL_LOGIN() o SUSER_SNAME() para identificar al usuario, y compararlo contra una tabla de mapeo como:

La función RLS consulta esta tabla y determina qué datos puede ver el usuario actual. Algo así:

Este modelo funciona bien si los usuarios acceden directamente con sus identidades, y si hay una buena sincronización entre AD y los datos internos. Pero cuidado: este patrón no es válido si la aplicación usa un login compartido, porque entonces ORIGINAL_LOGIN() siempre devuelve lo mismo.

También requiere un mantenimiento cuidadoso de la tabla de mapeo. Si te olvidas de añadir un nuevo usuario, no verá nada. Y eso está bien. Lo preocupante sería que viera de más.

Este patrón es ideal para:

  • Reporting interno
  • Aplicaciones corporativas en intranets
  • Escenarios con SSRS o Power BI con Kerberos bien configurado (sí, existen)

RLS en aplicaciones con un único login SQL y múltiples usuarios

Este es, con diferencia, el escenario más habitual. Una aplicación que se conecta a la base de datos con un solo login SQL Server (por ejemplo, AppUser) y desde ahí da servicio a miles de usuarios distintos, cada uno con sus propios permisos y ámbito de acceso.

Desde el punto de vista de SQL Server, todos los accesos vienen del mismo login. Por tanto, el nombre del usuario no sirve para nada. Aquí RLS solo tiene sentido si usamos SESSION_CONTEXT() para establecer el contexto del usuario en cada sesión.

  1. El patrón correcto es:
  2. La aplicación identifica al usuario (login web, token, sesión, lo que sea).
  3. Determina su TenantId, su ámbito de acceso, si es admin, etc.
  4. Al abrir la conexión (o justo después), ejecuta
    EXEC sp_set_session_context N’TENANT_ID’, 17;
    EXEC sp_set_session_context N’ES_ADMINISTRADOR’, 0;
  5. La función RLS consulta ese contexto y decide si mostrar o no cada fila.

Funciona. Es limpio. Es seguro. Pero solo si te aseguras de que cada conexión establece su contexto correctamente. Y eso implica entender bien cómo funciona el pool de conexiones. Porque si alguien reutiliza una conexión con el contexto de otro usuario, acabas sirviendo datos del usuario A al usuario B. Y eso no es un bug: es un incidente de seguridad.

Este patrón requiere no solo código en la aplicación para establecer el contexto en cada conexión sino validación en la base de datos para asegurarse de que el contexto existe y funciones RLS bien diseñadas (inline, sin llamadas externas ni joins innecesarios). Si además añades una capa de control en la aplicación tendrás doble seguridad.

Este escenario, bien montado, es el pan de cada día en escenarios como aplicaciones web SaaS, portales internos de gestión multiusuario o APIs que consumen datos con identidad propia (pero login compartido)

RLS en aplicaciones multi-tenant con varios clientes

Aquí las cosas se complican. Estamos ante una única aplicación que sirve a múltiples clientes independientes, y todos los datos viven en las mismas tablas, separados lógicamente por una columna TenantId. Este patrón es muy eficiente… hasta que alguien mete la pata y un SELECT devuelve datos de otro tenant.

RLS aquí no es una opción. Es una necesidad.

El patrón es similar al del punto anterior: la aplicación se conecta con un login compartido, pero establece el TenantId como contexto al inicio de cada sesión. La diferencia es que ahora ese TenantId define los límites legales del acceso a datos.

Es decir, ya no es un usuario con menos o más permisos. Es otro cliente, con sus propios datos. Si algo se cuela, no solo es un error, es una violación de privacidad con consecuencias legales.

La función RLS, por tanto, debe ser clara, directa, sin adornos:

Y la política se aplica a todas las tablas sensibles. Además, conviene reforzar la integridad con defaults:

Y con predicados de bloqueo (de eso hablaremos pronto) para evitar updates o deletes entre tenants.

Este patrón funciona, pero solo si se impide a la aplicación cambiar el contexto a lo loco, el TenantId se valida contra los permisos del usuario web y todas las rutas de acceso pasan por código que inicializa el contexto.

Además, como ya he remarcado, este escenario es el más sensible, y por tanto donde más cuidado debemos tener. Si no haces RLS aquí, estás confiando en que la aplicación nunca se equivoque. Buena suerte con eso.

Predicados de bloqueo en RLS

Cuando implementamos RLS, todo el mundo se queda encantado con el FILTER PREDICATE: ese que impide que el usuario vea filas que no le tocan. Pero la mayoría se olvida, o no quiere saber, que eso no impide que puedan hacer INSERT, UPDATE o DELETE sobre datos que no deberían tocar. Así de simple. Y así de peligroso. Ahí es donde entran los BLOCK PREDICATES, el otro 50% de la seguridad que RLS nos ofrece.

Un BLOCK PREDICATE define si una operación de modificación de datos está permitida. Se puede aplicar a:

  • AFTER INSERT (cuando se insertan nuevas filas)
  • AFTER UPDATE (cuando se actualiza una fila)
  • BEFORE UPDATE (para impedir que se cambie el valor de clave de filtrado, por ejemplo TenantId)
  • BEFORE DELETE (para validar que el usuario puede borrar esa fila)

Y aquí viene la parte buena, estos bloqueos se aplican antes de que la operación se realice. Si no se cumple la condición, la instrucción falla con error. Sin necesidad de triggers, sin lógica adicional. De forma declarativa y centralizada. Como debe ser.

Vamos con un ejemplo.

Supongamos que tenemos una tabla Facturas y ya tenemos aplicado un FILTER PREDICATE que impide ver facturas de otros tenants. Muy bien. Pero si no hacemos nada más, el usuario podría hacer esto:

INSERT INTO Facturas (FacturaId, TenantId, Importe) VALUES (9999, 42, 1500);

Y colar datos con el TenantId de otro cliente. Luego, como no puede verlas, ni se entera. Pero ya están en tu base. ¿Te hace ilusión explicárselo a legal? A mí tampoco.

Para evitarlo, añadimos un BLOCK PREDICATE:

Y luego lo aplicamos así:

Esto bloquea los INSERT y DELETE por defecto. Si queremos bloquear los updates también (y deberíamos), lo hacemos explícitamente:

Y si no queremos que nadie cambie el TenantId de una fila, lo añadimos como BEFORE UPDATE:

Esto impide que alguien coja una factura legítima y le cambie el TenantId para que desaparezca mágicamente de la vista de su propietario original. Muy creativo. Muy ilegal.

Consideraciones importantes con los bloqueos de RLS

Al usar BLOCK PREDICATE, las operaciones que no cumplan la condición fallan con un error genérico del tipo:

Esto es intencionado. No dice qué falló ni por qué, porque revelar detalles de seguridad no es buena idea. Pero esto también significa que debes controlar bien los errores en la aplicación, o los usuarios se encontrarán mensajes confusos.

Y como siempre, las funciones deben ser INLINE para no perder rendimiento. Y deben ser simples, sin joins ni condiciones complejas. Esto se ejecuta en cada fila afectada. Si metes un SELECT TOP 1 dentro, estás haciendo cosas malas y mereces tus bloqueos (los tuyos, no los de RLS).

Conclusión

RLS es una herramienta poderosa, pero no mágica. Su utilidad real depende de cómo te conectas, de quién eres en la base de datos y de cómo estableces el contexto. Un mismo mecanismo puede servir tanto para proteger acceso interno como para blindar un modelo multi-tenant.

Pero si no eliges el patrón correcto para tu escenario, estás poniendo una alarma en la puerta mientras dejas la ventana abierta. Y eso no es seguridad: es postureo.

Ya hemos cubierto lo esencial de RLS: qué es, cómo se implementa, cómo se adapta a escenarios reales y cómo no confiar ciegamente en que el FILTER PREDICATE lo hace todo. Porque si no añades bloqueos, estás dejando que el usuario escriba donde no puede leer. Y eso es como cerrar la puerta pero dejar las ventanas abiertas: solo te protege si el atacante es educado.

Usar RLS bien no es complicado. Pero requiere tomárselo en serio. Establecer contexto. Validar accesos. Aplicar filtros y bloqueos. Y sobre todo: asumir que si no lo defines tú, alguien lo hará por ti. Probablemente mal.

Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de LinkedIn y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

Publicado por Roberto Carrancio en Cloud, SQL Server, 0 comentarios

Seguridad a nivel de fila (RLS) en SQL Server

Cuando hablamos de seguridad en SQL Server, la mayoría piensa primero en roles, permisos, y si somos afortunados, en principios de mínimo privilegio. Sin embargo, en muchas organizaciones se sigue dejando la lógica de acceso a los datos en manos de la capa de aplicación. Y eso, como todos sabemos, es pedirle a un desarrollador frontend que entienda el negocio y además proteja los datos. Un sinsentido. Ahí entra en juego Row-Level Security (RLS), una funcionalidad introducida en SQL Server 2016 (sí, hace casi una década) que permite filtrar los datos directamente en el motor, sin tener que montar castillos de naipes con vistas o triggers que solo traen dolores de cabeza.

¿Qué es RLS y por qué debería importarnos?

La seguridad a nivel de fila permite restringir el acceso a las filas de una tabla en función del contexto del usuario que realiza la consulta. Y esto se hace de forma transparente, sin modificar el código de las consultas. No hablamos de un WHERE opcional añadido por el ORM de turno. Hablamos de reglas que se ejecutan en el servidor, en cada acceso, sin excepciones.

RLS nos permite definir una política de seguridad que determina si una fila puede o no ser accedida. Esa política se implementa mediante una función escalar, que actúa como el portero de discoteca: decide quién entra y quién no. Y lo mejor: el usuario no ve que se le han vetado filas. Simplemente, no están.

A diferencia de los trucos sucios con vistas filtradas y lógica duplicada, RLS está diseñado para que el control sea centralizado, mantenible y eficiente. Y, lo más importante, que no se pueda esquivar con una consulta directa.

Cómo funciona RLS bajo el capó

Para habilitar RLS necesitamos tres ingredientes:

  • Una función de filtrado, generalmente inline para evitar penalizaciones absurdas de rendimiento.
  • Una política de seguridad que asocia la función con una tabla concreta.
  • Usuarios (o roles) sobre los que queramos aplicar el filtrado.

La función recibe como parámetros las columnas de la tabla que queremos usar como condición de acceso, y devuelve un 1 (permitido) o un 0 (bloqueado). Así de sencillo. Y como todo buen sistema de seguridad, lo sencillo no quita lo peligroso: una mala implementación puede abrir más puertas de las que cierra.

Veámoslo con un ejemplo rápido:

Aquí estamos usando SESSION_CONTEXT() para almacenar el contexto del usuario (en este caso, su departamento), y comparar si la fila que se intenta leer pertenece al mismo departamento. Este patrón es de lo más habitual: guarda el valor relevante al iniciar sesión, y luego úsalo como filtro en la función RLS.

Después, aplicamos la política:

Y listo. A partir de ese momento, cualquier consulta contra la tabla Empleados estará sujeta al filtro. Sin excepciones. Sin necesidad de modificar el SELECT. Sin posibilidad de que el usuario borde el control.

Tampas comunes de RLS

Sí, puedes meter lógica compleja en la función RLS. No, no deberías. Las funciones de RLS se ejecutan por cada fila accedida, y si te vienes arriba y le metes llamadas a otras tablas, condicionales complejos o conversiones mágicas, lo que consigues es una performance digna de una migración mal hecha a Access.

Además, cuidado con usar funciones escalares no inline. No solo penalizan el rendimiento, sino que en versiones anteriores a SQL Server 2019 no se pueden usar directamente en RLS. Y aun en 2019 o superior, si puedes escribir una función inline, hazlo. Por tu salud mental y la de quien venga después.

También hay quien se pregunta: “¿Y si quiero permitir el acceso completo a ciertos roles o usuarios?” Pues puedes gestionar excepciones dentro de la propia función, comprobando por ejemplo el nombre del login o algún valor del SESSION_CONTEXT. Pero hazlo con moderación. Si acabas con una función que parece una novela de Agatha Christie para decidir quién puede leer qué, igual el problema no es el RLS.

RLS en escritura: INSERT, UPDATE y DELETE

Por defecto, RLS aplica el filtro también a operaciones de escritura. Eso significa que un usuario solo podrá insertar o modificar filas que cumplan la condición del filtro. No basta con tener permiso para escribir: si el valor que se inserta no pasa el control, la operación falla.

Este comportamiento se puede personalizar con predicados de bloqueo (BLOCK PREDICATE), pero por ahora no vamos a entrar en eso. Esto es una introducción, no una tesis. Lo importante es entender que RLS no es solo para SELECT. También puede protegernos de inserts maliciosos o updates “por accidente”.

¿Dónde guarda el contexto el RLS?

Una de las claves para que RLS funcione bien es cómo pasamos el contexto del usuario al motor. SQL Server no tiene una variable mágica llamada UsuarioActual.Departamento, así que somos nosotros los que tenemos que alimentar ese contexto. La opción más limpia y controlada es usar SESSION_CONTEXT.

Esto nos permite establecer pares clave-valor que persisten durante toda la sesión, y que podemos consultar desde la función RLS. Por ejemplo, en el momento de la conexión:

Esto lo puede hacer la capa de aplicación al conectarse, o mejor aún, a través de un procedimiento almacenado bien controlado. ¿Que podríamos usar ORIGINAL_LOGIN() o SUSER_SNAME() para extraer el usuario? Sí, pero volvemos al infierno de tener que mapear usuarios, mantener tablas auxiliares, y perder la trazabilidad del acceso real.

Limitaciones que no debes ignorar (aunque quieras)

RLS no cifra los datos. No evita que un administrador con permisos vea todo. No protege frente a accesos directos desde backups o desde otros medios. Es una herramienta de seguridad a nivel lógico, no físico.

Tampoco funciona automáticamente con todo. Por ejemplo, si creas una vista que usa WITH CHECK OPTION, puedes encontrarte con comportamientos inesperados. Y si haces SELECT INTO o usas funciones que acceden a múltiples tablas, el rendimiento puede sorprenderte… pero no en el buen sentido.

Y por supuesto, si alguien tiene permisos para desactivar la política o modificar la función RLS, todo se va al garete. Esto no sustituye una buena gestión de permisos. La complementa.

Conclusión: si no usas RLS, que sea porque no lo necesitas, no porque no lo conoces

RLS es una funcionalidad potente, elegante y bastante ignorada. Nos permite aplicar reglas de acceso directamente en el motor de SQL Server, con garantías y sin depender de que la aplicación “haga lo correcto”.

Eso sí: como cualquier herramienta de seguridad, hay que usarla bien. Si no tienes un modelo claro de control de acceso, implementar RLS sin criterio solo añade complejidad. Pero si sabes lo que haces y quieres evitar que un SELECT de más enseñe lo que no debe… entonces RLS es tu amigo.

En siguientes artículos profundizaremos en patrones de uso, ejemplos reales, y cómo integrar RLS con Active Directory o Azure AD. Pero por hoy, lo dejamos aquí. Que no se diga que no avisamos.

Si tenéis alguna duda o sugerencia, podéis dejarla en Twitter, por mail o dejarnos un mensaje en los comentarios. Y recuerda que también tenemos un grupo de LinkedIn y un canal de YouTube a los que te puede unir. ¡Hasta la próxima!

Publicado por Roberto Carrancio en Cloud, SQL Server, 1 comentario