Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
de Patrick Fletcher, Tom FitzMacken
Advertencia
Esta documentación no es para la versión más reciente de SignalR. Eche un vistazo a ASP.NET Core SignalR.
En este artículo se describen los problemas de seguridad que debe tener en cuenta al desarrollar una aplicación SignalR.
Versiones de software usadas en este tema
- Visual Studio 2013
- .NET 4.5
- SignalR versión 2
Versiones anteriores de este tema
Para obtener información sobre las versiones anteriores de SignalR, consulte Versiones anteriores de SignalR.
Preguntas y comentarios
Deje sus comentarios sobre cómo le gustó este tutorial y lo que podríamos mejorar en los comentarios en la parte inferior de la página. Si tiene preguntas que no están directamente relacionadas con el tutorial, puede publicarlas en el foro de ASP.NET SignalR o StackOverflow.com.
Información general
Este documento contiene las siguientes secciones:
Conceptos de seguridad de SignalR
Autenticación y autorización
SignalR no proporciona ninguna característica para autenticar a los usuarios. En su lugar, integre las características de SignalR en la estructura de autenticación existente para una aplicación. Los usuarios se autentican como lo haría normalmente en la aplicación y funcionan con los resultados de la autenticación en el código de SignalR. Por ejemplo, puede autenticar a los usuarios con ASP.NET autenticación de formularios y, a continuación, en el centro, aplicar qué usuarios o roles están autorizados para llamar a un método. En el centro, también puede pasar información de autenticación, como el nombre de usuario o si un usuario pertenece a un rol, al cliente.
SignalR proporciona el atributo Authorize para especificar qué usuarios tienen acceso a un centro o método. El atributo Authorize se aplica a un centro o a métodos concretos de un centro. Sin el atributo Authorize, todos los métodos públicos del centro están disponibles para un cliente que está conectado al centro. Para más información sobre los centros, consulte Autenticación y autorización para SignalR Hubs.
El atributo se aplica Authorize
a los concentradores, pero no a las conexiones persistentes. Para aplicar reglas de autorización al usar un PersistentConnection
, debe invalidar el AuthorizeRequest
método . Para obtener más información sobre las conexiones persistentes, consulte Autenticación y autorización para conexiones persistentes de SignalR.
Token de conexión
SignalR mitiga el riesgo de ejecutar comandos malintencionados validando la identidad del remitente. Para cada solicitud, el cliente y el servidor pasan un token de conexión que contiene el identificador de conexión y el nombre de usuario para los usuarios autenticados. El identificador de conexión identifica de forma única cada cliente conectado. El servidor genera aleatoriamente el identificador de conexión cuando se crea una nueva conexión y conserva ese identificador durante la duración de la conexión. El mecanismo de autenticación de la aplicación web proporciona el nombre de usuario. SignalR usa el cifrado y una firma digital para proteger el token de conexión.
Para cada solicitud, el servidor valida el contenido del token para asegurarse de que la solicitud procede del usuario especificado. El nombre de usuario debe corresponder al identificador de conexión. Al validar tanto el identificador de conexión como el nombre de usuario, SignalR impide que un usuario malintencionado suplanta a otro usuario fácilmente. Si el servidor no puede validar el token de conexión, se produce un error en la solicitud.
Dado que el identificador de conexión forma parte del proceso de comprobación, no debe revelar el identificador de conexión de un usuario a otros usuarios ni almacenar el valor en el cliente, como en una cookie.
Tokens de conexión frente a otros tipos de token
Las herramientas de seguridad marcan ocasionalmente los tokens de conexión porque parecen ser tokens de sesión o tokens de autenticación, lo que supone un riesgo si se expone.
El token de conexión de SignalR no es un token de autenticación. Se usa para confirmar que el usuario que realiza esta solicitud es el mismo que creó la conexión. El token de conexión es necesario porque ASP.NET SignalR permite que las conexiones se muevan entre servidores. El token asocia la conexión con un usuario determinado, pero no afirma la identidad del usuario que realiza la solicitud. Para que una solicitud de SignalR se autentique correctamente, debe tener algún otro token que aserte la identidad del usuario, como una cookie o un token de portador. Sin embargo, el propio token de conexión no hace ninguna notificación de que el usuario realizó la solicitud, solo que el identificador de conexión contenido en el token está asociado a ese usuario.
Dado que el token de conexión no proporciona ninguna notificación de autenticación propia, no se considera un token de "sesión" o "autenticación". Se producirá un error al tomar el token de conexión de un usuario determinado y reproducirlo en una solicitud autenticada como un usuario diferente (o una solicitud no autenticada), ya que la identidad del usuario de la solicitud y la identidad almacenada en el token no coincidirán.
Volver a unir grupos al volver a conectarse
De forma predeterminada, la aplicación SignalR volverá a asignar automáticamente un usuario a los grupos adecuados al volver a conectarse desde una interrupción temporal, como cuando se quita una conexión y se vuelve a establecer antes de que se agote el tiempo de espera de la conexión. Al volver a conectarse, el cliente pasa un token de grupo que incluye el identificador de conexión y los grupos asignados. El token de grupo está firmado digitalmente y cifrado. El cliente conserva el mismo identificador de conexión después de una reconexión; Por lo tanto, el identificador de conexión pasado desde el cliente reconectado debe coincidir con el identificador de conexión anterior usado por el cliente. Esta comprobación impide que un usuario malintencionado pase solicitudes para unirse a grupos no autorizados al volver a conectarse.
Sin embargo, es importante tener en cuenta que el token de grupo no expira. Si un usuario pertenecía a un grupo en el pasado, pero estaba prohibido de ese grupo, ese usuario puede ser capaz de imitar un token de grupo que incluya el grupo prohibido. Si necesita administrar de forma segura qué usuarios pertenecen a los grupos, debe almacenar esos datos en el servidor, como en una base de datos. A continuación, agregue lógica a la aplicación que comprueba en el servidor si un usuario pertenece a un grupo. Para obtener un ejemplo de comprobación de la pertenencia a grupos, consulte Trabajar con grupos.
Los grupos que se vuelven a unir automáticamente solo se aplican cuando se vuelve a conectar una conexión después de una interrupción temporal. Si un usuario se desconecta al alejarse de la aplicación o se reinicia la aplicación, la aplicación debe controlar cómo agregar ese usuario a los grupos correctos. Para obtener más información, consulte Trabajar con grupos.
Cómo SignalR impide la falsificación de solicitudes entre sitios
La falsificación de solicitud entre sitios (CSRF) es un ataque en el que un sitio malintencionado envía una solicitud a un sitio vulnerable donde el usuario ha iniciado sesión actualmente. SignalR evita CSRF haciendo que sea muy poco probable que un sitio malintencionado cree una solicitud válida para la aplicación SignalR.
Descripción del ataque CSRF
Este es un ejemplo de un ataque CSRF:
Un usuario inicia sesión en
www.example.com
, mediante la autenticación de formularios.El servidor autentica al usuario. La respuesta del servidor incluye una cookie de autenticación.
Sin cerrar sesión, el usuario visita un sitio web malintencionado. Este sitio malintencionado contiene el siguiente formato HTML:
<h1>You Are a Winner!</h1> <form action="http://example.com/api/account" method="post"> <input type="hidden" name="Transaction" value="withdraw" /> <input type="hidden" name="Amount" value="1000000" /> <input type="submit" value="Click Me"/> </form>
Observe que la acción de formulario publica en el sitio vulnerable, no en el sitio malintencionado. Esta es la parte "entre sitios" de CSRF.
El usuario hace clic en el botón Enviar. El explorador incluye la cookie de autenticación con la solicitud.
La solicitud se ejecuta en el servidor example.com con el contexto de autenticación del usuario y puede hacer cualquier cosa que pueda hacer un usuario autenticado.
Aunque en este ejemplo se requiere que el usuario haga clic en el botón del formulario, la página malintencionada podría ejecutar tan fácilmente un script que envíe una solicitud AJAX a la aplicación SignalR. Además, el uso de SSL no impide un ataque CSRF, ya que el sitio malintencionado puede enviar una solicitud de "https://".
Normalmente, los ataques CSRF son posibles contra sitios web que usan cookies para la autenticación, ya que los exploradores envían todas las cookies pertinentes al sitio web de destino. Sin embargo, los ataques CSRF no se limitan a aprovechar las cookies. Por ejemplo, la autenticación básica y Digest también son vulnerables. Una vez que un usuario inicia sesión con la autenticación básica o implícita, el explorador envía automáticamente las credenciales hasta que finaliza la sesión.
Mitigaciones de CSRF tomadas por SignalR
SignalR realiza los pasos siguientes para evitar que un sitio malintencionado cree solicitudes válidas a la aplicación. SignalR realiza estos pasos de forma predeterminada, no es necesario realizar ninguna acción en el código.
- Deshabilitación de solicitudes entre dominios SignalR deshabilita las solicitudes entre dominios para evitar que los usuarios llamen a un punto de conexión de SignalR desde un dominio externo. SignalR considera que cualquier solicitud de un dominio externo no es válida y bloquea la solicitud. Se recomienda mantener este comportamiento predeterminado; De lo contrario, un sitio malintencionado podría engañar a los usuarios para enviar comandos a su sitio. Si necesita usar solicitudes entre dominios, consulte Cómo establecer una conexión entre dominios.
- Pasar el token de conexión en la cadena de consulta, no la cookie SignalR pasa el token de conexión como un valor de cadena de consulta, en lugar de como una cookie. Almacenar el token de conexión en una cookie no es seguro porque el explorador puede reenviar accidentalmente el token de conexión cuando se encuentra código malintencionado. Además, pasar el token de conexión en la cadena de consulta impide que el token de conexión persista más allá de la conexión actual. Por lo tanto, un usuario malintencionado no puede realizar una solicitud en las credenciales de autenticación de otro usuario.
- Comprobación del token de conexión Como se describe en la sección Token de conexión , el servidor sabe qué identificador de conexión está asociado a cada usuario autenticado. El servidor no procesa ninguna solicitud de un identificador de conexión que no coincida con el nombre de usuario. Es poco probable que un usuario malintencionado pueda adivinar una solicitud válida porque el usuario malintencionado tendría que conocer el nombre de usuario y el identificador de conexión generado aleatoriamente. Ese identificador de conexión deja de ser válido en cuanto finaliza la conexión. Los usuarios anónimos no deben tener acceso a ninguna información confidencial.
Recomendaciones de seguridad de SignalR
Protocolo Secure Socket Layers (SSL)
El protocolo SSL usa el cifrado para proteger el transporte de datos entre un cliente y un servidor. Si la aplicación SignalR transmite información confidencial entre el cliente y el servidor, use SSL para el transporte. Para obtener más información sobre cómo configurar SSL, consulte Configuración de SSL en IIS 7.
No usar grupos como mecanismo de seguridad
Los grupos son una forma cómoda de recopilar usuarios relacionados, pero no son un mecanismo seguro para limitar el acceso a información confidencial. Esto es especialmente cierto cuando los usuarios pueden volver a unirse automáticamente a grupos durante una reconexión. En su lugar, considere la posibilidad de agregar usuarios con privilegios a un rol y limitar el acceso a un método concentrador solo a los miembros de ese rol. Para obtener un ejemplo de restricción del acceso basado en un rol, consulte Autenticación y autorización para SignalR Hubs. Para obtener un ejemplo de comprobación del acceso de los usuarios a grupos al volver a conectarse, consulte Trabajar con grupos.
Control seguro de la entrada de los clientes
Para asegurarse de que un usuario malintencionado no envía un script a otros usuarios, debe codificar toda la entrada de los clientes destinados a la difusión a otros clientes. Debe codificar mensajes en los clientes receptores en lugar del servidor, ya que la aplicación SignalR puede tener muchos tipos diferentes de clientes. Por lo tanto, la codificación HTML funciona para un cliente web, pero no para otros tipos de clientes. Por ejemplo, un método de cliente web para mostrar un mensaje de chat controlaría de forma segura el nombre de usuario y el mensaje llamando a la html()
función .
chat.client.addMessageToPage = function (name, message) {
// Html encode display name and message.
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#discussion').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</li>');
};
Conciliación de un cambio en el estado de usuario con una conexión activa
Si el estado de autenticación de un usuario cambia mientras existe una conexión activa, el usuario recibirá un error que indica que "La identidad del usuario no puede cambiar durante una conexión de SignalR activa". En ese caso, la aplicación debe volver a conectarse al servidor para asegurarse de que el identificador de conexión y el nombre de usuario están coordinados. Por ejemplo, si la aplicación permite al usuario cerrar sesión mientras existe una conexión activa, el nombre de usuario de la conexión ya no coincidirá con el nombre que se pasa para la siguiente solicitud. Querrá detener la conexión antes de que el usuario inicie sesión y, a continuación, reiniciarla.
Sin embargo, es importante tener en cuenta que la mayoría de las aplicaciones no tendrán que detener e iniciar manualmente la conexión. Si la aplicación redirige a los usuarios a una página independiente después de cerrar sesión, como el comportamiento predeterminado en una aplicación de Formularios Web Forms o la aplicación MVC, o actualiza la página actual después de cerrar sesión, la conexión activa se desconecta automáticamente y no requiere ninguna acción adicional.
En el ejemplo siguiente se muestra cómo detener e iniciar una conexión cuando el estado del usuario ha cambiado.
<script type="text/javascript">
$(function () {
var chat = $.connection.sampleHub;
$.connection.hub.start().done(function () {
$('#logoutbutton').click(function () {
chat.connection.stop();
$.ajax({
url: "Services/SampleWebService.svc/LogOut",
type: "POST"
}).done(function () {
chat.connection.start();
});
});
});
});
</script>
O bien, el estado de autenticación del usuario puede cambiar si el sitio usa la expiración deslizante con la autenticación de formularios y no hay ninguna actividad para mantener válida la cookie de autenticación. En ese caso, el usuario se cerrará la sesión y el nombre de usuario ya no coincidirá con el nombre de usuario en el token de conexión. Para solucionar este problema, agregue algún script que solicite periódicamente un recurso en el servidor web para mantener válida la cookie de autenticación. En el ejemplo siguiente se muestra cómo solicitar un recurso cada 30 minutos.
$(function () {
setInterval(function() {
$.ajax({
url: "Ping.aspx",
cache: false
});
}, 1800000);
});
Archivos proxy de JavaScript generados automáticamente
Si no desea incluir todos los concentradores y métodos en el archivo proxy de JavaScript para cada usuario, puede deshabilitar la generación automática del archivo. Puede elegir esta opción si tiene varios centros y métodos, pero no quiere que todos los usuarios conozcan todos los métodos. Para deshabilitar la generación automática, establezca EnableJavaScriptProxies en false.
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableJavaScriptProxies = false;
app.MapSignalR(hubConfiguration);
Para obtener más información sobre los archivos de proxy de JavaScript, consulte El proxy generado y lo que hace automáticamente.
Excepciones
Debe evitar pasar objetos de excepción a los clientes porque los objetos pueden exponer información confidencial a los clientes. En su lugar, llame a un método en el cliente que muestre el mensaje de error pertinente.
public Task SampleMethod()
{
try
{
// code that can throw an exception
}
catch(Exception e)
{
// add code to log exception and take remedial steps
return Clients.Caller.DisplayError("Sorry, the request could not be processed.");
}
}