Azure SignalR 服务的应用程序防火墙(预览版)

应用程序防火墙提供对分布式系统中客户端连接的复杂控制。 在深入了解其功能和设置之前,让我们阐明应用程序防火墙不执行的操作:

  1. 它不会替换身份验证。 防火墙在客户端连接身份验证层后面运行。
  2. 它与网络层访问控制无关。

应用程序防火墙的作用是什么?

应用程序防火墙由各种规则列表组成。 目前,有一个名为“客户端连接计数规则”的规则列表。 未来的更新将支持更多规则列表,用于控制连接生存期和消息吞吐量等方面。

此准则分为三个部分:

  1. 不同应用程序防火墙规则简介。
  2. 有关使用门户或 Bicep 在 SignalR 服务端配置规则的说明。
  3. 在服务器端配置令牌的步骤。

先决条件

客户端连接计数规则

客户端连接计数规则限制并发客户端连接。 当客户端尝试建立新连接时,会按顺序检查规则。 如果违反任何规则,则连接将被拒绝,状态代码为 429。

ThrottleByUserIdRule

此规则限制用户的并发连接数。 例如,如果用户使用不同的设备打开多个浏览器选项卡或登录,则可以使用此规则来限制该用户的并发连接数。

注意

  • UserId 必须存在于访问令牌中,此规则才有效。 请参阅配置访问令牌

ThrottleByJwtSignatureRule

此规则限制同一令牌的并发连接数,以防止恶意用户重用令牌来建立无限连接,这可能会耗尽连接配额。

注意

  • 默认情况下,不能保证 SDK 生成的令牌每次都不同。 尽管每个令牌都包含时间戳,但如果在数秒内生成大量令牌,则此时间戳可能相同。 若要避免相同的令牌,请将随机声明插入令牌声明。 请参阅配置访问令牌

ThrottleByJwtCustomClaimRule

更高级,可以根据自定义声明将连接分组到不同的组中。 系统将对具有相同声明的连接进行汇总,以执行该检查。 例如,可以添加 ThrottleByJwtCustomClaimRule,以允许具有 5 个使用自定义声明名称“freeUser”的并发连接。

注意

  • 该规则适用于具有特定声明名称的所有声明。 连接计数汇总是基于同一声明(包括声明名称和声明值)。 ThrottleByUserIdRule 是此规则的一种特殊情况,适用于采用 userIdentity 声明的所有连接。

警告

  • 避免使用过于激进的 maxCount。 客户端连接可能会在不完成 TCP 握手的情况下关闭。 SignalR 服务无法立即检测到这些“半关闭”连接。 连接被视为活动,直到检测信号失败。 因此,激进的限制策略可能会意外地限制客户端。 更流畅的方法是为连接计数保留一些缓冲区,例如:将 maxCount 加倍。

设置应用程序防火墙

若要使用应用程序防火墙,请导航到 Azure 门户上的 SignalR“应用程序防火墙”边栏选项卡,然后单击“添加”以添加规则。

有关在门户中为 Azure SignalR 添加应用程序防火墙规则的屏幕截图。

配置访问令牌

仅当访问令牌包含相应的声明时,应用程序防火墙规则才会生效。 如果连接没有相应的声明,则跳过规则。

下面是一个在默认模式下在访问令牌中添加 userId 或自定义声明的示例:

services.AddSignalR().AddAzureSignalR(options =>
    {
        //  Add necessary claims according to your rules.
        options.ClaimsProvider = context => new[]
        {
            // Add UserId: Used in ThrottleByUserIdRule
            new Claim(ClaimTypes.NameIdentifier, context.Request.Query["username"]),

            // Add unique claim: Ensure uniqueness when using ThrottleByJwtSignatureRule. 
            // The token name is not important. You could change it as you like.
            new Claim("uniqueToken", Guid.NewGuid().ToString()),
           
            // Custom claim: Used in ThrottleByJwtCustomClaimRule
            new Claim("<Custom Claim Name>", "<Custom Claim Value>"),
            // Custom claim example
            new Claim("freeUser", context.Request.Query["username"]),
        };
    });

无服务器模式的逻辑与此类似。

有关详细信息,请参阅客户端协商