4

我们在 SQL Server 2000中有一个常规的(即非扩展的)存储过程,它调用一个外部 exe。反过来,该 exe 加载来自 SDK 的 .dll 并从中调用一些过程(即 Init、DoStuff、Shutdown)。

我们拥有这个外部 exe 的唯一原因是因为我们不想创建一个会调用 .dll 的扩展存储过程。我们认为,如果 dll 崩溃(不太可能发生但仍然如此),那么 SQL Server 进程也会崩溃,这不是我们想要的。使用外部 exe,只有该 exe 会崩溃。

现在,我们正在升级到 SQL Server 2008并考虑创建一个调用该事物的 CLR 存储过程,从而摆脱 exe。当然,这个 SP 会被标记为 UNSAFE。因此的问题是,与扩展的 SP 方法相比,这样做是否安全(更安全、足够安全等)?

我在 BOL 上找到的唯一相关的事情是:

指定 UNSAFE 允许程序集中的代码对 SQL Server 进程空间执行非法操作,因此可能会损害 SQL Server 的稳健性和可伸缩性

,但我不确定它是否回答了我的问题,因为我不是追求“鲁棒性和可扩展性”,而是追求稳定性和保持事物正常运行。

PS:我们想要摆脱 exe,因为它在管理 SP 权限时会造成不便(你知道,如果你调用包含 xp_cmdshell 的 SP,这些东西会突然适用于你)。

4

2 回答 2

3

由于此代码最初用于扩展存储过程,因此听起来像是非托管代码。非托管代码中的错误很容易使您的进程崩溃。

CLR 集成比扩展存储过程更强大,但代码仍在进程中运行,因此错误可能会导致 SQL Server 崩溃或损坏。(相比之下,理论上,SAFE CLR 例程不会损坏 SQL Server,尽管它可能会导致问题降低服务器的可用性,而不会完全关闭 SQL Server。)

基本上,在这种情况下不使 SQL Server 崩溃的唯一方法是:

  1. 避免使用会崩溃的功能。
  2. 修复错误代码。
  3. 在单独的进程中运行代码(启动可执行文件、调用 Windows 服务、调用 Web 服务等)。您可以编写一个托管的 .NET DLL 来执行此交互。最有可能的是,您仍然需要加载它 UNSAFE,但是——如果它写得正确——实际上它可能是相当安全的。
于 2009-07-04T13:20:38.453 回答
1

因此的问题是,与扩展的 SP 方法相比,这样做是否安全(更安全、足够安全等)?

一般是的。我的意思是,如果您正在向操作系统进程发起攻击,那么您正在向操作系统进程发起攻击。我看不出使用扩展存储过程 API 来做到这一点必然比 SQLCLR API 更安全,尤其是当可能崩溃的是位于数据库之外的操作系统进程时。

当然,我不确定 XP API,因为我没有使用过它,但我确实知道以下内容:

  • XP API 已被弃用,建议所有可以使用其中任何一种技术完成的新项目都应在 SQLCLR 中完成。
  • SQLCLR 确实允许比其他两个更细化的权限,包括进行模拟的能力(如果执行 SQLCLR 对象的登录名是 Windows 登录名)。
  • SQLCLR API 由数据库和程序集所有者(即AUTHORIZATION子句指定的用户)在进程/内存方面分开。因此,您可以在一个数据库中的程序集出现问题,而不会影响其他数据库中的 SQLCLR 对象(如果另一个用户拥有程序集,甚至在同一个数据库中,尽管实际上这可能很少发生,因为大多数人只是使用默认值dbo)。

我不确定它是否回答了我的问题,因为我不是在追求“稳健性和可扩展性”,而是在追求稳定性和保持事物正常运行。

当然,当 Assembly 设置为时,您可以在 SQLCLR 中执行以下操作UNSAFE

  • 可能写入注册表(取决于授予运行 SQL Server 进程的登录身份帐户的访问权限,或者如果启用了模拟并且它是 Windows 登录,则执行 SQLCLR 功能的登录)。
  • 可能写入文件系统
  • 可能与系统上运行的进程交互
  • 与执行来自同一程序集的其他 SQL Server SPID(即会话)共享内存(意味着该数据库中由该用户拥有的特定程序集)。这可能是人们最难以理解的,因为当您习惯于控制台应用程序和 Windows 应用程序拥有自己的单独内存空间时,这是出乎意料的,但是在这里,因为它是每个所有者每个数据库每个程序集的单个 AppDomain,执行该代码的所有会话都共享所有static变量。很多代码都是假设 AppDomain 是私有的,因此在静态变量中存储值是有效的,因为它会缓存值,但是在 SQLCLR 中,如果两个进程正在覆盖彼此的值并读取另一个进程,则可能会出现意外行为会话的价值。
  • 潜在的内存泄漏。主机保护属性试图阻止您使用可以执行此操作的内置 .NET 功能,例如TimeZoneInfo用于在 TimeZoneID 之间转换时间,但主机保护属性不会在程序集上强制执行UNSAFE
  • 在执行 UNSAFE / FullTrust 代码(协作多任务与抢占)时,运行 SQLCLR 方法的线程可能会以不同方式处理。我以为我读过 UNSAFE 线程的管理方式不同,但不确定我在哪里读到它并正在寻找源代码。

但是以上都说了,如果你调用的是外部EXE,它有自己的AppDomain。

所以,你可以做的是:

  1. 继续使用 SQLCLR 包装器调用 EXE 以Process.Start(). 这为您提供了进程/内存分离以及更轻松地控制对单个存储过程的权限的能力,该存储过程只会调用此 EXE 并且没有人可以更改它(至少在不更改 SQLCLR 代码并重新安装程序集的情况下不能更改)。

  2. 在同一台机器上安装 SQL Server Express 的实例,在那里加载 SQLCLR 对象,并在两个方向(从当前 SQL Server 实例到新的 SQL Server Express 实例)创建链接服务器,以便您可以在它们之间轻松通信。这将允许您隔离 SQLCLR 执行并使其远离主 SQL Server 进程。

Of course, that all being said, how much of a concern is this really? Meaning, how likely is it that a process fully crashes and takes down everything with it? Sure, it's not impossible, but usually a crash would take down just the AppDomain and not the CLR host itself. I would think it far more likely that code that doesn't crash but is written poorly and consumes too much memory and/or CPU would be the problem people run into.

于 2016-04-08T07:06:22.740 回答