【问题标题】:How to parameterise a SQL REVOKE command如何参数化 SQL REVOKE 命令
【发布时间】:2017-01-18 09:57:57
【问题描述】:

如何参数化 SQL REVOKE 命令?

DECLARE @ViewName nvarchar = 'MyViewName'
DECLARE @UserRole nvarchar = 'MyRoleName'

REVOKE SELECT ON [@ViewName] TO [@UserRole]

输出以下错误:

Cannot find the object '@ViewName', because it does not exist or you do not have permission.`

我需要使用动态 SQL 来解决这个问题还是有其他方法?

我的实际用例在 ASP.NET SqlDataClient 中,并且正在生成代码,因此我对它的控制有限。发送到 SQL 的代码(由 SQL Profiler 嗅探)是:

exec sp_executesql N'REVOKE SELECT ON [@ViewName] TO [@UserRole]',N'@ViewName nvarchar(24),@UserRole nvarchar(12)',@ViewName=N'MyViewName',@UserRole=N'MyUserRole'

【问题讨论】:

  • 你必须使用动态sql。
  • 因为GRANTREVOKE 本身需要相当多的权限,所以在构建动态SQL 并可以在不同凭据下执行命令的存储过程中执行此操作通常很有吸引力。这样,您可以通过控制对存储过程的访问来选择性地将权限分配给REVOKE,如果这成为要求,则添加审核,最后但并非最不重要的是,您可以继续使用参数。
  • @JeroenMostert 这听起来像是正确的答案。如果您将其作为答案并添加一个小示例,那么我将其标记为正确。

标签: asp.net sql-server sqldatasource


【解决方案1】:

因为GRANTREVOKE 本身需要相当大的权限,所以在构建动态SQL 并可以在不同凭据下执行命令的存储过程中执行此操作通常很有吸引力。这样,您可以通过控制对存储过程的访问来选择性地为REVOKE 分配权限,如果需要,可以添加审核,最后但并非最不重要的是,您可以继续使用参数。

在这种情况下:

CREATE PROCEDURE dbo.RevokeSelect(@ObjectName NVARCHAR(128), @RoleName NVARCHAR(128)) 
WITH EXECUTE AS OWNER AS BEGIN
    SET NOCOUNT ON;

    DECLARE @SQL NVARCHAR(MAX);
    SELECT @SQL = REPLACE(REPLACE(
        N'REVOKE SELECT ON @ObjectName TO @RoleName;',
        '@ObjectName', QUOTENAME(@ObjectName)),
        '@RoleName', QUOTENAME(@RoleName))
    ;
    -- For debugging
    --PRINT @SQL
    EXEC (@SQL)
END;
GO
GRANT EXECUTE ON dbo.RevokeSelect TO [application_login];

感谢EXECUTE AS OWNER[application_login] 帐户无需额外权限;它可以通过存储过程REVOKE SELECT在数据库中的任何对象上。这可能正是您想要的,但如果不是,您应该删除 EXECUTE AS OWNER 并授予单独的 CONTROL 对对象的权限(但这当然也允许许多其他操作)。

请注意,执行动态 SQL 的过程需要仔细审查,以确保它不会受到 SQL 注入的影响,就像使用动态 SQL 的任何其他过程一样。显然,如果该过程使用EXECUTE AS OWNER,则这一点更为重要,因为它可以做任何事情。在这种情况下,将QUOTENAME 应用于两个参数即可解决此问题。

最后但同样重要的是,虽然EXECUTE AS OWNER 简单方便,但如果数据库所有者不是帐户而是组,它就会失败。在这种情况下,如果要委派权限,则必须创建一个代理帐户以在 EXECUTE AS 中使用或使用证书对存储过程进行签名。如果开发人员不能被EXECUTE AS OWNER 的力量所信任,那么无论如何您都可能想要这样做。这超出了此答案的范围,但 Erland Sommerskog 对此主题有一个excellent writeup

【讨论】:

  • 感谢您抽出宝贵时间将您的评论扩展为完整的答案。太棒了!
  • 是否也可以参数化SELECT?即REVOKE @Permission ON @ObjectName TO @RoleName。当我尝试这样做时,我得到一个错误'SELECT' 附近的语法不正确。我正在尝试从生成以下 SQL(由 SQL Profiler 捕获)的 SqlDataSource 执行:exec revokeRolePermission @Permission=N'SELECT',@RoleName=N'MyRoleName',@ObjectName=N'MyViewName'
  • @Adam:您可以使用文本替换,就像使用其他两个参数一样。添加另一个REPLACE(。请注意,这样做还允许无意义的调用,例如REVOKE BANANA;如果这是一个问题,您可能希望存储过程只检查参数 (IF @Permission = 'SELECT' THEN ...)。
  • @Adam:surecheck 参数 (IF @Permission NOT IN ('SELECT', 'GRANT') BEGIN; RAISERROR(...); RETURN;) 因为你打开自己的 SQL 注入这个新字符串不能被转义(例如,@Permission=N'REVOKE ALL ON X TO dbo; DROP TABLE MyImportantTable; --' 会很高兴地构造一个非常糟糕的语句)。虽然这可能不会发生在您的应用程序中,但在存储过程中完全防止它仍然是一种很好的做法。更好的是,考虑为此设置两个单独的程序,因为要做的事情非常有限。
  • 对于GRANT,当然可以阅读其他内容(你不能REVOKE GRANT)。如果我们谈论的是意见,很难理解为什么您需要授予或撤销除SELECT 许可之外的任何其他内容。如果您将其扩展到其他对象和权限,请注意不要意外创建一个可以授予任何人任何权限的安全噩梦,因为这很容易被利用。 (显然,撤销的风险要小一些。)在所有情况下都必须防止注入。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-14
  • 1970-01-01
  • 1970-01-01
  • 2011-01-15
  • 2021-03-31
  • 1970-01-01
  • 2019-08-14
相关资源
最近更新 更多