Restringir la actualización en ciertas columnas. Solo permita que el procedimiento almacenado actualice esas columnas

17

Tengo columnas de precios sensibles que me gustaría actualizar solo a través de un procedimiento almacenado. Me gustaría que todo el código o los intentos manuales de alterar los valores en estas columnas de precios fallen si no está utilizando los procedimientos almacenados diseñados para actualizarlo.

Estoy considerando implementar esto usando disparadores y una tabla de tokens. La idea que estoy considerando es tener una tabla de tokens. los procedimientos almacenados deberán primero insertar valores en la tabla de tokens. Luego actualice las columnas de precios. El activador de actualización verificará si el token existe en la tabla de tokens para la fila actualizada. Si se encuentra, continuaría. Si no se encuentra el token, generará una excepción y hará que la transacción de actualización falle.

¿Hay una buena / mejor manera de implementar esta restricción?

Elias
fuente
1
Puede usar una vista para la seguridad basada en columnas. Eso será mucho más elegante que un gatillo. Otorgue permiso a los usuarios sobre la vista pero no sobre los datos subyacentes.
Thomas Stringer
Ese es un buen punto. Pero el problema sigue sin resolverse sin interrumpir muchas aplicaciones que utilizan la agrupación de conexiones.
Elias
¿Puede explicar cómo esto va a "romper muchas aplicaciones que utilizan la agrupación de conexiones"?
Aaron Bertrand

Respuestas:

21

SQL Server permite permisos a nivel de columna. Solo por ejemplo:

GRANT UPDATE ON dbo.Person (FirstName, LastName) TO SampleRole;
DENY UPDATE ON dbo.Person (Age, Salary) TO SampleRole;

fuente
Gracias Michal, pero esta solución no funcionará para mí porque mi aplicación es una aplicación web que utiliza la agrupación de conexiones. Todos los usuarios se conectan utilizando la misma cadena de conexión de SQL Server.
Elias
1
@Elias no entiendo. La cadena de conexión se conecta como un usuario específico, ¿verdad? Así que reemplace SampleRolecon ese usuario ...
Aaron Bertrand
Los permisos de nivel de columna son el camino a seguir aquí. Eso y garantizar que los desarrolladores sepan que realizar cambios en los valores a través de t-sql directamente destruirá el sistema.
mrdenny
6
-- prevent your web app user from updating that column directly:

DENY UPDATE ON dbo.YourTable(Price) TO WebApplicationUserName;
GO

-- create a stored procedure while logged in as sysadmin:

CREATE PROCEDURE dbo.UpdateYourTable
  @ProductID INT,
  @Price DECIMAL(10,2)
WITH EXECUTE AS OWNER
AS
BEGIN
  SET NOCOUNT ON;

  UPDATE dbo.YourTable 
    SET Price = @Price
    WHERE ProductID = @ProductID;
END
GO

-- grant explicit access only to that stored procedure to the web app user:

GRANT EXEC ON dbo.UpdateYourTable TO WebApplicationUserName;
Aaron Bertrand
fuente
2

Si todos sus usuarios tienen el mismo inicio de sesión (ouch, BTW), entonces esta es otra opción

  • revocar los derechos de actualización de ese usuario (o rol, si lo está haciendo de esa manera).
  • Modifique el proceso almacenado con la cláusula "ejecutar como propietario"
  • entonces el proceso almacenado se ejecutará con los derechos del usuario que posee el esquema en el que reside (si está dentro dbo, entonces ya está cubierto).

Los usuarios habituales de la aplicación carecerán de derechos de actualización para esa tabla, por lo que no podrán actualizarla de otra manera.

SqlRyan
fuente
No necesita crear un nuevo usuario para hacer esto ...
Aaron Bertrand
@aaronbertrand tienes razón, por eso, e reasonni pensaba que "ejecutarías como creador", pero eso no es una cosa, puedes "ejecutar como propietario" siempre que el usuario que posee el esquema tenga derechos para actualizar esa tabla Si el proceso almacenado está en dbo, entonces estás cubierto. Actualizaré mi respuesta.
SqlRyan