对话安全设置可以为特定会话提供加密、远程身份验证和远程授权。 若会话使用对话安全设置,Service Broker 会对发送到 SQL Server 实例之外的所有消息进行加密。 Service Broker 会话默认使用对话安全设置。
对话安全基础知识
利用 Service Broker 对话安全设置,应用程序可以对单个对话会话(或对话)进行身份验证、授权或加密。 默认情况下,所有对话会话均使用对话安全设置。 开始对话时,可以通过在 ENCRYPTION = OFF 语句中包含 BEGIN DIALOG CONVERSATION 子句来显式允许对话继续,而无需对话安全性。 但是,如果会话面向的服务存在远程服务绑定,则即使如此 ENCRYPTION = OFF,对话也会使用安全性。
对于使用安全设置的对话,Service Broker 会对发送到 SQL Server 实例之外的所有消息进行加密。 保留在 SQL Server 实例中的消息从不加密。 在对话安全设置中,仅作为起始服务宿主的数据库和作为目标服务宿主的数据库才需要能够访问用于提供安全性的证书。 也就是说,执行消息转发的实例不需要能够解密实例转发的消息。
Service Broker 提供两种类型的对话安全设置,“完全安全设置”和“匿名安全设置”。 对于使用对话安全设置的会话,Service Broker 提供远程授权,将会话的远程端映射到本地用户。
无论会话使用完全安全设置还是匿名安全设置,消息都要在网络上进行加密。 但是,在这两种方法之间,目标数据库中的有效权限和用于消息加密的策略略有不同。
无论会话使用完全安全设置还是使用匿名安全设置,消息正文都使用为特定会话生成的对称会话密钥进行加密。 仅使用为对话安全设置提供的证书,通过私钥加密对密钥进行加密。 Service Broker 还会执行消息完整性检查,以帮助检测消息是否损坏或篡改。
SQL Server 为使用对话安全设置的会话创建会话密钥。 为了在数据库存储会话密钥时保护会话密钥,Service Broker 使用数据库的主密钥加密会话密钥。 如果数据库主密钥不可用,则在创建数据库主密钥或会话超时之前,会话的消息将保留在 transmission_status 错误中。因此,参与会话的两个数据库都必须包含主密钥,即使数据库托管在同一实例中也是如此。 如果启动的数据库不包含主密钥,对话框将失败。 如果目标数据库不包含主密钥,消息将保留在发起数据库的传输队列中。 这些消息的最后一个传输错误指示无法传递消息的原因。 使用 ENCRYPTION = OFF 参数创建未加密的对话,或使用以下命令创建数据库主密钥:
CREATE MASTER KEY ENCRYPTION BY PASSWORD = '<password>';
为方便起见,Service Broker 允许停留在单个数据库中的安全会话继续进行,而不考虑该数据库是否包含主密钥。 虽然两个不同的数据库可以在会话生存期期间移到不同的 SQL Server 实例中,但是单个数据库中的会话将始终停留在该数据库中。 因此,会话可以进行。
完全安全性
完全安全设置帮助防止起始服务向不可信数据库发送消息,并帮助防止目标服务接收来自不可信数据库的消息。 若会话使用完全安全设置,Service Broker 会加密通过网络传输的消息。
完全安全设置为起始服务和目标服务均提供标识。 完全安全设置要求起始服务信任目标服务,并且目标服务也信任起始服务。 例如,从供应商订购部件的服务可能需要订购应用程序信任供应商服务和供应商服务来信任订购应用程序。
数据库管理员通过交换包含公钥的证书建立信任。 对于完全对话安全设置,每一会话端都包含本地用户的私钥和远程用户的公钥。 作为起始服务宿主的数据库包含“远程服务绑定”。 远程服务绑定指定拥有与远程数据库中的私钥相对应的证书的本地用户。 因此,代表起始服务的操作将在目标数据库中以指定的用户身份运行。
目标数据库包含相应的用户。 此用户拥有与拥有发起服务的用户拥有的私钥对应的证书。 因此,代表目标服务的操作在起始数据库中以发起起始服务的用户身份运行。
对于使用完全安全设置的对话,每一会话端都生成一个会话密钥。 每个方向中的第一条消息均包含会话密钥,它用密钥交换密钥进行加密,详细信息请参阅证书和 Service Broker。
匿名安全性
匿名安全设置有助于防止起始服务将消息发送到不可信数据库。 若会话使用匿名安全设置,Service Broker 会加密通过网络传输的消息。
匿名安全性将目标服务标识到发起服务,但不标识目标服务的发起服务。
例如,提交工作订单的应用程序可能需要保证工作订单的接收者是预期目标,但目标数据库可能不需要为提交工作订单的服务提供任何特殊特权。 在这种情况下,包含起始服务的数据库必须包含针对目标服务的远程服务绑定。
由于目标服务无法验证发起服务的标识,因此代表发起服务的操作作为目标数据库中固定数据库角色public的成员运行。 目标数据库接收不到有关启动该会话的用户的任何信息。 目标数据库不需要包含启动会话的用户的证书。
对于使用匿名安全设置的对话,会话两端均使用由起始数据库生成的会话密钥。 目标数据库不会向发起的数据库返回会话密钥。
对话安全性的安全上下文
Service Broker 远程授权控制对单个服务的远程访问。 远程授权确定安全上下文,SQL Server 实例的传入消息在此上下文中发送到服务。
Service Broker 总是对完全不在 SQL Server 实例内进行的安全对话使用远程授权。 为会话配置的对话框安全性决定了 Service Broker 用于远程授权的安全上下文。
即使配置了远程授权,Service Broker 也不会在 SQL Server 实例中保留会话时使用远程授权。 对于实例中的会话,SQL Server 安全主体已可供 SQL Server 使用,因此无需使用远程授权来确定 Service Broker 操作的正确安全上下文。 但是,正如本主题前面所述,Service Broker 创建会话密钥,以便在会话期间将某个数据库移到另一个实例中时,会话仍可继续进行。
对于使用匿名安全设置的会话,连接在目标数据库中以固定数据库角色 public 的成员身份运行。 在这种情况下,固定数据库角色 public 必须具有向服务发送消息的权限。 但该角色无需数据库中的其他权限。
对于使用完全安全设置的会话,各会话端的连接在运行时具有远程服务绑定中指定的用户的权限。 例如,如果远程服务绑定将服务名称 InventoryService 与用户 InventoryServiceRemoteUser关联,SQL Server 将使用安全上下文 InventoryServiceRemoteUser 将应用程序的消息 InventoryService 放在目标服务的队列中。
为提高安全性,拥有服务私钥的用户通常与被指定激活的用户不同。 拥有私钥的用户只需要向队列添加消息的权限,即 SEND 使用该队列的服务的权限。 相反,被指定激活的用户应具有完成请求的工作及发送响应所需的权限。 在前面的示例中, InventoryServiceRemoteUser 不需要有权查询清单表或发送返回消息。 用户只需要向使用队列 InventoryService 发送消息的权限。 存储过程激活发生在具有队列所指定的凭据的另一个会话中。 在将消息排入队列的会话与处理消息的会话之间不需要共享凭据。
创建安全对话框
Service Broker 建立两个数据库之间的对话时,起始服务必须在目标数据库中建立用户上下文,以便将消息放置于目标队列中。 此用户上下文确定起始服务是否有权限打开与目标数据库的对话。
实现此操作的最佳方法是创建证书和远程服务绑定。 有关创建证书的详细信息,请参阅 CREATE CERTIFICATE。 有关创建远程服务绑定的详细信息,请参阅 CREATE REMOTE SERVICE BINDING。
注意
如果未正确设置安全上下文,则对话上发送的消息将保留在 sys.transmission_queue 启动服务中,列中显示以下错误消息 transmission_status : The server principal '%.*ls' is not able to access the database '%.*ls' under the current security context.