Estoy diseñando un servicio web RESTful al que deben acceder los usuarios, pero también otros servicios y aplicaciones web. Todas las solicitudes entrantes deben estar autenticadas. Toda la comunicación se realiza a través de HTTPS. La autenticación de usuario funcionará en función de un token de autenticación, adquirido mediante la POST del nombre de usuario y la contraseña (a través de una conexión SSL) a un recurso de sesión proporcionado por el servicio.
En el caso de los clientes de servicios web, no hay un usuario final detrás del servicio al cliente. Las solicitudes se inician mediante tareas programadas, eventos o algunas otras operaciones informáticas. La lista de servicios de conexión se conoce de antemano (obviamente, supongo). ¿Cómo debo autenticar estas solicitudes provenientes de otros servicios (web)? Quiero que el proceso de autenticación sea lo más fácil posible de implementar para esos servicios, pero no a costa de la seguridad. ¿Cuáles serían los estándares y las mejores prácticas para un escenario como este?
Opciones en las que puedo pensar (o que me han sugerido):
Haga que los servicios al cliente recurran a tener un nombre de usuario y contraseña "falsos", y autentíquelos de la misma manera que los usuarios. No me gusta esta opción, simplemente no se siente bien.
Asigne una identificación de aplicación permanente para el servicio del cliente, posiblemente también una clave de aplicación. Por lo que he entendido, esto es lo mismo que tener nombre de usuario + contraseña. Con esta identificación y clave, puedo autenticar cada solicitud o crear un token de autenticación para autenticar más solicitudes. De cualquier manera, no me gusta esta opción, porque cualquiera que pueda obtener la identificación y la clave de la aplicación puede hacerse pasar por el cliente.
Podría agregar una verificación de dirección IP a la opción anterior. Esto dificultaría la realización de solicitudes falsas.
Certificados de cliente. Configurar mi propia autoridad de certificación, crear un certificado raíz y crear certificados de cliente para los servicios del cliente. Sin embargo, me vienen a la mente un par de cuestiones: a) ¿cómo puedo permitir que los usuarios se autentiquen sin certificados yb) qué tan complicado es implementar este escenario desde el punto de vista del servicio al cliente?
Algo más, ¿debe haber otras soluciones por ahí?
Mi servicio se ejecutaría en Java, pero omití deliberadamente información sobre el marco específico en el que se construiría, porque estoy más interesado en los principios básicos y no tanto en los detalles de implementación; supongo que la mejor solución para esto será ser posible de implementar independientemente del marco subyacente. Sin embargo, soy un poco inexperto en este tema, por lo que también apreciaré mucho los consejos y ejemplos concretos sobre la implementación real (como bibliotecas útiles de terceros, artículos, etc.).
Respuestas:
Cualquier solución a este problema se reduce a un secreto compartido. Tampoco me gusta la opción de nombre de usuario y contraseña codificados, pero tiene la ventaja de ser bastante simple. El certificado de cliente también es bueno, pero ¿es realmente muy diferente? Hay un certificado en el servidor y otro en el cliente. Su principal ventaja es que es más difícil utilizar la fuerza bruta. Sin embargo, es de esperar que tenga otras protecciones para protegerse contra eso.
No creo que su punto A para la solución de certificado de cliente sea difícil de resolver. Solo usa una rama.
if (client side certificat) { check it } else { http basic auth }
No soy un experto en Java y nunca he trabajado con él para hacer certificados del lado del cliente. Sin embargo, un rápido Google nos lleva a este tutorial que busca su callejón.A pesar de toda esta discusión sobre "lo que es mejor", permítanme señalar que hay otra filosofía que dice, "menos código, menos inteligencia es mejor". (Yo personalmente sostengo esta filosofía). La solución de certificado de cliente parece mucho código.
Sé que expresó preguntas sobre OAuth, pero la propuesta de OAuth2 sí incluye una solución a su problema llamada " tokens de portador " que deben usarse junto con SSL. Creo que, en aras de la simplicidad, elegiría el usuario / pase codificado de forma rígida (uno por aplicación para que se puedan revocar individualmente) o los tokens de portador muy similares.
fuente
Después de leer su pregunta, diría, genere un token especial para realizar la solicitud requerida. Este token vivirá en un tiempo específico (digamos en un día).
Aquí hay un ejemplo de para generar un token de autenticación:
por ejemplo: 3 de junio de 2011
luego concatenar con la contraseña de usuario, ejemplo "my4wesomeP4ssword!"
Luego haz MD5 de esa cadena:
Cuando llames a una solicitud, usa siempre este token,
Este token es siempre único todos los días, por lo que creo que este tipo de protección es más que suficiente para proteger siempre nuestro servicio.
La esperanza ayuda
:)
fuente
Hay varios enfoques diferentes que puede tomar.
Los puristas de RESTful querrán que use la autenticación BÁSICA y envíe credenciales en cada solicitud. Su razón fundamental es que nadie almacena ningún estado.
El servicio al cliente podría almacenar una cookie, que mantiene una identificación de sesión. Personalmente, no encuentro esto tan ofensivo como algunos de los puristas de quienes escucho; puede ser costoso autenticarse una y otra vez. Sin embargo, parece que no te gusta mucho esta idea.
A partir de su descripción, realmente parece que podría estar interesado en OAuth2. Mi experiencia hasta ahora, por lo que he visto, es que es un poco confuso y un poco vanguardista. Hay implementaciones por ahí, pero son pocas y distantes entre sí. En Java, entiendo que se ha integrado en los módulos de seguridad de Spring3 . (Su tutorial está muy bien escrito). He estado esperando para ver si habrá una extensión en Restlet , pero hasta ahora, aunque se ha propuesto y puede estar en la incubadora, todavía no se ha incorporado por completo.
fuente
Creo que el enfoque:
es bastante estándar, independientemente de cómo lo implemente y otros detalles técnicos específicos.
Si realmente quiere ir más allá, tal vez podría considerar la clave https del cliente en un estado temporalmente inválido hasta que las credenciales sean validadas, limitar la información si nunca lo están y otorgar acceso cuando se validan, nuevamente en base a la expiración.
Espero que esto ayude
fuente
En lo que respecta al enfoque del certificado de cliente, no sería muy difícil de implementar y, al mismo tiempo, permitir la entrada a los usuarios sin certificados de cliente.
Si de hecho creara su propia Autoridad de Certificación autofirmada y emitiera certificados de cliente para cada servicio de cliente, tendría una manera fácil de autenticar esos servicios.
Dependiendo del servidor web que esté utilizando, debe haber un método para especificar la autenticación del cliente que aceptará un certificado de cliente, pero no lo requiere. Por ejemplo, en Tomcat al especificar su conector https, puede establecer 'clientAuth = want', en lugar de 'true' o 'false'. Luego, debe asegurarse de agregar su certificado CA autofirmado a su almacén de confianza (de forma predeterminada, el archivo cacerts en el JRE que está utilizando, a menos que haya especificado otro archivo en la configuración de su servidor web), por lo que los únicos certificados confiables serían los emitidos fuera de su CA autofirmado.
En el lado del servidor, solo permitiría el acceso a los servicios que desea proteger si puede recuperar un certificado de cliente de la solicitud (no nulo) y pasa cualquier verificación de DN si prefiere alguna seguridad adicional. Para los usuarios sin certificados de cliente, aún podrían acceder a sus servicios, pero simplemente no tendrán certificados presentes en la solicitud.
En mi opinión, esta es la forma más 'segura', pero ciertamente tiene su curva de aprendizaje y sus gastos generales, por lo que puede que no sea necesariamente la mejor solución para sus necesidades.
fuente
5. Algo más: ¿debe haber otras soluciones por ahí?
Tienes razón, ¡la hay! Y se llama JWT (JSON Web Tokens).
JSON Web Token (JWT) es un estándar abierto (RFC 7519) que define una forma compacta y autónoma de transmitir información de forma segura entre las partes como un objeto JSON. Esta información puede ser verificada y confiable porque está firmada digitalmente. Los JWT se pueden firmar usando un secreto (con el algoritmo HMAC) o un par de claves pública / privada usando RSA.
Recomiendo encarecidamente buscar JWT. Son una solución mucho más simple al problema en comparación con soluciones alternativas.
https://jwt.io/introduction/
fuente
Puede crear una sesión en el servidor y compartirla
sessionId
entre el cliente y el servidor con cada llamada REST.Primera solicitud REST autenticar:
/authenticate
. Devuelve la respuesta (según el formato de su cliente) consessionId: ABCDXXXXXXXXXXXXXX
;Almacenar esta
sessionId
enMap
la sesión real.Map.put(sessionid, session)
o utilizarSessionListener
para crear y destruir claves para usted;Obtenga sessionid con cada llamada REST, como
URL?jsessionid=ABCDXXXXXXXXXXXXXX
(o de otra manera);HttpSession
del mapa usandosessionId
;fuente
Usaría una aplicación para redirigir a un usuario a su sitio con un parámetro de identificación de la aplicación, una vez que el usuario aprueba la solicitud, genera un token único que la otra aplicación usa para la autenticación. De esta manera, las otras aplicaciones no manejan las credenciales de usuario y los usuarios pueden agregar, eliminar y administrar otras aplicaciones. Foursquare y algunos otros sitios se autentican de esta manera y es muy fácil de implementar como la otra aplicación.
fuente
Además de la autenticación, le sugiero que piense en el panorama general. Considere hacer su servicio RESTful backend sin ninguna autenticación; luego coloque un servicio de capa intermedia requerido de autenticación muy simple entre el usuario final y el servicio de backend.
fuente