Guía de mitigación de amenazas para ASP.NET Core Blazor representación estática del lado servidor

En este artículo se explican las consideraciones de seguridad que los desarrolladores deben tener en cuenta al desarrollar Blazor Web Apps con representación estática del lado servidor.

Blazor combina tres modelos diferentes en uno para escribir aplicaciones web interactivas. Representación tradicional del lado servidor, que es un modelo de solicitud y respuesta basado en HTTP. Representación interactiva del lado servidor, que es un modelo de representación basado en SignalR. Por último, la representación del lado cliente, que es un modelo de representación basado en WebAssembly.

Todas las consideraciones de seguridad generales definidas para los modos de representación interactiva se aplican a Blazor Web Apps cuando hay componentes interactivos que se representan en uno de los modos de representación admitidos. En las secciones siguientes se explican las consideraciones de seguridad específicas de la representación del lado servidor no interactiva en Blazor Web Apps y los aspectos específicos que se aplican cuando los modos de representación interactúan entre sí.

Consideraciones generales para la representación del lado servidor

El modelo de representación del lado servidor (SSR) se basa en el modelo tradicional de solicitud/respuesta de HTTP. Por lo tanto, hay áreas comunes de preocupación entre SSR y HTTP de solicitud/respuesta. Las consideraciones generales de seguridad y las amenazas específicas deben mitigarse correctamente. El marco proporciona mecanismos integrados para administrar algunas de estas amenazas, pero otras amenazas son específicas del código de la aplicación y deben controlarse mediante la aplicación. Estas amenazas se pueden clasificar de la siguiente manera:

  • Autenticación y autorización: la aplicación debe asegurarse de que el usuario está autenticado y autorizado para acceder a la aplicación y a los recursos que expone. El marco proporciona mecanismos integrados para la autenticación y autorización, pero la aplicación debe asegurarse de que los mecanismos están configurados y se usan correctamente. Los mecanismos integrados de autenticación y autorización se tratan en el Blazor nodo de seguridad Servidor de la documentación y en el nodo Seguridad y Identityde la documentación ASP.NET Core, por lo que no se tratarán aquí.

  • Validación y saneamiento de entrada: todas las entradas que llegan desde un cliente deben validarse y sanearse antes de su uso. De lo contrario, la aplicación podría exponerse a ataques, como la inyección de código SQL, el scripting entre sitios, la falsificación de solicitudes entre sitios, la redirección abierta y otras formas de ataques. La entrada puede provenir de cualquier parte de la solicitud.

  • Administración de sesiones: administrar correctamente las sesiones de usuario es fundamental para asegurarse de que la aplicación no está expuesta a ataques, como la corrección de sesión, el secuestro de sesión y otros ataques. La información almacenada en la sesión debe estar protegida y cifrada correctamente, y el código de la aplicación debe impedir que un usuario malintencionado adivine o manipule las sesiones.

  • Control y registro de errores: la aplicación debe asegurarse de que los errores se controlan y registran correctamente. De lo contrario, la aplicación podría exponerse a ataques, como la divulgación de información. Esto puede ocurrir cuando la aplicación devuelve información confidencial en la respuesta o cuando la aplicación devuelve mensajes de error detallados con datos que se pueden usar para atacar la aplicación.

  • Protección de datos: los datos confidenciales deben protegerse correctamente, lo que incluye la lógica de la aplicación cuando se ejecuta en WebAssembly, ya que se puede diseñar fácilmente de forma inversa.

  • Denegación de servicio: la aplicación debe asegurarse de que no está expuesta a ataques, como la denegación de servicio. Esto sucede, por ejemplo, cuando la aplicación no está protegida correctamente frente a ataques por fuerza bruta o cuando una acción puede hacer que la aplicación consuma demasiados recursos.

Validación y saneamiento de entrada

Todas las entradas que llegan desde el cliente deben considerarse como de confianza a menos que se genere y proteja su información en el servidor, como un token CSRF, una autenticación cookie, un identificador de sesión o cualquier otra carga que esté protegida con cifrado autenticado.

Normalmente, la entrada está disponible para la aplicación a través de un proceso de enlace, por ejemplo a través del atributo [SupplyParameterFromQuery] o del atributo [SupplyParameterFromForm]. Antes de procesar esta entrada, la aplicación debe asegurarse de que los datos son válidos. Por ejemplo, la aplicación debe confirmar que no había errores de enlace al asignar los datos del formulario a una propiedad de componente. De lo contrario, la aplicación podría procesar datos no válidos.

Si la entrada se usa para realizar una redirección, la aplicación debe asegurarse de que la entrada es válida y que no apunta a un dominio considerado no válido o a una subruta no válida dentro de la ruta de acceso base de la aplicación. De lo contrario, la aplicación puede exponerse a ataques de redireccionamiento abiertos, donde un atacante puede crear un vínculo que redirige al usuario a un sitio malintencionado.

Si la entrada se usa para realizar una consulta de base de datos, la aplicación debe confirmar que la entrada es válida y que no expone la aplicación a ataques de inyección de código SQL. De lo contrario, un atacante podría crear una consulta malintencionada que se pueda usar para extraer información de la base de datos o modificarla.

Los datos que podrían provenir de la entrada del usuario también deben sanearse antes de incluirlos en una respuesta. Por ejemplo, la entrada puede contener HTML o JavaScript que se puede usar para realizar ataques de scripting entre sitios, que se pueden usar para extraer información del usuario o para realizar acciones en nombre del usuario.

El marco proporciona los siguientes mecanismos para ayudar con la validación y la sanación de entrada:

  • Todos los datos de formulario enlazados se validan para la corrección básica. Si no se puede analizar una entrada, el proceso de enlace notifica un error que la aplicación puede detectar antes de realizar cualquier acción con los datos. El componente integrado EditForm tiene esto en cuenta antes de invocar la devolución de llamada del formulario OnValidSubmit. Blazor evita ejecutar la devolución de llamada si hay uno o varios errores de enlace.
  • El marco usa un token antifalsificación para protegerse frente a ataques de falsificación de solicitudes entre sitios. Para obtener más información, consulte Autenticación y autorizaciónBlazor ASP.NET Core e Información general sobre formularios BlazorASP.NET Core.

Todos los permisos y entradas deben validarse en el servidor en el momento de realizar una acción determinada para asegurarse de que los datos sean válidos y precisos en ese momento y que el usuario pueda realizar la acción. Este enfoque es coherente con las instrucciones de seguridad proporcionadas para la representación interactiva del lado servidor.

Administración de sesiones

El marco controla la administración de sesiones. El marco usa una sesión cookie para identificar la sesión del usuario. La sesión cookie está protegida mediante las API de protección de datos principales de ASP.NET. La sesión cookie no es accesible para el código JavaScript que se ejecuta en el explorador y no se puede adivinar ni manipular fácilmente por un usuario.

Con respecto a otros datos de sesión, como los datos almacenados dentro de los servicios, los datos de sesión deben almacenarse dentro de los servicios de ámbito, ya que los servicios con ámbito son únicos por una sesión de usuario determinada, en lugar de los servicios singleton que se comparten entre todas las sesiones de usuario en una instancia de proceso determinada.

Cuando se trata de SSR, no hay mucha diferencia entre los servicios de ámbito y transitorios en la mayoría de los casos, ya que la duración del servicio se limita a una sola solicitud. Hay una diferencia en dos escenarios:

  • Si el servicio se inserta en más de una ubicación o en momentos diferentes durante la solicitud.
  • Si el servicio se puede usar en un contexto de servidor interactivo, donde sobrevive a varias representaciones y es fundamental que el servicio esté en el ámbito de la sesión del usuario.

Registro y control de errores

El marco proporciona registro integrado para la aplicación en el nivel de marco. El marco registra eventos importantes, como cuando el token antifalsificación de un formulario no se puede validar, cuando un componente raíz comienza a representarse y cuando se envía una acción. La aplicación es responsable de registrar cualquier otro evento que pueda ser importante para registrar.

El marco proporciona control de errores integrado para la aplicación en el nivel de marco. El marco controla los errores que se producen durante la representación de un componente y usa el mecanismo de límite de error para mostrar un mensaje de error descriptivo o permite que el error se propague hasta el middleware de control de excepciones, que está configurado para representar la página de error.

Los errores que se producen durante la representación de streaming después de que la respuesta se haya iniciado para enviarse al cliente se muestran en la respuesta final como un mensaje de error genérico. Los detalles sobre la causa del error solo se incluyen durante el desarrollo.

Protección de los datos

El marco ofrece mecanismos para proteger la información confidencial de una sesión de usuario determinada y garantiza que los componentes integrados usen estos mecanismos para proteger la información confidencial, como proteger la identidad de usuario al usar la autenticación cookie. Fuera de los escenarios que controla el marco, el código de desarrollador es responsable de proteger otra información específica de la aplicación. La forma más común de hacerlo es a través de las API de protección de datos principales de ASP.NET o cualquier otra forma de cifrado. Como regla general, la aplicación es responsable de:

  • Asegurarse de que un usuario no puede inspeccionar ni modificar la información privada de otro usuario.
  • Asegurarse de que un usuario no puede modificar los datos de usuario de otro usuario, como un identificador interno.

Con respecto a la protección de datos, debe comprender claramente dónde se ejecuta el código. Para la representación estática del lado del servidor (SSR estática) y la representación interactiva del lado del servidor (SSR interactiva), el código se almacena en el servidor y nunca llega al cliente. Para el modo de representación de WebAssembly interactivo, el código de la aplicación siempre llega al cliente, lo que significa que cualquier información confidencial almacenada en el código de la aplicación está disponible para cualquier persona con acceso a la aplicación. La ofuscación y otra técnica similar para "proteger" el código no es eficaz. Una vez que el código llega al cliente, se puede diseñar de forma inversa para extraer la información confidencial.

Denegación de servicio

En el nivel de servidor, el marco proporciona límites en los parámetros de solicitud y respuesta, como el tamaño máximo de la solicitud y el tamaño del encabezado. En cuanto al código de aplicación, Blazorel sistema de asignación de formularios define límites similares a los definidos por el sistema de enlace de modelos de MVC:

  • Límite en el número máximo de errores.
  • Límite de la profundidad máxima de recursión para el enlazador.
  • Límite del número máximo de elementos vinculados en una colección.

Además, hay límites definidos para el formulario, como el tamaño máximo de clave de formulario y el tamaño del valor y el número máximo de entradas.

En general, la aplicación debe evaluar cuándo existe la posibilidad de que una solicitud desencadene una cantidad asimétrica de trabajo por parte del servidor. Algunos ejemplos de esto incluyen cuando el usuario envía una solicitud parametrizada por N y el servidor realiza una operación en respuesta que es N veces más costosa, donde N es un parámetro que un usuario controla y puede crecer indefinidamente. Normalmente, la aplicación debe imponer un límite en el número máximo de N que está dispuesto a procesar o asegurarse de que cualquier operación sea menor, igual o más costosa que la solicitud por un factor constante.

Este aspecto tiene más que ver con la diferencia de crecimiento entre el trabajo que realiza el cliente y el trabajo que realiza el servidor que con una comparación específica de 1→N. Por ejemplo, un cliente podría enviar un elemento de trabajo (insertar elementos en una lista) que tarda N unidades de tiempo en realizar, pero el servidor necesita N^2^ para procesar (ya que podría estar haciendo algo muy naïve). Lo que importa es la diferencia entre N y N^2^.

Por lo tanto, hay un límite en cuanto al trabajo que el servidor debe estar dispuesto a hacer, que es específico de la aplicación. Este aspecto se aplica a las cargas de trabajo del lado servidor, ya que los recursos están en el servidor, pero no se aplican necesariamente a las cargas de trabajo de WebAssembly en el cliente en la mayoría de los casos.

El otro aspecto importante es que esto no solo está reservado al tiempo de CPU. También se aplica a los recursos, como la memoria, la red y el espacio en el disco.

En el caso de las cargas de trabajo de WebAssembly, normalmente hay poca preocupación sobre la cantidad de trabajo que realiza el cliente, ya que normalmente el cliente está limitado por los recursos disponibles en el cliente. Sin embargo, hay algunos escenarios en los que el cliente podría verse afectado, si por ejemplo, una aplicación muestra datos de otros usuarios y un usuario es capaz de agregar datos al sistema que obliga a los clientes que muestran los datos a realizar una cantidad de trabajo que no es proporcional a la cantidad de datos agregados por el usuario.

  • Asegúrese de que el usuario está autenticado y autorizado para acceder a la aplicación y a los recursos que expone.
  • Valide y sanee todas las entradas procedentes de un cliente antes de usarla.
  • Administre correctamente las sesiones de usuario para asegurarse de que el estado no se comparte erróneamente entre los usuarios.
  • Controle y registre correctamente los errores para evitar exponer información confidencial.
  • Registre eventos importantes en la aplicación para identificar posibles problemas y acciones de auditoría realizadas por los usuarios.
  • Proteja la información confidencial mediante las API de protección de datos principales de ASP.NET o uno de los componentes disponibles (Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage, PersistentComponentState).
  • Asegúrese de que la aplicación comprende los recursos que puede consumir una solicitud determinada y tiene límites para evitar ataques por denegación de servicio.