RabbitMQ安全设计,用于从服务器声明队列(并从客户端使用)

RabbitMQ安全设计,用于从服务器声明队列(并从客户端使用),rabbitmq,Rabbitmq,我有一个测试应用程序(首先是RabbitMQ),它在部分受信任的客户机上运行(因为我不希望他们自己创建队列),因此我将研究队列的安全权限以及客户机连接的凭据 对于消息传递,主要是从服务器到客户机的单向广播,有时是从服务器到特定客户机的查询(通过该查询,回复将在replyTo队列上发送,该队列专用于服务器侦听响应的客户机) 我目前在服务器上有一个接收功能,用于查找来自客户端的“公告”广播: agentAnnounceListener.Received += (model, ea) => {

我有一个测试应用程序(首先是RabbitMQ),它在部分受信任的客户机上运行(因为我不希望他们自己创建队列),因此我将研究队列的安全权限以及客户机连接的凭据

对于消息传递,主要是从服务器到客户机的单向广播,有时是从服务器到特定客户机的查询(通过该查询,回复将在replyTo队列上发送,该队列专用于服务器侦听响应的客户机)

我目前在服务器上有一个接收功能,用于查找来自客户端的“公告”广播:

agentAnnounceListener.Received += (model, ea) =>
{
    var body = ea.Body;
    var props = ea.BasicProperties;
    var message = Encoding.UTF8.GetString(body);

    Console.WriteLine(
        "[{0}] from: {1}. body: {2}",
        DateTimeOffset.FromUnixTimeMilliseconds(ea.BasicProperties.Timestamp.UnixTime).Date,
        props.ReplyTo,
        message);

      // create return replyTo queue, snipped in next code section
};
我希望在上述接收处理程序中创建返回主题:

var result = channel.QueueDeclare(
    queue: ea.BasicProperties.ReplyTo,
    durable: false,
    exclusive: false,
    autoDelete: false,
    arguments: null);
或者,我可以将接收到的公告存储在数据库中,并在常规计时器上运行此列表,并在每次通过时为每个消息声明一个队列

在这两种场景中,服务器将在将来使用这个新创建的通道向客户端发送查询

我的问题是:

1) 当从客户端接收消息时,在服务器上创建回复通道更好吗?或者如果我在外部(在计时器上)创建回复通道,那么声明已经存在的队列(可能有数千个端点)是否存在性能问题

2) 如果一个客户端开始表现不好,是否有任何方法可以引导它们(在receive函数中,我可以查找每分钟多少条消息,并在满足某些条件时引导)?在管道中接收之前,是否可以定义任何其他筛选器来阻止发送过多消息的客户端


3) 在上面的示例中,请注意每次运行时我的消息都会不断出现(相同的旧消息),请问如何清除它们?

我认为阻止客户端创建队列只会使设计复杂化,而不会带来太多安全好处。 您允许客户端创建消息。在RabbitMQ中,阻止客户端向服务器发送大量消息并不容易

如果您想限制您的客户端,RabbitMQ可能不是最佳选择。当服务器开始处理所有消息时,它会限制速率,但您不能使用现成的解决方案在服务器上对每个客户端设置严格的速率限制。此外,通常允许客户端创建队列

方法1-网络应用

也许您应该尝试改用web应用程序:

  • 客户端通过服务器进行身份验证
  • 要宣布,客户端将POST请求发送到某个端点,即
    /api/Announce
    ,可能会提供一些允许它们这样做的凭据
  • 要接收传入消息,
    GET/api/messages
  • 要确认已处理的消息:
    POST/api/acknowledge
当客户确认收到时,您将从数据库中删除您的邮件

通过这种设计,您可以编写自定义逻辑来限制或禁止行为不正常的客户端,并且您可以完全控制服务器

方法2-RabbitMQ管理API

如果您仍然希望使用RabbitMQ,则可以通过使用

您需要编写一个应用程序,该应用程序将根据计时器查询RabbitMQ管理API,并且:

获取所有当前连接,并检查每个连接的消息速率

如果消息速率超过阈值,请使用
/api/permissions/vhost/user
端点关闭连接或撤销用户权限


在我看来,如果您不需要RabbitMQ提供的所有排队功能(如工作队列或复杂路由),web应用程序可能会更简单。

以下是一些适用于您的场景的通用架构/可靠性想法。对你的3个具体问题的回答在最后

总体建筑理念 我不确定服务器上声明响应队列的方法是否会带来性能/稳定性方面的好处;你必须对其进行基准测试。我认为实现您想要的最简单的拓扑结构如下:

  • 每个客户端在连接时都会声明一个
    独占
    和/或
    自动删除
    匿名队列。如果客户端的网络连接非常粗略,以至于不希望保持打开的直接连接,那么类似于上面Alex建议的“Web App”,让客户端访问代表其声明独占/自动删除队列的端点,并关闭连接(在消费者离开时自动删除队列)当客户没有足够的定期联系时。只有在面对网络不可靠的情况下无法调整客户端的RabbitMQ心跳时,或者如果可以证明需要在web应用层内限制队列创建速率时,才应该这样做
  • 每个客户端的队列都绑定到一个广播主题交换,服务器使用该主题交换来传递广播消息(通配符路由密钥)或特定目标消息(仅与一个客户端的队列名称匹配的路由密钥)
  • 当服务器需要从客户端获得回复时,您可以让服务器在发送“response needed”消息之前声明响应队列,并在消息中对响应队列进行编码(基本上就是您现在正在做的事情),或者,您可以在客户机中构建语义,在尝试再次使用
    独占的
    (互斥)之前,客户机停止从广播队列中使用固定的时间,将其响应发布到自己的队列中,并确保服务器在分配的时间内使用这些响应,在关闭服务器之前,使用并恢复正常的广播语义。不过,第二种方法要复杂得多,可能不值得
  • 防止客户端压倒RabbitMQ 可以降低服务器负载并帮助防止客户端使用RMQ操作向服务器添加的内容包括