【问题标题】:Service Broker Internal Activation Poisoning - Where?Service Broker 内部激活中毒 - 在哪里?
【发布时间】:2015-12-10 22:53:03
【问题描述】:

我收到有毒信息,但我不知道为什么。

我的代理设置如下所示:

CREATE MESSAGE TYPE
  [//DB/Schema/RequestMessage]
  VALIDATION = WELL_FORMED_XML;
CREATE MESSAGE TYPE
  [//DB/Schema/ReplyMessage]
  VALIDATION = WELL_FORMED_XML;

CREATE CONTRACT [//DB/Schema/Contract](
  [//DB/Schema/RequestMessage] SENT BY INITIATOR,
  [//DB/Schema/ReplyMessage] SENT BY TARGET
)

CREATE QUEUE Schema.TargetQueue

CREATE SERVICE [//DB/Schema/TargetService]
ON QUEUE Schema.TargetQueue (
  [//DB/Schema/Method3Contract]
)

CREATE QUEUE Schema.InitiatorQueue

CREATE SERVICE [//DB/Schema/InitiatorService]
ON QUEUE Schema.InitiatorQueue

然后我有我的内部激活程序:

CREATE PROCEDURE Schema.Import
AS

DECLARE @RequestHandle UNIQUEIDENTIFIER;
DECLARE @RequestMessage VARCHAR(8);
DECLARE @RequestMessageName sysname;

WHILE (1=1)
BEGIN
  BEGIN TRANSACTION;

  WAITFOR (
    RECEIVE TOP(1)
      @RequestHandle = conversation_handle,
      @RequestMessage = message_body,
      @RequestMessageName = message_type_name
    FROM
      Schema.TargetQueue

  ), TIMEOUT 5000;


  IF (@@ROWCOUNT = 0)
  BEGIN
    COMMIT TRANSACTION;
    BREAK;
  END

  EXEC Schema.ImportStep1 @ID = @RequestMessage;
  --EXEC Schema.ImportStep2 @ID = @RequestMessage;

  END CONVERSATION @RequestHandle;

  COMMIT TRANSACTION;
END

我的激活是通过以下方式启用的:

ALTER QUEUE Schema.TargetQueue
    WITH 
    STATUS = ON,
    ACTIVATION 
    ( STATUS = ON,
      PROCEDURE_NAME = Schema.Import,
      MAX_QUEUE_READERS = 10,
      EXECUTE AS SELF
    )

我用这个存储过程启动这个过程

CREATE PROCEDURE Schema.ImportStart
AS
BEGIN
  DECLARE @ID VARCHAR(8);

  DECLARE Cursor CURSOR FOR 
    SELECT ID FROM OtherDatabase.OtherSchema.ImportTable
    EXCEPT
    SELECT ID FROM Table

  OPEN Cursor;
  FETCH NEXT FROM Cursor INTO @ID;
  WHILE @@FETCH_STATUS = 0
  BEGIN
    DECLARE @InitiateHandle UNIQUEIDENTIFIER;
    DECLARE @RequestMessage VARCHAR(8);

    BEGIN TRANSACTION;

    BEGIN DIALOG
      @InitiateHandle
    FROM SERVICE
      [//DB/Schema/InitiatorService]
    TO SERVICE
      N'//DB/Schema/TargetService'
    ON CONTRACT
      [//DB/Schema/Contract]
    WITH
      ENCRYPTION = OFF;

    SELECT @RequestMessage = @ID;

    SEND ON CONVERSATION
      @InitiateHandle
    MESSAGE TYPE
      [//DB/Schema/RequestMessage]
      (@RequestMessage);

    COMMIT TRANSACTION;

    FETCH NEXT FROM Cursor INTO @ID;
  END
  CLOSE Cursor;
  DEALLOCATE Cursor;
END

所以这应该是如何工作的:

  • 我执行 ImportStart
  • 为每个 ID 生成一条消息
  • 内部激活使导入步骤得以执行

相反,我收到有毒消息并且队列被禁用。

如果,

  • 我将 Schema.TargetQue 激活设置为关闭
  • EXEC schema.ImportStart
  • EXEC 架构。手动导入

效果很好。

有什么见解吗?

【问题讨论】:

  • 您是否在错误日志中看到任何有关自动激活过程的日志消息以及其他详细信息(通常您会看到)?在不知道其他任何事情的情况下,最可能的罪魁祸首是身份验证/授权,但这只是猜测
  • 我不是服务器管理员,我只有 db_owner 权限,所以如果没有向我的 IT 部门正式请求,我无法查看日志,我想我会继续这样做。如果是身份验证/授权,您将如何进行故障排除?我尝试将执行 AS 更改为 Caller、self、服务帐户和我的用户名;都没有运气。
  • 很大程度上取决于您所看到的结果。例如,您是否真的验证过消息正在到达队列,并且该过程实际上已经到了尝试接收与在此之前失败的地步?如果您必须请求并等待日志,您可能需要考虑在各个位置临时向您的激活过程添加一些打印语句,以便为您提供有关执行到达何处的指针(打印也会输出到激活的 procs 上的日志)。当然,目前这只是猜测,很可能根本不是auth。
  • 试试这个:EXECUTE AS USER = '<queueowner>'; EXEC Schema.Import。这将在与激活发生时相同的上下文中运行激活的过程,您将看到发生的任何错误。
  • 我实际上刚刚弄明白了,看起来 chadhoc 是在正确的轨道上,在日志中它抛出了错误激活的 proc '[Schema].[Import]' running on queue ' DB.Schema.TargetQueue' 输出以下内容:'服务器主体 "hcaelxxam" 在当前安全上下文下无法访问数据库 "database"。尽管是 db_owner。经过一番谷歌搜索,我找到了这篇文章:technet.microsoft.com/en-us/library/ms187861.aspx 因为我使用了两个数据库,所以模拟权限被拒绝了。 ALTER DATABASE database SET TRUSTWORTHY ON 修复了它。谢谢大家!

标签: sql-server stored-procedures service-broker


【解决方案1】:

嗯:

  • 您的消息类型定义为well_formed_xml,但您将varchar(8) 作为消息正文发送。真的有用吗?
  • 您使用[//DB/Schema/Method3Contract] 作为目标队列,但没有定义它。很可能是拼写错误。
  • 您在队列激活中指定EXECUTE AS SELF。 BOL 对这个案例说了一些神秘的话:

    自我
    指定存储过程作为当前用户执行。 (执行此 ALTER QUEUE 语句的数据库主体。)

我不确定我是否理解引用的陈述,因为它显然与您的经验相矛盾。如果它是您的用户帐户,那么一切都应该没问题,因为您似乎拥有完成这项工作所需的所有权限。

所以,以防万一——Schema 架构的所有者是谁?该委托人拥有什么权限?而且,如果不是你,谁执行alter queue 语句(为什么)?

如果无法访问日志,诊断问题要困难得多,但我会先创建一个具有与您相同权限的新用户帐户,将其设置为 Schema 架构的所有者,然后慢慢处理它,撤销不必要的权限,直到它中断。当然,假设它会起作用。

【讨论】:

  • 1. well_formed_xml 作为 varchar(8) 确实有效,尽管我知道为什么它可能是不好的做法。 2. Method3Contract 是一些行话的剩余部分,我在发布之前(很差地)清理了这些术语。 3. 我发现答案是当程序试图访问第二个数据库时,模拟权限被拒绝(执行失败)。不过谢谢!
  • @hcaelxxam,在这种情况下,您访问另一个数据库的事实改变了游戏规则。如果所有内容都位于单个 DB 中,则不需要 trustworthy 选项。
猜你喜欢
  • 2014-05-15
  • 1970-01-01
  • 1970-01-01
  • 2011-01-14
  • 2012-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多