OpenRowset与链接服务器

时间:2019-06-24 18:49:20

标签: sql-server security

我知道这类问题经常出现,但是我发现在这里或其他网站上没有发现任何理由不使用openrowset查询,而不是“每个人都说这很糟糕,因此即使即使他们无法证明原因”。

我们有一个带有主服务器的安装程序(简称为ServerMaster),该服务器与多个子服务器(ServerChild1,ServerChild2等)具有连接。这些子服务器还可以通过链接服务器对ServerMaster进行读写访问。在我们的方案中,没有解决方法。由于各种原因,ServerMaster和ServerChildren之间通常存在两种交互方式。 ServerChild框上的数据库(潜在的1000多个数据库)必须写入ServerMaster。通过链接服务器进行的访问使用可信连接,而不是特定帐户。

我们还有一个Windows服务,用于处理ServerMaster上的队列。此服务使用特定帐户建立连接以运行为队列提供服务的proc。当请求到达此队列时,该服务将调用ServerMaster上的另一个proc来生成许多脚本,以针对ServerChild上的数据库执行这些脚本。 proc对定义的一组表运行许多查询,以获取构建脚本所需的行。这涉及检查每个ServerChild上数据库的一组表。这些表都是不同的,但最终具有相同的基础,即项目和版本。在某些表中,这些列存在。在其他情况下,它们存在但具有不同的名称(即Part和Revision)。在其他情况下,它们仍然不存在,但可以绑定到关系结构中(例如,零件表具有零件,修订和零件ID(PK),并且与此相关的是PartAspects,它连接在零件ID上。

因为数据绑定回到了表中定义的主要源,所以我们必须将基表Part联接到已定义的查询,该查询以一致的方式为我们提供联接和标识键。因此,为此,我们为每个表定义了一个列,以提供此查询。

因此,我们的管理表如下所示:

TableName: Parts
LockQuery: SELECT PartID As ItemID, Revision As Version, PartID FROM Parts

TableName: PartAspects
LockQuery: SELECT p.PartID As ItemID, p.Revision As Version, pa.AspectID FROM Parts p JOIN PartAspects pa ON p.PartID = pa.PartID

这意味着当我们遍历每个表时,我们可以定义一个一致的结构,以跨所有ServerChild框获取正确的数据集。

由于LockQuery的性质,我们使用OPENQUERY执行此操作。查询的这一方面与proc中生成的临时表以及ServerMaster上的其他物理表连接。

现在,在临时开发环境中(与实时活动无关),我们使用纯文本密码,同时我们等待IT部门解决一些跨服务器问题。显然,这不会使它脱离这种孤立的临时环境,但是这已经引起了数据库管理员的疑问,即为什么我们要使用Openquery的“不安全”方法。 DBA确实承认他们不知道为什么它是“不安全的”,并且不能提供任何使它变得不安全的可支持方案,但是正如Internet上的每个人所说的那样,它一定是不安全的。当然,当我们的IT部门解决跨服务器问题时,我们将通过具有严格限制的单一服务帐户的受信任连接建立此连接,该帐户仅对其所需的对象具有权限。

到目前为止,给出的理由是应该通过链接服务器来完成,因为“这就是Microsoft的建议”。好吧,据我所知,这根本不是MS建议的。 MS以前在安装时启用了Ad Hoc查询,但从2008年起停止这样做。这并不是因为它本来就很糟糕,而是因为关闭不需要的东西是常识,除非需要它们。如果经验丰富的开发人员/ dba需要它们,则可以启用它们。

第二个参数始终是,MS表示“ OPENDATASOURCE仅应用于引用不经常访问的OLE DB数据源。对于将被多次访问的任何数据源,请定义一个链接服务器。”似乎每个人都将其翻译为:“永远不要使用它,除非它是一个一次性查询,而且永远不会再次运行。”不频繁是一个非常开放的术语。我对此的解释是,由于我们的代码仅在服务处理此队列时才从单个proc运行单个select语句,所以这种情况很少发生。这不是由多个操作员定期触发的常规过程。

现在,此“可以”被重构为在查询中使用替换值,因此被迫对链接的服务器全部运行查询。这将需要在ServerMaster上运行查询的各个方面,而不是在ServerChild上触发整个查询,从而导致效率大大降低(考虑到它将针对1000多个数据库运行),更不用说它将需要一个混乱的解决方案使用替换字符串对多个ServerChildren上的多个数据库执行该操作的方法。

论点3是,与链接服务器相比,它具有更大的攻击范围。在一定程度上,这是事实。但是,该攻击区域仅在安全允许的范围内。如果ServerChild的sysadmin帐户受到攻击,则攻击者可能会使用ServerMaster在ServerChild上执行恶意操作。但是,他们也可以直接在ServerChild上直接执行此操作,而无需首先为ServerMaster设置一组受损的凭据。这不是AdHoc查询的问题,这是帐户遭到入侵的问题。同样,如果ServerMaster上的帐户遭到破坏,则他们仅具有该帐户提供的访问权限。如果除了ServerChild上没有必要以外,它没有其他任何访问权限,则风险不会比通过链接服务器高。

最后,这似乎使每个人都大吃一惊,在ServerChild上启用此功能意味着,入侵了ServerChild帐户的黑客可以从ServerChild内连接到自己的服务器,并转储所需的一切。如果安全性配置得太差以至于不允许这样做,那么这可能再次成立。但是,实际情况是这些盒子都位于我们自己的环境中。它们都位于DMZ的后面,并且没有一个可以在域外部访问。它们是内部受害的,因此这里的“风险”是内部不良行为者会访问他们不应该访问的数据。现在,如果您认为此场景中的数据已经存在于所有ServerChild框中,并且在上下文之外都不敏感甚至毫无意义,那么风险(a)不大于通过链接服务器暴露的风险,(b )只能由配置不当的安全性(允许访问不必要的对象)才会暴露的风险,或者(c)应该通过配置DMZ而非SQL Server来解决的风险。

这是我们运行查询的一个示例(显然,这里的代码不是动态的,但执行时是连接和查询:

    UPDATE lc
    SET DefinedAspect = pa.SourceDataColumn
    FROM #LocalObjects lc
    JOIN OPENROWSET('ConnectionSettings', 'SELECT p.PartID As ItemID, p.Revision As Version, pa.AspectID FROM Parts p JOIN PartAspects pa ON p.PartID = pa.PartID') clk
    ON lc.ItemID = clk.ItemID
      AND lc.Version = clk.Version
    JOIN PartAspect pa
    ON clk.AspectID = pa.ASpectID

因此,我在这里寻找的是一个可以提供真实且可支持的理由的人,为什么我们应该删除当前代码并以效率较低,不太优雅的链接服务器方式重做。

请记住,建议不要更改模型并使用复制,例如,此处未列出。我希望证明在这种情况下,AdHoc查询不会比链接服务器更具风险,并且如果正确配置了安全性,则两种方法都存在任何顾虑,并且可以通过适当的安全控制措施加以缓解。

请不要说“ MS say X”,因为这不能就为什么一种方法优于另一种方法给出明确的答案。我正在寻找理由,目前的想法是,如果每个人都说这很糟糕,那一定是。

您可能会说,我对这一论点充其量还是持怀疑态度,但是如果有人可以向我展示一个切实可行的理由说明其糟糕之处,我将非常乐于接受。

0 个答案:

没有答案