Seguridad a nivel de fila (RLS) en SQL Server

Descubre cómo funciona RLS en SQL Server para aplicar seguridad a nivel de fila de forma eficaz, centralizada y sin trampas.

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!

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

Mi nombre es Roberto Carrancio y soy un DBA de SQL server con más de 10 años de experiencia en el sector. Soy el creador del blog soydba.es donde intento publicar varios artículos a la semana (de lunes a viernes que los fines de semana me gusta estar con mi gente y disfrutar de mi moto) Espero que disfrutes leyendo este blog tanto como yo disfruto escribiendo y que te sea de utilidad. Si tienes alguna sugerencia, pregunta o comentario, puedes dejarlo al final de cada entrada o enviarme un correo electrónico. Estaré encantado de leerte y responderte. ¡Gracias por tu visita! Mi principal interés es compartir mi conocimiento sobre bases de datos con todo el que quiera aprenderlo. Me parece un mundo tan apasionante como desconocido. Fuera de lo profesional me encanta la cocina, la moto y disfrutar de tomar una cervecita con amigos.

1 comentario

[…] 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 […]

Deja una respuesta