Este team redactor ha pasado horas investigando la solución a tus dudas, te brindamos la soluciones por eso nuestro objetivo es servirte de mucha apoyo.
Además del sistema de privilegios estándar SQL disponible a través de GRANT, las tablas pueden tener políticas de seguridad de fila que restringen, por usuario, qué filas pueden ser devueltas por consultas normales o insertadas, actualizadas o eliminadas por comandos de modificación de datos. Esta característica también se conoce como Seguridad a nivel de fila. De forma predeterminada, las tablas no tienen ninguna política, de modo que si un usuario tiene privilegios de acceso a una tabla de acuerdo con el sistema de privilegios SQL, todas las filas dentro de ella están igualmente disponibles para consultas o actualizaciones.
Cuando la seguridad de fila está habilitada en una tabla (con ALTER TABLE … ENABLE ROW LEVEL SECURITY), todo acceso normal a la tabla para seleccionar filas o modificar filas debe estar permitido por una política de seguridad de filas. (Sin embargo, el propietario de la tabla no suele estar sujeto a las políticas de seguridad de filas). Si no existe ninguna política para la tabla, se utiliza una política de denegación predeterminada, lo que significa que no hay filas visibles ni se pueden modificar. Operaciones que se aplican a toda la tabla, como TRUNCATE
y REFERENCES
, no están sujetos a la seguridad de la fila.
Las políticas de seguridad de filas pueden ser específicas de comandos, roles o ambos. Se puede especificar una política para aplicar a ALL
comandos, o para SELECT
, INSERT
, UPDATE
, o DELETE
. Se pueden asignar varios roles a una política determinada y se aplican las reglas normales de herencia y pertenencia al rol.
Para especificar qué filas son visibles o modificables según una política, se requiere una expresión que devuelva un resultado booleano. Esta expresión se evaluará para cada fila antes de cualquier condición o función que provenga de la consulta del usuario. (Las únicas excepciones a esta regla son leakproof
funciones, que están garantizadas para no filtrar información; el optimizador puede optar por aplicar dichas funciones antes de la comprobación de seguridad de filas). Filas para las que la expresión no devuelve true
no será procesado. Se pueden especificar expresiones separadas para proporcionar un control independiente sobre las filas que son visibles y las filas que pueden modificarse. Las expresiones de política se ejecutan como parte de la consulta y con los privilegios del usuario que ejecuta la consulta, aunque las funciones de definición de seguridad se pueden utilizar para acceder a datos que no están disponibles para el usuario que llama.
Superusuarios y roles con el BYPASSRLS
El atributo siempre omite el sistema de seguridad de filas al acceder a una mesa. Los propietarios de mesas normalmente también pasan por alto la seguridad de las filas, aunque el propietario de una mesa puede optar por estar sujeto a la seguridad de las filas con ALTER TABLE … FORCE ROW LEVEL SECURITY.
Habilitar y deshabilitar la seguridad de filas, así como agregar políticas a una tabla, es siempre un privilegio exclusivo del propietario de la tabla.
Las políticas se crean usando el comando CREATE POLICY, se modifican usando el comando ALTER POLICY y se eliminan usando el comando DROP POLICY. Para habilitar y deshabilitar la seguridad de filas para una tabla determinada, use el comando ALTER TABLE.
Cada política tiene un nombre y se pueden definir varias políticas para una tabla. Como las políticas son específicas de la tabla, cada política de una tabla debe tener un nombre exclusivo. Diferentes tablas pueden tener políticas con el mismo nombre.
Cuando se aplican varias políticas a una consulta determinada, se combinan mediante OR
(para políticas permisivas, que son las predeterminadas) o usando AND
(para políticas restrictivas). Esto es similar a la regla de que un rol determinado tiene los privilegios de todos los roles de los que es miembro. Las políticas permisivas frente a las restrictivas se analizan más adelante.
Como ejemplo simple, aquí se explica cómo crear una política en el account
relación para permitir sólo miembros de la managers
rol para acceder a filas, y solo filas de sus cuentas:
CREATETABLE accounts (manager text, company text, contact_email text);ALTERTABLE accounts ENABLEROWLEVEL SECURITY;CREATE POLICY account_managers ON accounts TO managers USING(manager =current_user);
La política anterior proporciona implícitamente una WITH CHECK
cláusula idéntica a su USING
cláusula, de modo que la restricción se aplique tanto a las filas seleccionadas por un comando (por lo que un administrador no puede SELECT
, UPDATE
, o DELETE
filas existentes que pertenecen a un administrador diferente) y a filas modificadas por un comando (por lo que las filas que pertenecen a un administrador diferente no se pueden crear a través de INSERT
o UPDATE
).
Si no se especifica ningún rol o el nombre de usuario especial PUBLIC
se utiliza, la política se aplica a todos los usuarios del sistema. Para permitir que todos los usuarios accedan solo a su propia fila en una users
tabla, se puede utilizar una política simple:
CREATE POLICY user_policy ON users USING(user_name =current_user);
Esto funciona de manera similar al ejemplo anterior.
Para utilizar una política diferente para las filas que se agregan a la tabla en comparación con las filas que están visibles, se pueden combinar varias políticas. Este par de políticas permitiría a todos los usuarios ver todas las filas en el users
tabla, pero solo modificar la suya propia:
CREATE POLICY user_sel_policy ON users FORSELECTUSING(true);CREATE POLICY user_mod_policy ON users USING(user_name =current_user);
en un SELECT
comando, estas dos políticas se combinan usando OR
, con el efecto neto de que se pueden seleccionar todas las filas. En otros tipos de comando, solo se aplica la segunda política, por lo que los efectos son los mismos que antes.
La seguridad de la fila también se puede desactivar con el ALTER TABLE
mando. La desactivación de la seguridad de filas no elimina ninguna política definida en la tabla; simplemente se ignoran. Entonces, todas las filas de la tabla son visibles y modificables, sujeto al sistema estándar de privilegios SQL.
A continuación se muestra un ejemplo más amplio de cómo se puede utilizar esta función en entornos de producción. La mesa passwd
emula un archivo de contraseña de Unix:
-- Simple passwd-file based exampleCREATETABLE passwd ( user_name textUNIQUENOTNULL, pwhash text, uid intPRIMARYKEY, gid intNOTNULL, real_name textNOTNULL, home_phone text, extra_info text, home_dir textNOTNULL, shell textNOTNULL);CREATE ROLE admin;-- AdministratorCREATE ROLE bob;-- Normal userCREATE ROLE alice;-- Normal user-- Populate the tableINSERTINTO passwd VALUES('admin','xxx',0,0,'Admin','111-222-3333',null,'/root','/bin/dash');INSERTINTO passwd VALUES('bob','xxx',1,1,'Bob','123-456-7890',null,'/home/bob','/bin/zsh');INSERTINTO passwd VALUES('alice','xxx',2,1,'Alice','098-765-4321',null,'/home/alice','/bin/zsh');-- Be sure to enable row level security on the tableALTERTABLE passwd ENABLEROWLEVEL SECURITY;-- Create policies-- Administrator can see all rows and add any rowsCREATE POLICY admin_all ON passwd TO admin USING(true)WITHCHECK(true);-- Normal users can view all rowsCREATE POLICY all_view ON passwd FORSELECTUSING(true);-- Normal users can update their own records, but-- limit which shells a normal user is allowed to setCREATE POLICY user_mod ON passwd FORUPDATEUSING(current_user= user_name)WITHCHECK(current_user= user_name AND shell IN('/bin/bash','/bin/sh','/bin/dash','/bin/zsh','/bin/tcsh'));-- Allow admin all normal rightsGRANTSELECT,INSERT,UPDATE,DELETEON passwd TO admin;-- Users only get select access on public columnsGRANTSELECT(user_name, uid, gid, real_name, home_phone, extra_info, home_dir, shell)ON passwd TOpublic;-- Allow users to update certain columnsGRANTUPDATE(pwhash, real_name, home_phone, extra_info, shell)ON passwd TOpublic;
Al igual que con cualquier configuración de seguridad, es importante probar y asegurarse de que el sistema se comporte como se espera. Usando el ejemplo anterior, esto demuestra que el sistema de permisos está funcionando correctamente.
-- admin can view all rows and fields postgres=>set role admin;SET postgres=>table passwd; user_name | pwhash | uid | gid | real_name | home_phone | extra_info | home_dir | shell -----------+--------+-----+-----+-----------+--------------+------------+-------------+----------- admin | xxx |0|0| Admin |111-222-3333||/root |/bin/dash bob | xxx |1|1| Bob |123-456-7890||/home/bob |/bin/zsh alice | xxx |2|1| Alice |098-765-4321||/home/alice |/bin/zsh (3rows)-- Test what Alice is able to do postgres=>set role alice;SET postgres=>table passwd; ERROR: permission denied for relation passwd postgres=>select user_name,real_name,home_phone,extra_info,home_dir,shell from passwd; user_name | real_name | home_phone | extra_info | home_dir | shell -----------+-----------+--------------+------------+-------------+----------- admin | Admin |111-222-3333||/root |/bin/dash bob | Bob |123-456-7890||/home/bob |/bin/zsh alice | Alice |098-765-4321||/home/alice |/bin/zsh (3rows) postgres=>update passwd set user_name ='joe'; ERROR: permission denied for relation passwd -- Alice is allowed to change her own real_name, but no others postgres=>update passwd set real_name ='Alice Doe';UPDATE1 postgres=>update passwd set real_name ='John Doe'where user_name ='admin';UPDATE0 postgres=>update passwd set shell ='/bin/xx'; ERROR: new row violates WITHCHECKOPTIONfor"passwd" postgres=>deletefrom passwd; ERROR: permission denied for relation passwd postgres=>insertinto passwd (user_name)values('xxx'); ERROR: permission denied for relation passwd -- Alice can change her own password; RLS silently prevents updating other rows postgres=>update passwd set pwhash ='abc';UPDATE1
Todas las políticas construidas hasta ahora han sido políticas permisivas, lo que significa que cuando se aplican múltiples políticas, se combinan utilizando la “O“ Operador booleano. Si bien las políticas permisivas se pueden construir para permitir solo el acceso a las filas en los casos previstos, puede ser más sencillo combinar políticas permisivas con políticas restrictivas (que los registros deben aprobar y que se combinan utilizando el “Y“ Operador booleano). Sobre la base del ejemplo anterior, agregamos una política restrictiva para requerir que el administrador esté conectado a través de un socket Unix local para acceder a los registros del passwd
mesa:
CREATE POLICY admin_local_only ON passwd AS RESTRICTIVE TO admin USING(pg_catalog.inet_client_addr()ISNULL);
Entonces podemos ver que un administrador que se conecta a través de una red no verá ningún registro, debido a la política restrictiva:
=>SELECTcurrent_user;current_user-------------- admin (1row)=>select inet_client_addr(); inet_client_addr ------------------127.0.0.1(1row)=>SELECTcurrent_user;current_user-------------- admin (1row)=>TABLE passwd; user_name | pwhash | uid | gid | real_name | home_phone | extra_info | home_dir | shell -----------+--------+-----+-----+-----------+------------+------------+----------+-------(0rows)=>UPDATE passwd set pwhash =NULL;UPDATE0
Las verificaciones de integridad referencial, como las restricciones de clave única o primaria y las referencias de clave externa, siempre omiten la seguridad de las filas para garantizar que se mantenga la integridad de los datos. Se debe tener cuidado al desarrollar esquemas y políticas de nivel de fila para evitar “canal encubierto“ filtraciones de información a través de tales controles de integridad referencial.
En algunos contextos, es importante asegurarse de que no se aplique la seguridad de fila. Por ejemplo, al realizar una copia de seguridad, podría ser desastroso si la seguridad de las filas provocara silenciosamente la omisión de algunas filas de la copia de seguridad. En tal situación, puede establecer el parámetro de configuración row_security en off
. Esto en sí mismo no evita la seguridad de las filas; lo que hace es lanzar un error si los resultados de alguna consulta se filtran por una política. A continuación, se puede investigar y corregir el motivo del error.
En los ejemplos anteriores, las expresiones de política consideran solo los valores actuales en la fila para acceder o actualizar. Este es el caso más simple y de mejor rendimiento; cuando sea posible, es mejor diseñar aplicaciones de seguridad de filas para que funcionen de esta manera. Si es necesario consultar otras filas u otras tablas para tomar una decisión de política, eso se puede lograr utilizando sub-SELECT
s, o funciones que contienen SELECT
s, en las expresiones de política. Sin embargo, tenga en cuenta que dichos accesos pueden crear condiciones de carrera que podrían permitir la filtración de información si no se tiene cuidado. Como ejemplo, considere el siguiente diseño de tabla:
-- definition of privilege groupsCREATETABLE groups (group_id intPRIMARYKEY, group_name textNOTNULL);INSERTINTO groups VALUES(1,'low'),(2,'medium'),(5,'high');GRANTALLON groups TO alice;-- alice is the administratorGRANTSELECTON groups TOpublic;-- definition of users' privilege levelsCREATETABLE users (user_name textPRIMARYKEY, group_id intNOTNULLREFERENCES groups);INSERTINTO users VALUES('alice',5),('bob',2),('mallory',2);GRANTALLON users TO alice;GRANTSELECTON users TOpublic;-- table holding the information to be protectedCREATETABLE information (info text, group_id intNOTNULLREFERENCES groups);INSERTINTO information VALUES('barely secret',1),('slightly secret',2),('very secret',5);ALTERTABLE information ENABLEROWLEVEL SECURITY;-- a row should be visible to/updatable by users whose security group_id is-- greater than or equal to the row's group_idCREATE POLICY fp_s ON information FORSELECTUSING(group_id <=(SELECT group_id FROM users WHERE user_name =current_user));CREATE POLICY fp_u ON information FORUPDATEUSING(group_id <=(SELECT group_id FROM users WHERE user_name =current_user));-- we rely only on RLS to protect the information tableGRANTALLON information TOpublic;
Ahora suponga que alice
desea cambiar el “un poco secreto“ información, pero decide que mallory
no se le debe confiar el nuevo contenido de esa fila, por lo que lo hace:
BEGIN;UPDATE users SET group_id =1WHERE user_name ='mallory';UPDATE information SET info ='secret from mallory'WHERE group_id =2;COMMIT;
Eso parece seguro; no hay ventana donde mallory
debería poder ver el “secreto de mallory“ cuerda. Sin embargo, aquí hay una condición de carrera. Si mallory
está haciendo al mismo tiempo, digamos,
SELECT*FROM information WHERE group_id =2FORUPDATE;
y su transacción está en READ COMMITTED
modo, es posible que ella vea “secreto de mallory“. Eso sucede si su transacción llega al information
fila justo después alice
hace. Bloquea esperando alice
para confirmar la transacción, luego recupera el contenido de la fila actualizado gracias al FOR UPDATE
cláusula. Sin embargo, lo hace no buscar una fila actualizada para el implícito SELECT
de users
, porque ese sub-SELECT
no tenía FOR UPDATE
; en cambio el users
La fila se lee con la instantánea tomada al comienzo de la consulta. Por lo tanto, la expresión de política prueba el antiguo valor de mallory
nivel de privilegio y le permite ver la fila actualizada.
Hay varias formas de solucionar este problema. Una respuesta simple es usar SELECT ... FOR SHARE
en sub-SELECT
s en las políticas de seguridad de la fila. Sin embargo, eso requiere otorgar UPDATE
privilegio en la tabla referenciada (aquí users
) a los usuarios afectados, lo que podría resultar indeseable. (Pero se podría aplicar otra política de seguridad de fila para evitar que realmente ejerzan ese privilegio; o el sub-SELECT
podría estar incrustado en una función de definición de seguridad). Además, el uso concurrente de bloqueos de filas compartidas en la tabla a la que se hace referencia podría plantear un problema de rendimiento, especialmente si las actualizaciones son frecuentes. Otra solución, práctica si las actualizaciones de la tabla referenciada son poco frecuentes, es realizar un bloqueo exclusivo en la tabla referenciada al actualizarla, de modo que ninguna transacción concurrente pueda estar examinando valores de fila antiguos. O simplemente se puede esperar a que finalicen todas las transacciones simultáneas después de realizar una actualización de la tabla a la que se hace referencia y antes de realizar cambios que dependan de la nueva situación de seguridad.
Para obtener detalles adicionales, consulte CREAR POLÍTICA y ALTERAR TABLA.
Anterior | Hasta | próximo |
5.7. Privilegios | Hogar | 5.9. Esquemas |
Sección de Reseñas y Valoraciones
Eres capaz de asistir nuestro trabajo escribiendo un comentario y dejando una valoración te lo agradecemos.