如何使 SignalR 承载身份验证安全或如何不记录查询字符串

Posted

技术标签:

【中文标题】如何使 SignalR 承载身份验证安全或如何不记录查询字符串【英文标题】:How to make SignalR Bearer Authentication Secure OR how to Not Log the Query String 【发布时间】:2022-01-18 02:32:08 【问题描述】:

使用Bearer Token Authentication 时,SignalR 通过查询字符串传递 JWT 令牌。显然,这会带来the token gets logged 连同请求的​​风险,因此任何可以读取日志的人都可以通过复制令牌来冒充。

文档说:

如果您担心使用服务器日志记录这些数据,可以通过将 Microsoft.AspNetCore.Hosting 记录器配置为警告级别或更高级别(这些消息写入信息级别)来完全禁用此日志记录

在这个阶段我想到了一个附带问题:谁保证如果日志级别是Warning并且发生了一些不好的事情,日志中不会仍然包含请求 URL?

文档继续:

如果您仍想记录某些请求信息,您可以编写一个中间件来记录您需要的数据并过滤掉 access_token 查询字符串值(如果存在)。

我想这个想法是完全关闭请求的默认日志记录并用自定义日志记录中间件替换它。这对我来说听起来并不简单。所以我想知道:

是否有任何方法可以连接到记录器,然后自定义实际记录的内容? 或者我们可以利用现有的HTTP Logging 吗?乍一看,在查询字符串的日志记录方面,它似乎也是一个全有或全无的选项,或者有没有一种自定义方法? 是否有解决此问题的 NuGet 包? 其他人是如何解决这个问题的?

【问题讨论】:

我将专注于从查询字符串中完全删除身份验证的方法。也许***.com/questions/54825739/… 可以提供帮助。如果您想更改记录的内容,您可能需要深入了解日志框架的文档,或更改框架 anybody who can read the log can impersonate by copying the token 所以你现在正试图避开可以访问你的应用程序日志的管理员,那么我认为你可以做的是防止令牌不被写入日志,或者换句话说,你应该编写自定义日志记录功能。也许this document 可以帮助你。我还找到了类似的an answer。 【参考方案1】:

我已经采取了一种方法,即确实需要将 JWT 令牌作为查询字符串的一部分发送,正如 here 所解释的那样。

总而言之,当设置为 cookie 时,cookie 将作为 SignalR 连接初始化的一部分被浏览器自动发送:

document.cookie = `X-Authorization=$token; path=/; secure; samesite=strict`; // https://***.com/a/48618910/331281
const newConnection = new HubConnectionBuilder()
    .withUrl('/background-queue-hub', 
        skipNegotiation: true, // to avoid CORS problems (see: https://***.com/a/52913505/331281)
        transport: HttpTransportType.WebSockets,
    )
...
    

但是,这会冒CSWSH 的风险。因此,在服务器端,我们必须检查原始标头以减轻这种情况。它可以在 cookie 值被复制到 JWT Bearer 身份验证上下文的地方完成:

services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options => // https://***.com/a/66485247/331281

    options.Events = new JwtBearerEvents
    
        OnMessageReceived = context =>
        
            // for SignalR authentication we need to read the access token form the cookie
            // since we don't want to pass the authentication token through the query string
            // as the query string is being logged
            if (context.HttpContext.Request.Path.StartsWithSegments(SignalRHubPath))
            
                var allowedOrigins = Configuration["SignalR:AllowedOrigins"].Split(';');
                if (allowedOrigins.Contains(context.Request.Headers["Origin"].ToString())) // see: https://www.tpeczek.com/2017/07/preventing-cross-site-websocket.html
                
                    context.Token = context.Request.Cookies["X-Authorization"];
                
                else
                
                    context.Response.StatusCode = StatusCodes.Status403Forbidden;
                
            
            return Task.CompletedTask;
        
    ;
);

【讨论】:

以上是关于如何使 SignalR 承载身份验证安全或如何不记录查询字符串的主要内容,如果未能解决你的问题,请参考以下文章

.Net SignalR 在还配置了 Cookie 身份验证时使用 JWT 承载身份验证

Blazor WebAssembly SignalR 身份验证

SignalR - 使用访问令牌进行身份验证

使用 Blazor wasm Bearer Token 进行 SignalR 身份验证

如何使用 WebAPI 制作 HTML5 视频标签、承载身份验证?

如何使用AngularJS将身份验证承载令牌存储在浏览器cookie中