2008-09-30 15 views
5

Tenemos un servicio que maneja la autorización basada en un nombre de usuario y contraseña. En lugar de hacer que el nombre de usuario y la contraseña sean parte de la llamada, la colocamos en el encabezado SOAP.¿Cuáles son los posibles problemas con este esquema de seguridad de WebService?

En un escenario típico, un servicio web llama al servicio de autorización al inicio de la ejecución para verificar que la persona que llama puede llamarlo. Sin embargo, el problema es que algunos de estos servicios web se llaman entre sí, y eso significa que en cada subllamada se verifican los permisos del usuario, y eso puede ser muy costoso.

Lo que pensé hacer era hacer que el servicio de autorización devolviera un token de seguridad después de la primera llamada. Luego, en lugar de tener que llamar al servicio de autorización cada vez, el servicio web puede validar el encabezado de seguridad localmente.

La cabecera de seguridad se ve algo como esto (código C# - recortada para ilustrar el concepto esencial):

public sealed class SecurityHeader : SoapHeader 
{ 
    public string UserId;  // Encrypted 
    public string Password; // Encrypted; Just realized this field isn't necessary [thanks CJP] 

    public DateTime TimeStamp; // Used for calculating header Expiry 
    public string SecurityToken; 
} 

La idea general es que el SecurityHeader se comprueba con cada llamada. Si existe, no ha expirado, y SecurityToken es válido, entonces el Método web procede normalmente. De lo contrario, devolverá un error o intentará volver a autorizar y generar un nuevo SecurityHeader

El SecurityToken se basa en un hash salado de UserId, Password y TimeStamp. La sal se cambia todos los días para evitar repeticiones.

El único problema que veo es que un usuario puede tener permiso para acceder al servicio web A, pero no al servicio web B. Si llama a A y recibe un token de seguridad, tal como está ahora significa que B le permitirá a través de si él usa esa misma ficha. Tengo que cambiarlo para que el token de seguridad solo sea válido desde el servicio web al servicio web, en lugar del servicio de usuario a web, es decir. Debería estar bien si el usuario llama a A que llama a B, pero no está OK si el usuario llama al Servicio A y luego al Servicio D. Una forma de evitarlo es asignar una clave común (o un conjunto de claves) a servicios lógicamente relacionados. (es decir, si el cliente puede hacer A entonces lógicamente también puede hacer B).

Como alternativa, tendría que codificar el conjunto de permisos completo del usuario como parte del encabezado de seguridad. Tendré que investigar cuál será la sobrecarga.

Editar:

Varias personas han mencionado mirar otros sistemas de seguridad como WS-Security y SAML etc que ya tengo. De hecho, recibí la idea de WS-Security. El problema es que otros esquemas no proporcionan la funcionalidad que necesito (almacenamiento en caché de información de autorización y protección contra repeticiones sin una base de datos intermedia). Si alguien sabe de un plan que sí lo haga, lo usaré en lugar de glady. Además, esto es no acerca de la autenticación. Eso es manejado por otro mecanismo más allá de mi control.

Si resulta que no hay forma de almacenar en caché los datos de autorización, significa que tendré que incurrir en la sobrecarga de la autorización en cada nivel.

+0

Una aserción de SAML tiene el siguiente aspecto: "El cliente X tiene las funciones A y B. Esta afirmación es válida en el tiempo T. Firmado, servicio de autenticación." ¿Cómo es esto no lo que necesita? – ykaganovich

+0

Volveré a visitar SAML y XACML hoy. – ilitirit

Respuesta

1

Personalmente, no creo que tengas problemas allí, siempre y cuando tengas un marco subyacente centralizado para admitir la validación de los valores de SecurityToken.

2

Ok, reemplazando mis respuestas anteriores con una mejor.

Lo que describes debería funcionar si tienes una manera de compartir datos de forma segura entre tus servicios.Por ejemplo, si sus servicios comparten una clave secreta con el Servicio de Autorización, puede usar esta clave para obtener la sal.

Por cierto, no sé suficiente criptografía para decir si es lo suficientemente seguro como para agregar sal secreta + hash (aunque parece estar bien); Estoy bastante seguro de que es seguro HMAC con una clave secreta o privada. Rotar teclas es una buena idea, por lo que aún tendría una clave maestra y propagaría una nueva clave de firma.

Otros problemas con su enfoque son que (a) está codificando la lógica hash en cada servicio, y (b) los servicios pueden querer obtener datos más detallados del Servicio de Autorización que solo una respuesta sí/no. Por ejemplo, puede querer que el Servicio de Autorización inserte en el encabezado que este usuario pertenece a las funciones A y B pero no a C.

Como alternativa, puede dejar que el Servicio de Autorización cree una nueva cabecera con la información interesante que tiene, y firme ese bloque.

En este punto, estamos discutiendo una implementación de inicio de sesión único. Usted ya sabe sobre las especificaciones WS-Security. Este encabezado que describí suena muy parecido a una afirmación SAML.

Here's an article sobre el uso de WS-Security y SAML para Single Sign-On.

Ahora, no sé si necesita todo esto ... también hay soluciones intermedias. Por ejemplo, el Servicio de autorización podría firmar el bloque de nombre de usuario original; si te preocupa el rendimiento criptográfico público/privado y estás bien para compartir claves secretas, también puedes usar una clave secreta para firmar en lugar de claves públicas/privadas.

4

El problema fundamental con su esquema es que no está utilizando un marco estándar o implementación. Esto es independientemente de los méritos particulares de su esquema en sí.

La razón es simple, la seguridad (la criptografía en particular) es muy, muy complicada y casi imposible de hacer las cosas bien. Use una herramienta común que sea robusta, bien entendida y probada.

Ver: http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wss para obtener más información sobre WS-Security.

La mayoría de los marcos (.NET/JavaEE, etc.) tendrán soporte integrado (hasta cierto punto) para WS-Security.

Si cree que su plan es mejor de alguna manera que los estándares, le sugiero que lo escriba como un papel y lo envíe para su revisión por pares (junto con una implementación de referencia), pero NO lo use para asegurar Una aplicación.

EDIT para responder a OP Edición: Creo que estás confundiendo las funciones de autenticación y autorización de un poco, lo cual es fácil de hacer ...

El rollo de la señal de seguridad (o similar) en esquemas es autenticar al remitente del mensaje; básicamente, es el remitente quien debería ser. Como ha señalado con acierto, la autenticación no implica nada sobre los recursos subyacentes a los que se le debe otorgar acceso al remitente.

La autorización es el proceso mediante el cual toma un remitente autenticado y aplica un conjunto de permisos para que pueda restringir el ámbito de acceso. En general, los marcos no harán la autorización de manera predeterminada, debe habilitarla creando alguna forma de ACL o extendiendo algún tipo de interfaz tipo "Security Manager".

En efecto, la idea es que la capa de autenticación de ustedes que está intentando acceder a una página dice, y lo deja a usted para decidir si esa persona está autorizada a acceder a la página A.

Nunca se debe almacenar información sobre los derechos y permisos en el mensaje en sí; el receptor debe verificar los derechos contra su ACL (o base de datos o lo que sea) para cada mensaje. Esto limita su exposición en caso de que alguien descubra cómo modificar el mensaje.

+0

¿Ve algún problema potencial con él? – ilitirit

+0

Los problemas probablemente estarán en la implementación, p. si estás abierto a ataques de repetición, relleno, colisión, etc. Honestamente, no vale la pena el drama cuando se puede usar cosas que otras personas ya han hecho sus cabezas :) –

+0

Veo lo que quiere decir: no necesito almacenar la contraseña después de que el usuario haya sido autenticado. Eso solo hace las cosas un poco más simples. Sin embargo, todavía no ayuda con el problema inicial: almacenar en caché los permisos para que yo no * tenga * para verificarlo con cada mensaje (es una operación costosa) – ilitirit

0

Antes que nada, lea la publicación de @CJP, él hace un excelente y válido punto.
Si desea seguir adelante y rodar por sí mismo de todos modos (tal vez usted tiene una buena razón para ello), me gustaría hacer las siguientes observaciones:

  • Estás hablando de un servicio de autenticación, no una autorización Servicio. ¿Solo para asegurarte de que sabes de lo que estás hablando ...?
  • En segundo lugar, debe separar entre la sal (que no es un secreto) y la clave (que es). Debe tener un hash con clave (por ejemplo, HMAC), junto con sal (o un hash salado con llave. Suena como un sándwich). La sal, como se señaló, no es secreta, sino que debe cambiarse PARA CADA TESTAR y se puede incluir en el encabezado; la clave DEBE ser secreta y cambiarse todos los días es buena. Por supuesto, asegúrese de que está utilizando troceado fuerte (por ejemplo, SHA-256), las técnicas de gestión de claves adecuadas, etc, etc

Una vez más, le insto a que reconsidere rodar su propia, pero si usted tiene que salir por su cuenta ...

+0

No estoy hablando de un servicio de Autenticación, estoy hablando de autorización (permisos). Los valores de Sal pueden usarse como claves (también tengo una clave secreta). No he encontrado un esquema existente que maneje Autorización de terceros y ataques de repetición sin una base de datos intermediaria. – ilitirit

+0

Ok, después de editar veo su punto, pero todavía no es realmente autorización a menos que incluya el "conjunto de permisos". A lo sumo, su autenticación + acceso. – AviD

+0

Además, simplemente salar el hash no impedirá la suplantación, necesita un hash con clave para eso: la sal es para evitar los ataques de tablas del arco iris, por lo tanto, la necesidad de que sea único para cada token. – AviD

Cuestiones relacionadas