我在使用混合模式身份验证的 Microsoft SQL Server 2008 Express 实例中有一个名为 MyDB 的数据库。使用数据库 MyDB 的应用程序当前使用 Windows 身份验证和当前用户的 Windows 凭据进行连接。此登录名是“公共”服务器角色的成员,并且在 MyDB 数据库中具有映射到它的用户。此数据库用户是 db_datareader 和 db_datawriter 数据库角色的成员。

我想要的是,当应用程序连接时,它有权在 MyDB 中读取和写入。但是,当另一个应用程序使用相同的登录名连接时,应该只允许读取。

我的想法是创建一个登录触发器,它将检查连接字符串的应用程序名称部分,并据此决定是否应该切换执行上下文。(郑重声明,我知道依赖连接字符串的应用程序名称绝对不安全,而且很容易规避。此处的目的不是保护数据库,而是帮助用户避免在使用其他应用程序(例如 Microsoft Excel)连接时更改数据)

我创建了一个名为“myapp_reader”的新登录名,映射到 MyDB 数据库中的用户,该用户是 db_datareader 的成员。

然后我尝试使用以下 TSQL 创建登录触发器:

CREATE TRIGGER CheckUser
ON ALL SERVER
AFTER LOGON AS
BEGIN
IF APP_NAME() <> 'My Application Name'
    BEGIN
        EXECUTE AS LOGIN = 'myapp_reader' WITH NO REVERT
    END
END

但不幸的是,它不起作用。当我尝试连接时出现以下错误:

由于触发器执行,登录“MyComputer\MyWindowsUsername”登录失败。
将数据库上下文更改为“master”。
将语言设置更改为 us_english。(微软 SQL Server,错误:17892)

当我查看错误日志时,它显示:

错误:15590,严重性:16、状态:1.
只能在临时级别将“No Revert”或“Cookie”选项与“Execute As”语句一起使用。
错误:17892,严重性:20、状态:1.
由于触发器执行,登录“MyComputer\MyWindowsUsername”登录失败。[客户:xxx.xxx.xxx.xxx]

此错误是否意味着我无法永久更改登录触发器中的执行上下文?

有帮助吗?

解决方案

我认为不可能更改整个会话的执行上下文。您可以为数据库中的每个表/视图创建一个用于 INSERT、UPDATE 和 DELETE 的 DML 触发器,该触发器对某个 app_name() 进行回滚。您可以编写一个过程来自动创建所有这些触发器。

或者,如果您可以选择让 Excel 等应用程序通过链接服务器进行连接,那么此时您可以更改执行上下文。并创建一个登录触发器,如果​​用户尝试通过 Excel 或其他应用程序直接连接到服务器,该触发器会回滚连接。

其他提示

假设您可以控制应用程序并可以对其进行修改,那么应用程序角色将完全执行您想要的工作。请参阅在线书籍中的sp_setapprole以开始。

您不能以自己想要的方式做到这一点。

  • 用户连接在整个过程中具有相同的凭证,除了使用Execute AS的某些特定范围。
  • 您已经意识到您不能依靠app_name()或host_name()来检测某人何时连接的连接,这意味着每个表不依赖每个表的回滚触发器
  • 您的应用依赖于直接表写入访问

我能想到的一些选择...

  • 您的应用程序使用存储的Procs,用户仅读取访问表
  • 使用应用程序中的set context_info为回滚触发器设置“秘密”键
  • 更改您的应用程序以使用服务帐户/是Windows Service/etc,并代理用户名(网页将执行)
  • ...或一些排列

您确实需要下定决心要首先组织和管理凭据。

如果使用SP_SETAPPROLE,可以规避Windows身份验证并允许任何用户通过该应用程序访问。如果这是您真正想做的,那么如果应用程序是服务器为该应用程序创建用户帐户,并在该用户的凭据下运行它。

如果是客户端应用程序,则要制作一个Web服务,该服务只会读取并发送应用程序需要的特定数据并在新帐户下运行该Web服务。然后,在IIS7中,您可以在Web服务本身上放置ACL,以便它仍然受到保护。

另外,如果该应用不信任清洁并知道它在做什么,请要求在允许触摸SQL Server之前对其进行审查。如果是您自己的应用程序,请开始信任自己:-)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top