您的位置:首页 > 数据库

第七篇 SQL Server安全跨数据库所有权链接

2015-08-28 09:11 351 查看
本篇文章是SQL Server安全系列的第七篇,详细内容请参考原文

Relational databases are used in an amazing variety of applications with connections from a dizzying array of clients over widely distributed networks,特别是互联网,使得数据几乎向任何人,任何地方开放。数据库可以包含相当大部分的人类知识,包括高度敏感的个人信息和关键数据。
数据库的这些特性使得有人想要窃取数据或通过篡改以损害它的主人。确保你的数据是安全的是一个关键部分来配置SQL Server和开发应用程序存储数据。这一系列将探索SQL Server 2012安全基础,那样你可以保护你的数据和服务器资源,getting as granular as you need to be to protect against the unique security threats that can affect your data.大部分的功能适用于早期版本的SQL Server,但我也会讨论只适用于SQL Server 2012和以后版本的功能。
大多数的时候,你可能会关心独立数据库中有单独所有者的数据和对象访问的安全。但有时需要从多个数据库中访问数据和对象,这会引起一些安全问题,增加数据访问的复杂性。在这一篇,你会学习跨数据库所有权链接,使你可以安全的跨越数据库边界。
所有权链接
大多数的时候,你创建的数据库对象所引用的其他对象都是在同一个数据库中。比如一个存储过程所访问的表在同一个数据库,一个视图所连接的表都在同一个数据库。但是,有时你需要创建对象访问其他数据库中的对象。在以前,跨数据库访问的安全规则遵循在单一数据库中的规则。访问用户需要对访问对象有必要的权限,连续的所有权链接允许SQL Server简化权限检查。毕竟,SQL Server不能放松警惕无论对象存储在哪。类似单一数据库中,所有权链接有助于简化跨数据库的安全管理。
所有权链接工作的基本原理是一样的,不管你是在一个单一的数据库还是跨数据库。所有数据库对象都有一个所有者,并且所有者控制谁在对象上有权限。对象访问其他对象,比如存储过程在SELECT语句把多张表联接起来,形成一个连续的所有权链接,只要一个所有者拥有所有对象。
这种情况下用户只要有顶层对象(比如存储过程、视图)的权限,访问其他对象并不需要对底层对象有权限,只要存在一个连续的所有权链接就行。SQL Server一旦证实用户对顶层对象有权限就会停止检查底层对象的权限。这种设计为用户提供了更多更好的控制权,因为用户只需要直接访问对象的权限。
提示:所有权链接只适用于对象的权限,如SELECT、UPDATE和EXECUTE操作。SQL Server总是检查数据定义语言语句的权限,因为这些权限应用于语句而不是对象。
跨数据库所有权链接
跨数据库所有权链接是所有权链接的一个扩充,所有权链接的所有对象(包括用户直接访问的对象以及底层相关的对象)在同一个数据库。唯一不同的是跨数据库所有权链接跨越数据库边界。因此你可以在数据库中有一个视图将多个数据库下的表联接在一起。或者是一个存储过程访问多个数据库下的对象。在这些情况下,用户直接访问的源对象依赖于另一个数据库中的对象。
这两种所有权链的唯一重要的区别是,主体可以跨库成为其他对象的所有者。数据库用户也是一个主体,是完全包含在一个单一数据库中。即使多个数据库中都具有相同名称的数据库用户,这些都是独立的,不同的主体,不能参与一个完整的所有权链接,除非所有这些用户都映射到相同的服务器级别登录名。所以相关的所有者是登录名,而不是数据库用户。一个关键的概念:一个连续的所有权链接中的对象的共同拥有者是一个服务器级的主体,而不是一个数据库级的主体。
SQL Server内部通过SID而不是名称来区别对象的所有者。在一个单一的数据库,all objects owned by a single user have a single SID specified as the owner,因为在同一数据库中用户名不能重复。但在跨数据库中,SID是终极所有者在服务器级别的登录名对应。不同的用户在不同的数据库下可以有不同的登录名,所以会有不同的SID。这可能是用户与登录名潜在容易混乱的方面,所以要确保你清楚这一点!
一个连续的所有权链接要求所有对象(源对象和关联对象)的所有者映射到相同的登录名及相同的SID。
探索跨数据库所有权链接
本篇的样例代码会说明如何使用跨数据库所有权链接并解释它的特性。代码首先会在服务器级别创建一个叫做SharedLogin登录名。之后的代码会使用此登录名作为所有权链接中对象的共享所有者。

USE master;
GO
IF SUSER_SID('SharedLogin') IS NOT NULL DROP LOGIN SharedLogin;
CREATE LOGIN SharedLogin WITH password = 'Y&2!@37z#F!l1zB';
GO


代码7.1 创建SharedLogin登录名
我们需要两个数据库来演示跨数据库所有权链接,因此接下来代码会创建它们。用户直接访问对象的数据库叫做SourceDB,关联对象的数据库叫做ChainedDB。ChainedDB包含一个dbo.AlaskaCity表,里面有Alaska三大城市的人口数据。代码7.2会创建ChainedDB库和AlaskaCity表,然后往表中插入部分数据:

IF DB_ID('ChainedDB') IS NOT NULL DROP DATABASE ChainedDB;
CREATE DATABASE ChainedDB;
GO
USE ChainedDB;
GO
-- Create a table for access from another database
CREATE TABLE dbo.AlaskaCity
(
AlaskaCityID INT NOT NULL IDENTITY(1, 1),
CityName NVARCHAR(20) NOT NULL,
Population INT NOT NULL
CONSTRAINT PK_AlaskaCity PRIMARY KEY (AlaskaCityID)
);
GO
INSERT INTO dbo.AlaskaCity (CityName, Population)
VALUES ('Fairbanks', 31535), ('Anchorage', 291826), ('Juneau', 31275);
GO


代码7.2 创建ChainedDB库和AlaskaCity表并插入测试数据
代码7.3创建SourceDB库和一个视图,用户直接访问视图以返回ChainedDB库AlaskaCity表中的数据。代码中包含一个查询语句测试视图返回数据是否正确。如果你是以sysadmin身份登录这个语句应该正常执行。作为管理员运行是很方便,但是在生产使用它不安全,通常一个用户访问的代码不会有所有对象的所有权!

IF DB_ID('SourceDB') IS NOT NULL DROP DATABASE SourceDB;
CREATE DATABASE SourceDB;
GO
USE SourceDB;
GO
-- Create a view that accesses ChainedDB.dbo.AlaskaCity
CREATE VIEW dbo.AlaskaCitiesView AS
SELECT * FROM ChainedDB.dbo.AlaskaCity;
GO
SELECT * FROM dbo.AlaskaCitiesView ORDER BY Population DESC;


代码7.3 创建SourceDB库和AlaskaCitiesView视图
现在你有两个数据库,其中一个库下的对象会访问另一库下的对象,而且在sysadmin下执行是正常。代码7.4在SourceDB库创建一个SourceUser用户映射到SharedLogin登录名,并且将AlaskaCitiesView视图的查询权限授予给SourceUser用户。然后代码更改执行上下文到SharedLogin并尝试访问AlaskaCitiesView视图。查询会成功吗?

USE SourceDB;
GO
-- Create a user in the SourceDB who will access the view
CREATE USER SourceUser FOR LOGIN SharedLogin;
GRANT SELECT ON dbo.AlaskaCitiesView TO SourceUser;
GO
-- Try accessing the view as SourceUser
EXECUTE AS LOGIN = 'SharedLogin';
SELECT * FROM dbo.AlaskaCitiesView ORDER BY Population DESC;
GO
REVERT;


代码7.4 创建一个SourceUser用户映射到SharedLogin登录名
查询抛出一个错误:服务器主体 "SharedLogin" 无法在当前安全上下文下访问数据库 "ChainedDB"。
我们有一个连续的所有权链接:视图和表共享相同的所有者——dbo数据库用户。但是在服务器实例或新数据库上没有启用跨数据库所有权链接,下面我们将启用它。
启用跨数据库所有权链接
新安装的SQL Server实例跨数据库所有权链接选项默认是关闭的。这是因为启用这个选项会在实例的安全盔甲上打开几个漏洞;我将在这篇后面简要地讲解风险。当选项是禁用的,当代码依赖跨数据库所有权链接就会生成权限拒绝错误。(正如你稍后会看到的,在代码执行前这不是唯一需要修正的问题,但它是第一个我们将解决。)
服务器级别启用
在服务器级别为所有数据库启用跨数据库所有权链接。如果你启用它,它会应用到所有数据库上而且你不能在数据库上限制它。
使用SSMS,对象资源管理器下右击实例->属性->安全性,在对话框的底部你会看到跨数据库所有权链接的选项,如图7.1所示,点击确定实例下的所有数据库就会启用。

-- Clean up
USE master;
GO
IF SUSER_SID('SharedLogin') IS NOT NULL DROP LOGIN SharedLogin;
IF DB_ID('ChainedDB') IS NOT NULL DROP DATABASE ChainedDB;
IF DB_ID('SourceDB') IS NOT NULL DROP DATABASE SourceDB;


View Code
总结
跨数据库所有权链接是SQL Server帮助保持你的数据安全的另一种方式。禁用这个选项,恶意用户访问其他数据库中的数据就会更难。但在正确的场景和安全环境中,你可以启用此选项让数据库对象所有者对其数据有更严格的控制。你应该很少在服务器级别启用跨数据库所有权链接。相反,只为你真正需要的数据库启用,并确保不被特权用户滥用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: