Consideraciones de seguridad en ASP.NET Core SignalR

Por Andrew Stanton-Nurse

En este artículo se proporciona información sobre cómo proteger SignalR.

Uso compartido de recursos entre orígenes

El uso compartido de recursos entre orígenes (CORS) se puede usar para permitir conexiones de SignalR entre orígenes en el explorador. Si el código de JavaScript se hospeda en un dominio diferente de la aplicación SignalR, el middleware de CORS debe estar habilitado para permitir que JavaScript se conecte a la aplicación SignalR. Permita solicitudes entre orígenes solo de dominios en los que confíe o controle. Por ejemplo:

  • El sitio se hospeda en http://www.example.com
  • La aplicación SignalR se hospeda en http://signalr.example.com

CORS debe configurarse en la aplicación SignalR para permitir solo el origen www.example.com.

Para obtener más información acerca de la configuración de CORS, vea Habilitar solicitudes entre orígenes (CORS). SignalRrequiere las siguientes directivas de CORS:

  • Permita los orígenes esperados específicos. Permitir cualquier origen es posible, pero no es seguro ni recomendado.
  • Se deben permitir los métodos HTTP GET y POST.
  • Se deben permitir credenciales para que las sesiones permanentes basadas en cookie funcionen correctamente. Deben habilitarse incluso cuando no se usa la autenticación.

Sin embargo, en la versión 5.0 hemos proporcionado una opción en el cliente de TypeScript para no usar credenciales. La opción de no usar credenciales solo debe usarse cuando se sepa 100 % que credenciales como Cookies no son necesarias en la aplicación (las cookies las usa Azure App Service cuando se usan varios servidores para sesiones permanentes).

Por ejemplo, la siguiente directiva de CORS resaltada permite que un cliente del explorador de SignalR hospedado en https://example.com acceda a la aplicación SignalR hospedada en https://signalr.example.com:

using SignalRChat.Hubs;

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy =>
                      {
                          policy.WithOrigins("http://example.com");
                          policy.WithMethods("GET", "POST");
                          policy.AllowCredentials();
                      });
});

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddSignalR();

var app = builder.Build();

app.MapHub<ChatHub>("/chatHub");

En el ejemplo anterior, la directiva CORS se personaliza para permitir orígenes, métodos y credenciales específicos. Para obtener más información sobre cómo personalizar las directivas de CORS y el middleware en ASP.NET Core, consulte Middleware de CORS: CORS con directivas con nombre y middleware.

Restricción de orígenes de WebSocket

Las protecciones proporcionadas por CORS no se aplican a WebSockets. Para la restricción de orígenes en WebSockets, lea Restricción de orígenes de WebSockets.

ConnectionId

Exponer el ConnectionId puede provocar suplantación malintencionada si la versión del cliente o el servidor de SignalR es ASP.NET Core 2.2 o versiones anteriores. Si la versión del cliente o el servidor de SignalR son ASP.NET Core 3.0 o posterior, se debe conservar en secreto el ConnectionToken en lugar del ConnectionId. El objeto ConnectionToken no se expone a propósito en ninguna API. Puede ser difícil asegurarse de que los clientes de SignalR más antiguos no se conectan al servidor, por lo que incluso si la versión del servidor de SignalR es ASP.NET Core 3.0 o posterior, el ConnectionId no se debe exponer.

Registro de tokens de acceso

Al usar WebSockets o eventos Server-Sent, el cliente del explorador envía el token de acceso en la cadena de consulta. La recepción del token de acceso a través de la cadena de consulta suele ser tan segura como el uso del encabezado estándar de Authorization. Use siempre HTTPS para garantizar una conexión de un extremo a otro segura entre el cliente y el servidor. Muchos servidores web registran la dirección URL de cada solicitud, incluida la cadena de consulta. El registro de las direcciones URL puede registrar el token de acceso. ASP.NET Core registra la dirección URL de cada solicitud de forma predeterminada, que incluye la cadena de consulta. Por ejemplo:

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/chathub?access_token=1234

Si tiene dudas sobre cómo registrar estos datos con los registros de servidor, puede deshabilitar este registro por completo configurando el registrador Microsoft.AspNetCore.Hosting en el nivel de Warning o superior (estos mensajes se escriben en el nivel de Info). Para obtener más información, consulte Aplicar reglas de filtro de registro en el código para obtener más información. Si desea registrar cierta información de solicitud, puede escribir middleware para registrar los datos que necesita y filtrar el valor de la cadena de consulta de access_token (si está presente).

Excepciones

Los mensajes de excepción generalmente se consideran datos confidenciales que no se deben revelar a un cliente. De forma predeterminada, SignalR no envía al cliente los detalles de una excepción iniciada por un método del concentrador. En su lugar, el cliente recibe un mensaje genérico en el que se indica que se ha producido un error. La entrega de mensajes de excepción al cliente se puede invalidar (por ejemplo, en desarrollo o prueba) con EnableDetailedErrors. Los mensajes de excepción no se deben exponer al cliente en las aplicaciones de producción.

Administración de búfer

SignalR usa búferes por conexión para administrar los mensajes entrantes y salientes. De forma predeterminada, SignalR limita estos búferes a 32 KB. El mensaje más grande que un cliente o servidor puede enviar es de 32 KB. La memoria máxima que consume una conexión para mensajes es de 32 KB. Si los mensajes siempre son inferiores a 32 KB, puede reducir el límite, que:

  • Impide que un cliente pueda enviar un mensaje más grande.
  • El servidor nunca tendrá que asignar búferes grandes para aceptar mensajes.

Si los mensajes tienen más de 32 KB, puede aumentar el límite. Aumentar este límite significa:

  • El cliente puede hacer que el servidor asigne búferes de memoria grandes.
  • La asignación de servidores de búferes grandes puede reducir el número de conexiones simultáneas.

Hay límites para los mensajes entrantes y salientes, ambos se pueden configurar en el objeto HttpConnectionDispatcherOptions configurado en MapHub:

  • ApplicationMaxBufferSize representa el número máximo de bytes del cliente que el servidor almacena en búfer. Si el cliente intenta enviar un mensaje mayor que este límite, se puede cerrar la conexión.
  • TransportMaxBufferSize representa el número máximo de bytes que puede enviar el servidor. Si el servidor intenta enviar un mensaje (incluidos los valores devueltos de los métodos de concentrador) mayor que este límite, se producirá una excepción.

Si se establece el límite en 0, se deshabilita el límite. Al quitar el límite, un cliente puede enviar un mensaje de cualquier tamaño. Los clientes malintencionados que envían mensajes grandes pueden hacer que se asigne memoria excesiva. El exceso de uso de memoria puede reducir significativamente el número de conexiones simultáneas.

En este artículo se proporciona información sobre cómo proteger SignalR.

Uso compartido de recursos entre orígenes

El uso compartido de recursos entre orígenes (CORS) se puede usar para permitir conexiones de SignalR entre orígenes en el explorador. Si el código de JavaScript se hospeda en un dominio diferente de la aplicación SignalR, el middleware de CORS debe estar habilitado para permitir que JavaScript se conecte a la aplicación SignalR. Permita solicitudes entre orígenes solo de dominios en los que confíe o controle. Por ejemplo:

  • El sitio se hospeda en http://www.example.com
  • La aplicación SignalR se hospeda en http://signalr.example.com

CORS debe configurarse en la aplicación SignalR para permitir solo el origen www.example.com.

Para obtener más información acerca de la configuración de CORS, vea Habilitar solicitudes entre orígenes (CORS). SignalRrequiere las siguientes directivas de CORS:

  • Permita los orígenes esperados específicos. Permitir cualquier origen es posible, pero no es seguro ni recomendado.
  • Se deben permitir los métodos HTTP GET y POST.
  • Se deben permitir credenciales para que las sesiones permanentes basadas en cookie funcionen correctamente. Deben habilitarse incluso cuando no se usa la autenticación.

Sin embargo, en la versión 5.0 hemos proporcionado una opción en el cliente de TypeScript para no usar credenciales. La opción de no usar credenciales solo debe usarse cuando se sepa 100 % que credenciales como Cookies no son necesarias en la aplicación (las cookies las usa Azure App Service cuando se usan varios servidores para sesiones permanentes).

Por ejemplo, la siguiente directiva de CORS resaltada permite que un cliente del explorador de SignalR hospedado en https://example.com acceda a la aplicación SignalR hospedada en https://signalr.example.com:

using SignalRChat.Hubs;

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy =>
                      {
                          policy.WithOrigins("http://example.com");
                          policy.WithMethods("GET", "POST");
                          policy.AllowCredentials();
                      });
});

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddSignalR();

var app = builder.Build();

app.MapHub<ChatHub>("/chatHub");

En el ejemplo anterior, la directiva CORS se personaliza para permitir orígenes, métodos y credenciales específicos. Para obtener más información sobre cómo personalizar las directivas de CORS y el middleware en ASP.NET Core, consulte Middleware de CORS: CORS con directivas con nombre y middleware.

Restricción de orígenes de WebSocket

Las protecciones proporcionadas por CORS no se aplican a WebSockets. Para la restricción de orígenes en WebSockets, lea Restricción de orígenes de WebSockets.

ConnectionId

Exponer el ConnectionId puede provocar suplantación malintencionada si la versión del cliente o el servidor de SignalR es ASP.NET Core 2.2 o versiones anteriores. Si la versión del cliente o el servidor de SignalR son ASP.NET Core 3.0 o posterior, se debe conservar en secreto el ConnectionToken en lugar del ConnectionId. El objeto ConnectionToken no se expone a propósito en ninguna API. Puede ser difícil asegurarse de que los clientes de SignalR más antiguos no se conectan al servidor, por lo que incluso si la versión del servidor de SignalR es ASP.NET Core 3.0 o posterior, el ConnectionId no se debe exponer.

Registro de tokens de acceso

Al usar WebSockets o eventos Server-Sent, el cliente del explorador envía el token de acceso en la cadena de consulta. La recepción del token de acceso a través de la cadena de consulta suele ser tan segura como el uso del encabezado estándar de Authorization. Use siempre HTTPS para garantizar una conexión de un extremo a otro segura entre el cliente y el servidor. Muchos servidores web registran la dirección URL de cada solicitud, incluida la cadena de consulta. El registro de las direcciones URL puede registrar el token de acceso. ASP.NET Core registra la dirección URL de cada solicitud de forma predeterminada, que incluye la cadena de consulta. Por ejemplo:

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/chathub?access_token=1234

Si tiene dudas sobre cómo registrar estos datos con los registros de servidor, puede deshabilitar este registro por completo configurando el registrador Microsoft.AspNetCore.Hosting en el nivel de Warning o superior (estos mensajes se escriben en el nivel de Info). Para obtener más información, consulte Aplicar reglas de filtro de registro en el código para obtener más información. Si desea registrar cierta información de solicitud, puede escribir middleware para registrar los datos que necesita y filtrar el valor de la cadena de consulta de access_token (si está presente).

Excepciones

Los mensajes de excepción generalmente se consideran datos confidenciales que no se deben revelar a un cliente. De forma predeterminada, SignalR no envía al cliente los detalles de una excepción iniciada por un método del concentrador. En su lugar, el cliente recibe un mensaje genérico en el que se indica que se ha producido un error. La entrega de mensajes de excepción al cliente se puede invalidar (por ejemplo, en desarrollo o prueba) con EnableDetailedErrors. Los mensajes de excepción no se deben exponer al cliente en las aplicaciones de producción.

Administración de búfer

SignalR usa búferes por conexión para administrar los mensajes entrantes y salientes. De forma predeterminada, SignalR limita estos búferes a 32 KB. El mensaje más grande que un cliente o servidor puede enviar es de 32 KB. La memoria máxima que consume una conexión para mensajes es de 32 KB. Si los mensajes siempre son inferiores a 32 KB, puede reducir el límite, que:

  • Impide que un cliente pueda enviar un mensaje más grande.
  • El servidor nunca tendrá que asignar búferes grandes para aceptar mensajes.

Si los mensajes tienen más de 32 KB, puede aumentar el límite. Aumentar este límite significa:

  • El cliente puede hacer que el servidor asigne búferes de memoria grandes.
  • La asignación de servidores de búferes grandes puede reducir el número de conexiones simultáneas.

Hay límites para los mensajes entrantes y salientes, ambos se pueden configurar en el objeto HttpConnectionDispatcherOptions configurado en MapHub:

  • ApplicationMaxBufferSize representa el número máximo de bytes del cliente que el servidor almacena en búfer. Si el cliente intenta enviar un mensaje mayor que este límite, se puede cerrar la conexión.
  • TransportMaxBufferSize representa el número máximo de bytes que puede enviar el servidor. Si el servidor intenta enviar un mensaje (incluidos los valores devueltos de los métodos de concentrador) mayor que este límite, se producirá una excepción.

Si se establece el límite en 0, se deshabilita el límite. Al quitar el límite, un cliente puede enviar un mensaje de cualquier tamaño. Los clientes malintencionados que envían mensajes grandes pueden hacer que se asigne memoria excesiva. El exceso de uso de memoria puede reducir significativamente el número de conexiones simultáneas.

En este artículo se proporciona información sobre cómo proteger SignalR.

Uso compartido de recursos entre orígenes

El uso compartido de recursos entre orígenes (CORS) se puede usar para permitir conexiones de SignalR entre orígenes en el explorador. Si el código de JavaScript se hospeda en un dominio diferente de la aplicación SignalR, el middleware de CORS debe estar habilitado para permitir que JavaScript se conecte a la aplicación SignalR. Permita solicitudes entre orígenes solo de dominios en los que confíe o controle. Por ejemplo:

  • El sitio se hospeda en http://www.example.com
  • La aplicación SignalR se hospeda en http://signalr.example.com

CORS debe configurarse en la aplicación SignalR para permitir solo el origen www.example.com.

Para obtener más información acerca de la configuración de CORS, vea Habilitar solicitudes entre orígenes (CORS). SignalRrequiere las siguientes directivas de CORS:

  • Permita los orígenes esperados específicos. Permitir cualquier origen es posible, pero no es seguro ni recomendado.
  • Se deben permitir los métodos HTTP GET y POST.
  • Se deben permitir credenciales para que las sesiones permanentes basadas en cookie funcionen correctamente. Deben habilitarse incluso cuando no se usa la autenticación.

Sin embargo, en la versión 5.0 hemos proporcionado una opción en el cliente de TypeScript para no usar credenciales. La opción de no usar credenciales solo debe usarse cuando se sepa 100 % que credenciales como Cookies no son necesarias en la aplicación (las cookies las usa Azure App Service cuando se usan varios servidores para sesiones permanentes).

Por ejemplo, la siguiente directiva de CORS resaltada permite que un cliente del explorador de SignalR hospedado en https://example.com acceda a la aplicación SignalR hospedada en https://signalr.example.com:

using SignalRChat.Hubs;

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy =>
                      {
                          policy.WithOrigins("http://example.com");
                          policy.WithMethods("GET", "POST");
                          policy.AllowCredentials();
                      });
});

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddSignalR();

var app = builder.Build();

app.MapHub<ChatHub>("/chatHub");

En el ejemplo anterior, la directiva CORS se personaliza para permitir orígenes, métodos y credenciales específicos. Para obtener más información sobre cómo personalizar las directivas de CORS y el middleware en ASP.NET Core, consulte Middleware de CORS: CORS con directivas con nombre y middleware.

Restricción de orígenes de WebSocket

Las protecciones proporcionadas por CORS no se aplican a WebSockets. Para la restricción de orígenes en WebSockets, lea Restricción de orígenes de WebSockets.

ConnectionId

Exponer el ConnectionId puede provocar suplantación malintencionada si la versión del cliente o el servidor de SignalR es ASP.NET Core 2.2 o versiones anteriores. Si la versión del cliente o el servidor de SignalR son ASP.NET Core 3.0 o posterior, se debe conservar en secreto el ConnectionToken en lugar del ConnectionId. El objeto ConnectionToken no se expone a propósito en ninguna API. Puede ser difícil asegurarse de que los clientes de SignalR más antiguos no se conectan al servidor, por lo que incluso si la versión del servidor de SignalR es ASP.NET Core 3.0 o posterior, el ConnectionId no se debe exponer.

Registro de tokens de acceso

Al usar WebSockets o eventos Server-Sent, el cliente del explorador envía el token de acceso en la cadena de consulta. La recepción del token de acceso a través de la cadena de consulta suele ser tan segura como el uso del encabezado estándar de Authorization. Use siempre HTTPS para garantizar una conexión de un extremo a otro segura entre el cliente y el servidor. Muchos servidores web registran la dirección URL de cada solicitud, incluida la cadena de consulta. El registro de las direcciones URL puede registrar el token de acceso. ASP.NET Core registra la dirección URL de cada solicitud de forma predeterminada, que incluye la cadena de consulta. Por ejemplo:

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/chathub?access_token=1234

Si tiene dudas sobre cómo registrar estos datos con los registros de servidor, puede deshabilitar este registro por completo configurando el registrador Microsoft.AspNetCore.Hosting en el nivel de Warning o superior (estos mensajes se escriben en el nivel de Info). Para obtener más información, consulte Aplicar reglas de filtro de registro en el código para obtener más información. Si desea registrar cierta información de solicitud, puede escribir middleware para registrar los datos que necesita y filtrar el valor de la cadena de consulta de access_token (si está presente).

Excepciones

Los mensajes de excepción generalmente se consideran datos confidenciales que no se deben revelar a un cliente. De forma predeterminada, SignalR no envía al cliente los detalles de una excepción iniciada por un método del concentrador. En su lugar, el cliente recibe un mensaje genérico en el que se indica que se ha producido un error. La entrega de mensajes de excepción al cliente se puede invalidar (por ejemplo, en desarrollo o prueba) con EnableDetailedErrors. Los mensajes de excepción no se deben exponer al cliente en las aplicaciones de producción.

Administración de búfer

SignalR usa búferes por conexión para administrar los mensajes entrantes y salientes. De forma predeterminada, SignalR limita estos búferes a 32 KB. El mensaje más grande que un cliente o servidor puede enviar es de 32 KB. La memoria máxima que consume una conexión para mensajes es de 32 KB. Si los mensajes siempre son inferiores a 32 KB, puede reducir el límite, que:

  • Impide que un cliente pueda enviar un mensaje más grande.
  • El servidor nunca tendrá que asignar búferes grandes para aceptar mensajes.

Si los mensajes tienen más de 32 KB, puede aumentar el límite. Aumentar este límite significa:

  • El cliente puede hacer que el servidor asigne búferes de memoria grandes.
  • La asignación de servidores de búferes grandes puede reducir el número de conexiones simultáneas.

Hay límites para los mensajes entrantes y salientes, ambos se pueden configurar en el objeto HttpConnectionDispatcherOptions configurado en MapHub:

  • ApplicationMaxBufferSize representa el número máximo de bytes del cliente que el servidor almacena en búfer. Si el cliente intenta enviar un mensaje mayor que este límite, se puede cerrar la conexión.
  • TransportMaxBufferSize representa el número máximo de bytes que puede enviar el servidor. Si el servidor intenta enviar un mensaje (incluidos los valores devueltos de los métodos de concentrador) mayor que este límite, se producirá una excepción.

Si se establece el límite en 0, se deshabilita el límite. Al quitar el límite, un cliente puede enviar un mensaje de cualquier tamaño. Los clientes malintencionados que envían mensajes grandes pueden hacer que se asigne memoria excesiva. El exceso de uso de memoria puede reducir significativamente el número de conexiones simultáneas.

En este artículo se proporciona información sobre cómo proteger SignalR.

Uso compartido de recursos entre orígenes

El uso compartido de recursos entre orígenes (CORS) se puede usar para permitir conexiones de SignalR entre orígenes en el explorador. Si el código de JavaScript se hospeda en un dominio diferente de la aplicación SignalR, el middleware de CORS debe estar habilitado para permitir que JavaScript se conecte a la aplicación SignalR. Permita solicitudes entre orígenes solo de dominios en los que confíe o controle. Por ejemplo:

  • El sitio se hospeda en http://www.example.com
  • La aplicación SignalR se hospeda en http://signalr.example.com

CORS debe configurarse en la aplicación SignalR para permitir solo el origen www.example.com.

Para obtener más información acerca de la configuración de CORS, vea Habilitar solicitudes entre orígenes (CORS). SignalRrequiere las siguientes directivas de CORS:

  • Permita los orígenes esperados específicos. Permitir cualquier origen es posible, pero no es seguro ni recomendado.
  • Se deben permitir los métodos HTTP GET y POST.
  • Se deben permitir credenciales para que las sesiones permanentes basadas en cookie funcionen correctamente. Deben habilitarse incluso cuando no se usa la autenticación.

Sin embargo, en la versión 5.0 hemos proporcionado una opción en el cliente de TypeScript para no usar credenciales. La opción de no usar credenciales solo debe usarse cuando se sepa 100 % que credenciales como Cookies no son necesarias en la aplicación (las cookies las usa Azure App Service cuando se usan varios servidores para sesiones permanentes).

Por ejemplo, la siguiente directiva de CORS permite que un cliente del explorador de SignalR hospedado en https://example.com acceda a la aplicación SignalR hospedada en https://signalr.example.com:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // ... other middleware ...

    // Make sure the CORS middleware is ahead of SignalR.
    app.UseCors(builder =>
    {
        builder.WithOrigins("https://example.com")
            .AllowAnyHeader()
            .WithMethods("GET", "POST")
            .AllowCredentials();
    });

    // ... other middleware ...
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<ChatHub>("/chathub");
    });

    // ... other middleware ...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // ... other middleware ...

    // Make sure the CORS middleware is ahead of SignalR.
    app.UseCors(builder =>
    {
        builder.WithOrigins("https://example.com")
            .AllowAnyHeader()
            .WithMethods("GET", "POST")
            .AllowCredentials();
    });

    // ... other middleware ...

    app.UseSignalR(routes =>
    {
        routes.MapHub<ChatHub>("/chathub");
    });

    // ... other middleware ...
}

Restricción de orígenes de WebSocket

Las protecciones proporcionadas por CORS no se aplican a WebSockets. Para la restricción de orígenes en WebSockets, lea Restricción de orígenes de WebSockets.

Las protecciones proporcionadas por CORS no se aplican a WebSockets. Los exploradores no hacen lo siguiente:

  • Efectúan solicitudes preparatorias CORS.
  • Respetan las restricciones especificadas en los encabezados Access-Control al efectuar solicitudes de WebSocket.

En cambio, sí que envían el encabezado Origin al emitir solicitudes de WebSocket. Las aplicaciones deben configurarse para validar estos encabezados a fin de garantizar que solo se permitan los WebSockets procedentes de los orígenes esperados.

En ASP.NET Core 2.1 y versiones posteriores, la validación de encabezados se puede lograr mediante un middleware personalizado colocado antes de UseSignalR, y el middleware de autenticación en Configure:


// In Startup, add a static field listing the allowed Origin values:
private static readonly HashSet<string> _allowedOrigins = new HashSet<string>()
{
    // Add allowed origins here. For example:
    "https://www.mysite.com",
    "https://mysite.com",
};

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // ... other middleware ...

    // Validate Origin header on WebSocket requests to prevent unexpected cross-site 
    // WebSocket requests.
    app.Use((context, next) =>
    {
        // Check for a WebSocket request.
        if (string.Equals(context.Request.Headers["Upgrade"], "websocket"))
        {
            var origin = context.Request.Headers["Origin"];

            // If there is an origin header, and the origin header doesn't match 
            // an allowed value:
            if (!string.IsNullOrEmpty(origin) && !_allowedOrigins.Contains(origin))
            {
                // The origin is not allowed, reject the request
                context.Response.StatusCode = (int) HttpStatusCode.Forbidden;
                return Task.CompletedTask;
            }
        }

        // The request is a valid Origin or not a WebSocket request, so continue.
        return next();
    });

    // ... other middleware ...

    app.UseSignalR(routes =>
    {
        routes.MapHub<ChatHub>("/chathub");
    });

    // ... other middleware ...
}

Nota:

El encabezado Origin está controlado por el cliente y, al igual que el encabezado Referer, se puede falsificar. Estos encabezados no se deben usar como mecanismo de autenticación.

ConnectionId

Exponer el ConnectionId puede provocar suplantación malintencionada si la versión del cliente o el servidor de SignalR es ASP.NET Core 2.2 o versiones anteriores. Si la versión del cliente o el servidor de SignalR son ASP.NET Core 3.0 o posterior, se debe conservar en secreto el ConnectionToken en lugar del ConnectionId. El objeto ConnectionToken no se expone a propósito en ninguna API. Puede ser difícil asegurarse de que los clientes de SignalR más antiguos no se conectan al servidor, por lo que incluso si la versión del servidor de SignalR es ASP.NET Core 3.0 o posterior, el ConnectionId no se debe exponer.

Registro de tokens de acceso

Al usar WebSockets o eventos Server-Sent, el cliente del explorador envía el token de acceso en la cadena de consulta. La recepción del token de acceso a través de la cadena de consulta suele ser tan segura como el uso del encabezado estándar de Authorization. Use siempre HTTPS para garantizar una conexión de un extremo a otro segura entre el cliente y el servidor. Muchos servidores web registran la dirección URL de cada solicitud, incluida la cadena de consulta. El registro de las direcciones URL puede registrar el token de acceso. ASP.NET Core registra la dirección URL de cada solicitud de forma predeterminada, que incluye la cadena de consulta. Por ejemplo:

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/chathub?access_token=1234

Si tiene dudas sobre cómo registrar estos datos con los registros de servidor, puede deshabilitar este registro por completo configurando el registrador Microsoft.AspNetCore.Hosting en el nivel de Warning o superior (estos mensajes se escriben en el nivel de Info). Para obtener más información, consulte Aplicar reglas de filtro de registro en el código para obtener más información. Si desea registrar cierta información de solicitud, puede escribir middleware para registrar los datos que necesita y filtrar el valor de la cadena de consulta de access_token (si está presente).

Excepciones

Los mensajes de excepción generalmente se consideran datos confidenciales que no se deben revelar a un cliente. De forma predeterminada, SignalR no envía al cliente los detalles de una excepción iniciada por un método del concentrador. En su lugar, el cliente recibe un mensaje genérico en el que se indica que se ha producido un error. La entrega de mensajes de excepción al cliente se puede invalidar (por ejemplo, en desarrollo o prueba) con EnableDetailedErrors. Los mensajes de excepción no se deben exponer al cliente en las aplicaciones de producción.

Administración de búfer

SignalR usa búferes por conexión para administrar los mensajes entrantes y salientes. De forma predeterminada, SignalR limita estos búferes a 32 KB. El mensaje más grande que un cliente o servidor puede enviar es de 32 KB. La memoria máxima que consume una conexión para mensajes es de 32 KB. Si los mensajes siempre son inferiores a 32 KB, puede reducir el límite, que:

  • Impide que un cliente pueda enviar un mensaje más grande.
  • El servidor nunca tendrá que asignar búferes grandes para aceptar mensajes.

Si los mensajes tienen más de 32 KB, puede aumentar el límite. Aumentar este límite significa:

  • El cliente puede hacer que el servidor asigne búferes de memoria grandes.
  • La asignación de servidores de búferes grandes puede reducir el número de conexiones simultáneas.

Hay límites para los mensajes entrantes y salientes, ambos se pueden configurar en el objeto HttpConnectionDispatcherOptions configurado en MapHub:

  • ApplicationMaxBufferSize representa el número máximo de bytes del cliente que el servidor almacena en búfer. Si el cliente intenta enviar un mensaje mayor que este límite, se puede cerrar la conexión.
  • TransportMaxBufferSize representa el número máximo de bytes que puede enviar el servidor. Si el servidor intenta enviar un mensaje (incluidos los valores devueltos de los métodos de concentrador) mayor que este límite, se producirá una excepción.

Si se establece el límite en 0, se deshabilita el límite. Al quitar el límite, un cliente puede enviar un mensaje de cualquier tamaño. Los clientes malintencionados que envían mensajes grandes pueden hacer que se asigne memoria excesiva. El exceso de uso de memoria puede reducir significativamente el número de conexiones simultáneas.