c# - Autenticación cliente-servidor-¿usando SSPI?
.net windows-authentication (4)
Estoy trabajando en una aplicación cliente-servidor y quiero que el cliente se autentique a sí mismo con las credenciales de inicio de sesión del usuario, pero no quiero que el usuario tenga que escribir su nombre de usuario y contraseña. Ciertamente no quiero ser responsable de manejar las contraseñas de forma segura. Solo necesito que el usuario me demuestre que es quien dice ser, y luego mi servidor puede seguir adelante y otorgar / denegar los comandos a su gusto.
Mis usuarios forman parte de un dominio, por lo que quiero poder usar las credenciales de inicio de sesión que crearon cuando iniciaron sesión.
No estoy usando ningún tipo de servicios web, ni quiero hacerlo. Controlo el software del cliente y del servidor, y ambos están escritos en C # puro y utilizo sockets buenos para hacer el trabajo.
Preferiría hacer esto con C # /. Net puro, pero estoy abierto a usar C # inseguro y pinvokes para la API de win32 si eso significa que haré el trabajo.
He leído un poco acerca de SSPI en Windows, pero me siento un poco en la oscuridad ya que este tipo de desarrollo de aplicaciones es nuevo para mí.
¿Alguien sabe cómo hacer esto? ¿Es SSPI el camino? ¿Cómo se usa uno SSPI desde C #? ¿Existe una forma nativa de .Net para que mi código pueda permanecer portátil?
¿Alguna vez intentaste trabajar con WindowsIdentity?
Pure C # /. Net, serializable y GetCurrent () devuelve la cuenta de ejecución.
Token de seguridad
El usuario entrega un conjunto de reclamaciones a su aplicación en piggyback junto con su solicitud. En un servicio web, estas reclamaciones se incluyen en el encabezado de seguridad del sobre SOAP. En una aplicación web basada en navegador, las reclamaciones llegan a través de un HTTP POST desde el navegador del usuario, y luego se pueden almacenar en caché en una cookie si se desea una sesión. Independientemente de cómo lleguen, deben ser serializados de alguna manera, y aquí es donde entran los tokens de seguridad. Un token de seguridad es un conjunto serial de reclamos que está firmado digitalmente por la autoridad emisora. La firma es importante: le da seguridad de que el usuario no se limitó a realizar un montón de reclamos y se los envió. En situaciones de baja seguridad donde la criptografía no es necesaria o deseable, puede usar tokens sin firmar, pero ese no es un escenario en el que me centraré en este documento. Una de las características principales de WIF es la capacidad de crear y leer tokens de seguridad. WIF y la tubería subyacente en .NET Framework se encargan de todo el trabajo pesado criptográfico y presentan su aplicación con un conjunto de afirmaciones que puede leer.
citado de Windows Identity Foudation WhitePaper
Su pregunta principal fue:
"¿Existe una forma pura de C # / .NET para autenticar a los usuarios usando sus credenciales de inicio de sesión?"
WindowsIdentity "es" el token de autenticación emitido por su controlador de dominio y me parece que es el mejor enfoque en este momento.
Sabía muy poco acerca de WindowsIdentity cuando publiqué por primera vez, pero también sentí que ayudaría con su problema y restricciones. He leído mucho y finalmente he llegado a esta page .
La introducción de WIF se explica por sí misma, WindowsIdentity es un nuevo conjunto de .NET framework diseñado para las preocupaciones de seguridad basadas en Windows / basadas en roles.
SSPI, Kerberos son partes de todo el proceso de autenticación de Windows, el token de inicio de sesión obtenido por el usuario / máquina / proceso es otorgado por el controlador de dominio y no puede obtenerse "simplemente" instanciando un nuevo objeto WindowsIdentity. Si existiera este tipo de instanciación ilegal, todo el modelo de seguridad de Windows (dominios, UAC, etc.) estaría muerto.
Aquí hay un pequeño programa de consola que lanza una excepción si no es parte de "BUILTIN / Administrateurs" (cambie el nombre del grupo de acuerdo con sus propias necesidades). Siempre que "Ejecutar como administrador", el programa finaliza sin errores.
Hay un conjunto muy grande de permisos y cada demanda está basada en reclamaciones (¿es el miembro de identidad de xxx?)
using System;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;
namespace WindowsIdentityTest
{
class Program
{
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
static string SomeServerAction()
{ return "Authenticated users can access"; }
[PrincipalPermission(SecurityAction.Demand, Role = "BUILTIN//Administrateurs")]
static string SomeCriticalServerAction()
{ return "Only Admins can access"; }
static void Main(string[] args)
{
//This allows to perform security checks against the current Identity.
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
try
{
Console.WriteLine(SomeServerAction());
Console.WriteLine(SomeCriticalServerAction());
}
catch (SecurityException sec)
{
Console.WriteLine(string.Format("{0} : {1}/n------------/n{2}"
, sec.GetType()
, sec.Message
, sec.StackTrace));
}
catch (Exception ex)
{
Console.WriteLine("This shall not appen.");
}
Console.WriteLine("Press enter to quit.");
Console.ReadLine();
}
}
}
Espero que esto sea de ayuda.
Actualizar:
SSPI es el enfoque correcto para esto. La API no es demasiado difícil de usar, pero requiere un proyecto de tamaño decente para ajustarse a C #.
En el proceso de investigar los bits necesarios para resolver esta pregunta, escribí un proyecto para proporcionar SSPI en .Net. A continuación describo los conceptos básicos de la interfaz con la API SSPI de Windows para que cualquiera pueda replicar mis resultados. Si desea utilizar SSPI en .Net, puedo sugerirle que use el proyecto que creé para resolver esto:
NSspi - Una interfaz .Net para la API SSPI
SSPI le proporciona matrices de bytes sin procesar que contienen tokens de autenticación que luego decide cómo transmitir, ya sea a través de un socket con mensajes en formato binario, un canal XML personalizado, .Net Remoting, alguna forma de WCF, incluso un puerto serie. Tienes que decidir cómo tratar con ellos. Con SSPI, un servidor puede autenticar clientes, identificar de forma segura al cliente e incluso realizar procedimientos básicos de manejo de mensajes como cifrado / firma utilizando el contexto de seguridad establecido con el cliente.
La API de SSPI se documenta aquí: Descripción general de la API de SSPI
En concreto echar un vistazo a las siguientes funciones:
- AcquireCredentialsHandle
- Adquiere un identificador de alguna forma de credenciales (por ejemplo, el inicio de sesión del usuario actual). Utilizado por servidores y clientes.
- InitializeSecurityContext
- Utilizado por los clientes para establecer un contexto de seguridad con un servidor.
- AcceptSecurityContext
- Utilizado por los servidores para establecer un contexto de seguridad con un cliente.
El flujo de trabajo típico es que cada lado inicializará sus credenciales utilizando AcquireCredentialsHandle. El ciclo de autenticación entonces comienza y progresa de la siguiente manera:
- El cliente invoca InitializeSecurityContext, sin proporcionar tokens de entrada, que devuelve tokens de salida en forma de una matriz de bytes. ISC devuelve ''ContinueNeeded'' para indicar que el ciclo de autenticación no está completo.
- El cliente envía los tokens al servidor por cualquier medio que desee.
- El servidor alimenta los tokens recibidos como entrada para AcceptSecurityContext y produce sus propios tokens de salida. ASC también devuelve ''ContinueNeeded'' para indicar que el ciclo de autenticación no está completo.
- El servidor luego envía sus tokens de salida al cliente.
- El cliente proporciona los tokens de los servidores como entrada para InitializeSecurityContext, que devuelve nuevos tokens de salida.
- El cliente envía sus nuevos tokens de salida al servidor.
- ...
Este ciclo continúa hasta que el cliente ve que InitializeSecurityContext devuelve "OK" y el servidor ve que AcceptSecurityContext devuelve "OK". Cada función puede devolver "OK" y aún proporcionar un token de salida (como lo indica un retorno no nulo), para indicar que aún tiene que enviar datos al otro lado. Así es como el cliente sabe que su mitad está terminada, pero el servidor aún está incompleto; y viceversa si el servidor se completa antes que el cliente. El lado que se complete primero (devuelve ''OK'') depende del paquete de seguridad específico que utiliza SSPI, y cualquier consumidor de SSPI debe tener esto en cuenta.
La información anterior debería ser suficiente para que cualquiera pueda interactuar con el sistema SSPI con el fin de proporcionar ''Autenticación integrada de Windows'' en su aplicación y replicar mis resultados.
A continuación, se encuentra mi respuesta anterior, ya que aprendí a invocar la API de SSPI.
Me había olvidado de esta pregunta, y casualmente volví a este problema hace unos días por un capricho. Necesito resolver este problema en un año o dos, aunque :)
Es posible en .Net, y actualmente estoy desarrollando un contenedor de .PI SSPI que pretendo publicar.
Estoy basando mi trabajo en algunas msdn.microsoft.com/en-us/library/ms973911.aspx de Microsoft que encontré.
El ejemplo contiene un conjunto administrado de C ++ / CLI que implementa las partes necesarias de la API de SSPI (en la carpeta Microsoft/Samples/Security/SSPI/SSPI
extraída del archivo REMSSPI.exe). Luego tienen dos interfaces de usuario, una aplicación cliente y una aplicación de servidor, ambas escritas en C # que hacen uso de esta API para realizar la autenticación SSPI.
Las UIs hacen uso de la facilidad remota de .Net para unirlas todas, pero si entiendo la API de SSPI correctamente, la única información que el cliente y el servidor necesitan intercambiar consiste en bytes [] s que contienen datos de token de contexto de seguridad, que pueden fácilmente integrado en cualquier infraestructura de comunicaciones que desee; En mi caso, un protocolo binario de mi propio diseño.
Algunas notas sobre cómo hacer que la muestra funcione: tienen la fuente de la biblioteca ''SSPI'', que se compila mejor en VS 2005, aunque la he hecho funcionar en 2008; 2010 o superior requeriría un poco de trabajo, ya que utilizan construcciones de lenguaje que están en desuso. Es posible que también deba modificar los archivos de encabezado que forman parte del SDK de su plataforma, ya que utilizan asignaciones de puntero const a las variables inconscientes, y no conozco una mejor manera de hacer feliz al compilador (nunca he usado C ++ / CLI antes).
Incluyen una dll de SSPI compilada en la carpeta Microsoft / Samples / Security / SSPI / bin. Para que los binarios cliente / servidor funcionen, debe copiar esa dll en su directorio bin, de lo contrario, la resolución del ensamblado no funcionará.
Así que para resumir:
- Vaya msdn.microsoft.com/en-us/library/ms973911.aspx para descargar el archivo zip extraíble de muestra REMSSPI.exe.
- Extraiga el archivo REMSSPI.exe (dos veces ..)
- Microsoft / Samples / Security / SSPI /
-
bin/
- contiene dll compiladoMicrosoft.Samples.Security.SSPI.dll
-
SSPI/
- contiene fuente a dll -
Sample/
- contiene código fuente de UI-
bin/
- Contiene compilaciones de interfaz de usuario. Copie el archivo SSPI.dll aquí y ejecuteControlPanel.Client.exe
yControlPanel.Server.exe
-
-
Me equivoqué totalmente con WindowsIdentity (lo cual es bueno para la autorización ) porque olvidé que WCF maneja muchas cosas con archivos de configuración, seguridad de punto final y seguridad de mensajes / transporte.
¿Has probado con NegotiateStream ? El ejemplo dado parece ajustarse mejor a sus necesidades: utiliza Kerberos para la autenticación antes de permitir cualquier lectura / escritura. El uso de CredentialCache.DefaultNetworkCredentials
debería evitar que solicite una contraseña.
Nikola es correcta; no hay una forma nativa de .NET de lograr lo que está haciendo (al menos, no está utilizando el soporte de .NET Sockets de bajo nivel). Ciertamente, puedes sumergirte bajo las sábanas para hacer un poco de magia negra interoperatoria, pero si tanto el cliente como el servidor están bajo tu control, deberías considerar subir un poco la pila y usar una API de nivel superior como WCF, que SI tener soporte nativo de .NET para la autenticación integrada de Windows.
De acuerdo con su pregunta y el entorno descrito, podrá usar NetTcpBinding, que ofrece un alto rendimiento, así como la plomería para el flujo de autenticación / identidad que está buscando (también ofrece una forma bastante clara de manejar la autorización). utilizando la clase ServiceAuthorizationManager). Sin saber los detalles específicos de su aplicación / servicio, no puedo proporcionar un "Cómo" para implementar lo que está buscando hacer, pero puedo señalarle los documentos que tienen un ejemplo razonablemente simple.