Dva: muestra de autenticación oauth2

Creado en 5 sept. 2016  ·  26Comentarios  ·  Fuente: dvajs/dva

¿Hay ejemplos de OAuth2 de dva, cómo organizar modales y cómo verificar permisos?

Comentario más útil

En cuanto a la respuesta de @ u0x01 , dije mucha información confusa e inútil

De hecho, se puede resumir de la siguiente manera:

  1. Lanzar el access_token directamente al front-end en lugar de Session se debe a que necesita compartir la interfaz con el modo Cliente. Este tipo de interfaz a menudo no admite la verificación de la sesión, o es inconveniente administrar la sesión en un sistema distribuido.

  2. La seguridad contra ataques XSS y CSRF debe analizarse por separado

    2.1 Para evitar CSRF, el front-end coloca el access_token en el encabezado HTTP para enviar, y el back-end solo admite la verificación del encabezado, al mismo tiempo es suficiente diseñar bien la interfaz. Porque el sitio web de terceros no puede enviar encabezados HTTP adicionales solo a través del formulario, y el JS del sitio web de terceros no puede enviar datos a su propio sitio web (cuando CORS está configurado correctamente)

    2.2 Para evitar XSS, el front-end que almacena access_token es de hecho inseguro y JS puede leerlo a voluntad y enviarlo a través de dominios; y las cookies con HttpOnly establecidas son recursos de Credenciales. Los navegadores HttpOnly solo se puede decir que es un remedio

  3. La medida más segura es actuar como un proxy de entrada en el back-end y configurar el Access-Control-Allow-Origin CORS para permitir solo los nombres de dominio del front-end. Una vez que el usuario inicia sesión correctamente, se devuelve la sesión de HttpOnly y se agrega un código aleatorio como X-CSRF-TOKEN al campo del encabezado. Este código aleatorio existe con el access_token obtenido de la interfaz OAuth . El front-end usa Ajax o fetch para enviar datos con la cookie y este encabezado. Después de que el back-end verifica la validez de la cookie, necesita verificar la validez del encabezado X-CSRF .Básicamente, esto puede evitar que CSRF y XSS ordinario roben permisos

En resumen, la gestión de front-end de access_token no puede considerarse groseramente insegura

Actualización 1:

El middleware o backend usa jwt para cifrar access_token y, al mismo tiempo, forma la detección de inyección y CSP para evitar XSS

Todos 26 comentarios

¿No se realiza la verificación de oauth2 mediante la redirección de URL? Está bien si inicia sesión juzgando la cookie.

Parte de OAuht2 se realiza a través de access_token, no url, formato RESTFul puro

Sería mejor si hubiera un ejemplo de integración de dva y Spring Boot Oauth2: D

@soulmachine Yo uso esto, y lo resolveré

@WhatAKitty pasa el access_token, ¿dónde se almacena el access_token? Almacenado en local / seeionStorage tendrá riesgos de seguridad XSS.

@ u0x01 se almacena en localstorage. De hecho, no hay mucho riesgo. Access_token tiene un límite de tiempo. No puede iniciar sesión nuevamente después del tiempo de espera, y no hay permiso de refresh_token. Además, no hay otra forma, se consulta otra información relacionada y se almacena en localstorage.

@WhatAKitty Ahora los piratas informáticos usan o escriben herramientas automatizadas para atacar. El período de validez de dos horas de access_token es suficiente para hacer muchas cosas. ¿Cómo llegó a la conclusión de que "no hay demasiado riesgo"?
En segundo lugar, refresh_token no se coloca en localstorage, ¿dónde lo colocas?
El access_token es más adecuado para APP. El lado JS puro no debería usar el esquema de access_token. Aún existe el riesgo de ataques entre sitios.
La solución más segura ahora es agregar http-only a set-cookie.
Al verificar el inicio de sesión, lleve la cookie al servidor para obtener el estado de la sesión. Si falla, saltará directamente a la página de inicio de sesión.
La seguridad también es productividad, que es más importante que Taishan, por lo que no puede ser holgazán aquí.

@ u0x01 refresh_token, no se lo daré al cliente js. Por lo tanto, debe volver a certificarse una vez que expire. Es posible que no lo haya dejado claro antes, porque nuestra aplicación es así: access_token es solo una clave que le permite acceder. Si desea acceder a recursos específicos, debe pasar por la autenticación de usuario. Este proceso está protegido por SSL, por lo que no aparecerás. Dijeron varios riesgos.
En cuanto a la solución más segura que dijiste, también consideré el uso de cookies, pero una: no hice que el servidor fuera compatible con OAUTH2 y LOGIN PASSWORD al mismo tiempo, porque no puedo devolver un access_token después de iniciar sesión con LOGIN PASSWORD., Puede haber otras formas, pero no lo encontré. Segundo: debido al requerimiento de tiempo del proyecto, esta opción solo se puede seleccionar como un compromiso. Por lo tanto, este plan parece un poco inadecuado, pero de hecho no habrá problemas de seguridad.

@WhatAKitty nunca
Si puede garantizar que el sistema de su sitio web está 100% libre de vulnerabilidades XSS / CSRF, puede almacenarlo en localStorage y permitir que JS acceda a las credenciales directamente. (Pero nunca he visto a ninguna empresa que se haya atrevido a votar que su sistema no tiene lagunas de seguridad)

Y no entiendo qué significa acceder a recursos específicos, que deben ser autenticados por el usuario. En la especificación OAuth2, obtener access_token significa que el usuario (o Proveedor) ha aprobado esta autorización.

Además, mencionaste:
因为没法在使用 LOGIN PASSWORD 登录后给我返回一个access_token
Es un malentendido de la especificación OAUth2 y un uso incorrecto.

El método LOGIN PASSWORD es esencialmente un proceso en el que la UA solicita directamente la autenticación del proveedor OAUth2, consulte RFC6749 . En este momento, debe obtenerse el código_autorización. Después de que la UA obtenga el código_autorización, se enviará al Cliente para verificar la validez del Proveedor OAUth2. Si se pasa la verificación, el Cliente obtendrá el token de acceso del Proveedor OAUth2. En este momento, el Cliente puede usar access_token para acceder a los recursos. A continuación, el cliente emite un SessionID al UA.
(El cliente aquí se refiere al servidor o la APLICACIÓN de la parte comercial, no al usuario final, el usuario final es el propietario del recurso y la UA es el navegador)

Con todo, SessionID debe usarse para autenticar a los usuarios, incluso si no se usa SessionID, access_token debe colocarse en la cookie de solo http:

1. Don't use local storage for session identifiers. Stick with cookies and use the HTTPOnly and Secure flags.
2. If cookies won't work for some reason, then use session storage which will be cleared when the user closes the browser window.
3. Be cautious with storing sensitive data in local storage. Just like any other client side storage options this data can be viewed and modified by the user. 

Si realmente desea exponer el access_token al cliente, el método de compromiso es:

// GET /seesion
    access_token := ctx.Session().GetString("access_token")

    if access_token != "" {
        ctx.JSON(200, {"signed": true, "access_token": access_token})
    } else {
        ctx.Redirect("//yoursite.com/login")
    }

Pero todavía recomiendo ponerlo solo en la cookie. JS usa el método GET / SEION para determinar si ha iniciado sesión. Se accede a otros recursos como de costumbre. El servidor saltará a la página de inicio de sesión directamente después de descubrir que el access_token ha expirado :

// GET /seesion
    access_token := ctx.Session().GetString("access_token")
    if signed != "" {
        ctx.JSON(200, {"signed": true})
    } else {
        ctx.Redirect("//yoursite.com/login", "you need login first.")
    }

// GET /posts/:postid
    access_token := ctx.Session().GetString("access_token")

    if access_token != "" && isValidAccessToken(access_token) {
        ctx.JSON(200, getPostWithAccessToken(access_token, postid))
    } else {
        ctx.Redirect("//yoursite.com/login", "you need login first.")
    }

Por supuesto, si cree que el sistema de su sitio web no tiene valor de ataque, no he dicho nada.

Este tipo de pensamiento "aparentemente inadecuado, pero de hecho no habrá problemas de seguridad". No sé cuántas pérdidas le traerá a su empleador en el futuro:
Inventario de fugas de seguridad de la información corporativa
Se vendió un millón de información de clientes en tiempo real (el problema de fuga de seguridad de la información de esta empresa no se ha resuelto por completo hasta ahora, fue prohibido por una serie de grandes empresas de comercio electrónico, como un club de productos).

La seguridad de la información tiene un largo camino por recorrer.

@ u0x01
Permítanme hablar sobre lo que respondí antes. Puede que no esté claro. En el proceso de obtener access_token, no solo se requieren client_id y client_secret (esto puede no ser necesario), sino que también se requieren un nombre de usuario y una contraseña.

Puede proteger el sitio web de ataques de XSS / CSRF

Hay CSRF que se ha desactivado. En cuanto a XSS, todo el contenido almacenado en la base de datos se transferirá automáticamente y se filtrarán los campos ilegales. Aunque puede haber omisiones, es imposible eliminarlo por completo. La seguridad de la información no es absolutamente segura. Lo mismo ocurre con Microsoft y Apple No te creo, el sistema puede lograr un 100% de seguridad.

Incluso si no usa SessionID, debe poner access_token en http solo cookie

Http only tampoco es absolutamente seguro.

Es un malentendido de la especificación OAUth2 y un uso incorrecto.

No sé si esto se considera un uso incorrecto, pero ¿es posible que mi propia aplicación solicite una página de autorización. Después de que el usuario inicia sesión, obtiene la página de autorización y luego acepta acceder a ella? ¿Es demasiado problema? Por ahora, ningún sitio web hace esto para sus propias aplicaciones, ¿verdad?

Además, mi método de autenticación ideal puede ser diferente de lo que dijo, porque mi propio servidor proporciona servicios de autenticación OAuth2. Entonces creo que para mi cliente de navegador, es así: UA solicita AS, AS encuentra que no está autenticado, salta a LOGIN y luego, después de que el usuario inicia sesión, obtiene con éxito el permiso para acceder al servidor (esto puede be access_token, o puede serlo) Puede abrir directamente los permisos de acceso al servicio de recursos), y luego los usuarios pueden solicitar recursos directa / indirectamente (access_token) en el servidor de recursos en el lado js.

En otras palabras, mi método de autenticación ideal es para nuestra propia UA. Creo que si es un tercero, puede ser necesario utilizar el authorize_code que mencionaste para obtener la página de autorización a la que puede acceder el usuario.

El anterior es mi método de autenticación ideal, pero desafortunadamente mi nivel es limitado y no puedo obtener el efecto que quiero a través de OAuth2 de Spring.

No sé cuánto daño le traerá a su empleador en el futuro

En primer lugar, me gustaría señalar que nuestro proyecto es muy urgente, y la arquitectura se ha puesto al día recientemente. Si es posible, ¿no podría luchar por la excelencia? Sin embargo, el tiempo no lo permite, ¿tu jefe te permite arrastrar el proyecto del cliente mientras juegas a la seguridad técnica? La realidad suele ser cruel. Es posible que a su jefe no le importe en absoluto la seguridad de sus clientes, sino que se preocupan más por sus intereses. Lo único que puedo hacer es garantizar la mayor seguridad posible.

@ u0x01 De hecho, para mí también quiero hacer la arquitectura que diseñé sin ningún problema de seguridad, pero la realidad es:

  1. No puedo cumplir con este requisito con mi nivel técnico personal. Yo mismo no soy un experto técnico.
  2. Falta de un verdadero técnico experto que me oriente, si alguien está dispuesto a orientarme, creo que seré feliz

Hasta ahora, todas mis tecnologías han sido exploradas por una persona sin orientación. Algunas de las soluciones que faltan son, de hecho, mis defectos.

@WhatAKitty
Dado que su proyecto tiene prisa y al jefe no le importa, hágalo ahora de acuerdo con sus ideas.

Pero, ¿es posible que su propia aplicación solicite una página de autorización. Después de que el usuario inicie sesión, obtenga la página de autorización y luego acepte acceder a ella? ¿Es demasiado problema? Por ahora, ningún sitio web hace esto para sus propias aplicaciones, ¿verdad?

Consulte las especificaciones relevantes de OAuth2, OAuth2 tiene el concepto de permiso implícito.

En otras palabras, mi método de autenticación ideal es para nuestra propia UA. Creo que si es un tercero, puede ser necesario utilizar el authorize_code que mencionaste para obtener la página de autorización a la que puede acceder el usuario.

OAuth2 no parece tener el concepto de un tercero.

Además, ¿qué estás haciendo con la protección CSRF desactivada? ¿No es eso cavar un hoyo por ti mismo?
No dije que solo http es absolutamente seguro. El principal problema de seguridad que solo resuelve http es evitar que js lea las cookies. Cooperar con SSL puede evitar que terceros monitoreen las cookies (en el caso de ataques que no sean de intermediario).

@WhatAKitty
Solía ​​estar desde la perspectiva del jefe, pero de hecho, es bueno tener algunos problemas de seguridad. Por un lado, su jefe prestará atención a los problemas de seguridad y, por otro lado, dejará una comida para el ingeniero de seguridad de la información.

Los ingenieros de seguridad de la información deben agradecer a los programadores que deliberadamente dejan errores :)

@ u0x01 ¿ Parece que conoces bien OAuth2? ¿Es posible crear un grupo? No encontré mucha información de la aplicación en esta área y no tuve demasiado tiempo para recopilarla. Puedo hacerle algunas preguntas.

@ u0x01 El backend no tiene estado y no hay ninguna sesión. Necesitas usar el token para redis para determinar si ha expirado.¿Puedo preguntar dónde está seguro el token?

@longzb stateless ≠ sesión ninguna, mencionaste

Use token para redis para determinar si ha expirado

De hecho, el access_token se utiliza como sesión. Se recomienda conocer la definición y los métodos de trabajo de la sesión.

¿Dónde está seguro el token?

Ponerlo en la cookie http_only puede evitar que JS adquiera directamente la cookie, reduciendo así el valor y la posibilidad de ataques XSS / CSRF.

@ u0x01 Hmm. Ayer fui a Baidu. Voy a poner cookies, es mejor estar más seguro.

Este artículo es bueno sobre el análisis implícito.
Hoy estoy terminando la muestra SSM + ANTD. Después de leer este artículo, siento que la forma más segura es usar el servidor implícito para solicitar el servidor de autenticación y obtener el token, y solicitar implícitamente al servidor implícito que obtenga los recursos del servidor de recursos.

Debido a que, como se dice en este artículo, la autorización implícita es riesgosa, como el phishing, es fácil para el hacker pretender ser un cliente seguro para solicitar recursos.

Pero para hacer esto, dva necesita ser compatible con la renderización del lado del servidor. Ahora que antd lo admite, ¿dva ya lo admite? @ lo siento

No te preocupas por las cosas correctas.

¿Protegiendo la información ubicada en el cliente?

No necesita hacer nada una vez que la información ha llegado a su cliente (por ejemplo, su navegador) para protegerla. Puede almacenar el token de acceso en una cookie, en un campo oculto en su página web, en la caché local html5. o claramente visible directamente en el medio de la página y no cambia nada (excepto la navegación lateral ...).

Preocuparse por el token de acceso una vez que está en el cliente es como abrir el bloc de notas para escribir la contraseña de su correo electrónico y luego preocuparse de que un atacante pueda robar esa información desde una ubicación remota. No sucede. A menos que su computadora ya esté comprometida, pero en este punto ya has perdido.

¿Dónde tiene sentido preocuparse?

Por lo general, su información es vulnerable cuando está en tránsito. En el caso de OAuth2 (flujo implícito), el token de acceso estará en tránsito en dos lugares:

desde el servidor de autorización a su navegador
desde su navegador al servidor de recursos
Proteger la información mientras está en tránsito es tan fácil como usar TLS en todas partes, lo cual ya debería estar haciendo ya que está usando OAuth2 y es requerido por el protocolo.

Ahora el verdadero problema

Lo más probable es que la forma en que pretende utilizar OAuth2 no sea la forma en que debería utilizarlo.

Para comprender por qué probablemente hará un mal uso de OAuth2, debe conocer los flujos. OAuth2 define 4 flujo de autorización

Código de autorización (solo bueno, pero ... sigue leyendo)
Implícito (falsa sensación de seguridad)
Credenciales de contraseña del propietario del recurso (idea horrible)
Credenciales del cliente (no se aplica a su caso)
Dado que está utilizando un cliente de JavaScript, el único flujo que funciona para usted es el flujo implícito y ahora inicia los problemas.

Problemas de flujo implícitos

Hay muchos, pero hablemos del más crítico. ¡Los tokens de acceso no están vinculados a un cliente específico! De la sección de especificación 10.16:

Para los clientes públicos que utilizan flujos implícitos, esta especificación no proporciona ningún método para que el cliente determine a qué cliente se emitió un token de acceso.
Esto abre las puertas para que el atacante se haga pasar por usted, el propietario del recurso, y luego obtenga acceso al servidor de recursos. Sigamos leyendo la sección 10.16:

El propietario de un recurso puede delegar voluntariamente el acceso a un recurso otorgando un token de acceso al cliente malintencionado del atacante. Esto puede deberse a la suplantación de identidad (phishing) u otro pretexto. Un atacante también puede robar un token a través de algún otro mecanismo. Luego, un atacante puede intentar hacerse pasar por el propietario del recurso proporcionando el token de acceso a un cliente público legítimo.

En el flujo implícito (response_type = token), el atacante puede cambiar fácilmente el token en la respuesta del servidor de autorización, reemplazando el token de acceso real con el que se emitió previamente al atacante.

Los servidores que se comunican con aplicaciones nativas que dependen de que se les pase un token de acceso en el canal trasero para identificar al usuario del cliente pueden verse comprometidos de manera similar por un atacante que crea una aplicación comprometida que puede inyectar tokens de acceso robados arbitrarios.

Cualquier cliente público que asuma que solo el propietario del recurso puede presentarle un token de acceso válido para el recurso es vulnerable a este tipo de ataque.
Ese primer ataque en realidad ni siquiera es un ataque, sino más bien un "defecto" en el flujo implícito ...

El próximo ataque

Ahora comienzan los grandes problemas. Parece que está intentando utilizar el flujo implícito de OAuth2 como una forma de autenticación delegada del usuario final que no debe proporcionar. Volver a la sección de especificación 10.16

La autenticación de los propietarios de recursos ante los clientes está fuera del alcance de esta especificación. Cualquier especificación que utilice el proceso de autorización como una forma de autenticación delegada del usuario final al cliente (p. Ej., Servicio de inicio de sesión de terceros) NO DEBE usar el flujo implícito sin mecanismos de seguridad adicionales que permitirían al cliente determinar si el token de acceso se emitió para su uso (por ejemplo, restringir la audiencia del token de acceso).
En este punto, la mayoría de las veces se acabó el juego.

¿Cómo montar ese ataque?

Es bastante simple. Digamos que su servicio REST requiere un token de acceso de Facebook. Todo lo que un atacante debe hacer es alojar un servicio, por ejemplo stackoverflow, y requerir un token de acceso de Facebook. Cuando le da el token de acceso de Facebook a stackoverflow, stackoverflow (nuestro atacante) ahora puede hacerse pasar por usted con su servicio REST.

Todo eso porque los tokens de acceso no están vinculados a un cliente específico.

Una solución

No use el flujo implícito y, en su lugar, use el flujo de código de autorización. Lo que significa que su aplicación del lado del cliente 100% ya no tendrá que ser una aplicación del lado del cliente 100%.

¿Por qué no está utilizando el servidor que está sirviendo el cliente angularjs a su usuario para manejar el flujo de OAuth2?

Referencia: http://tools.ietf.org/html/rfc6749

@WhatAKitty Si un determinado identificador del navegador de cada usuario es único, el usuario traerá automáticamente este identificador al enviar la solicitud y no se puede cambiar. El backend puede vincular el token a este identificador cuando solicite el token por primera vez. Una vez que la siguiente solicitud no se corresponda con el ID del navegador almacenado en el token, se considerará una solicitud ilegal. .
Entonces, quiero preguntar, ¿existe un logotipo de este tipo cuando el navegador lo solicita? ?

@longzb generalmente usa JSESSIONID, o se puede personalizar. Por ejemplo, oschina usa su propia identificación

@WhatAKitty @soulmachine @longzb

Cuando los modos Contraseña y Cliente de OAuth2.0 se usan al mismo tiempo, se puede agregar un proxy de entrada al servidor back-end para almacenar el access_token, y este proxy también se puede usar como el CORS front-end (Spring Boot Oauth2 parece interceptar la verificación previa de CORS)

El modo de contraseña de front-end solo necesita enviar el nombre de usuario y la contraseña al agente. El agente obtiene la autorización y almacena el access_token. Luego, el SESSION_ID generado por el agente se devuelve al front-end y el agente debe administrar el expiración y actualización del access_token. Lo único expuesto al front-end es Remember- Me, etc. son diferentes en el encabezado de Set-Cookie: Expires=

El modo Cliente del cliente solo no necesita acceder al proxy, simplemente vaya directamente a la interfaz OAuth para obtener la autorización.

En cuanto a la respuesta de @ u0x01 , dije mucha información confusa e inútil

De hecho, se puede resumir de la siguiente manera:

  1. Lanzar el access_token directamente al front-end en lugar de Session se debe a que necesita compartir la interfaz con el modo Cliente. Este tipo de interfaz a menudo no admite la verificación de la sesión, o es inconveniente administrar la sesión en un sistema distribuido.

  2. La seguridad contra ataques XSS y CSRF debe analizarse por separado

    2.1 Para evitar CSRF, el front-end coloca el access_token en el encabezado HTTP para enviar, y el back-end solo admite la verificación del encabezado, al mismo tiempo es suficiente diseñar bien la interfaz. Porque el sitio web de terceros no puede enviar encabezados HTTP adicionales solo a través del formulario, y el JS del sitio web de terceros no puede enviar datos a su propio sitio web (cuando CORS está configurado correctamente)

    2.2 Para evitar XSS, el front-end que almacena access_token es de hecho inseguro y JS puede leerlo a voluntad y enviarlo a través de dominios; y las cookies con HttpOnly establecidas son recursos de Credenciales. Los navegadores HttpOnly solo se puede decir que es un remedio

  3. La medida más segura es actuar como un proxy de entrada en el back-end y configurar el Access-Control-Allow-Origin CORS para permitir solo los nombres de dominio del front-end. Una vez que el usuario inicia sesión correctamente, se devuelve la sesión de HttpOnly y se agrega un código aleatorio como X-CSRF-TOKEN al campo del encabezado. Este código aleatorio existe con el access_token obtenido de la interfaz OAuth . El front-end usa Ajax o fetch para enviar datos con la cookie y este encabezado. Después de que el back-end verifica la validez de la cookie, necesita verificar la validez del encabezado X-CSRF .Básicamente, esto puede evitar que CSRF y XSS ordinario roben permisos

En resumen, la gestión de front-end de access_token no puede considerarse groseramente insegura

Actualización 1:

El middleware o backend usa jwt para cifrar access_token y, al mismo tiempo, forma la detección de inyección y CSP para evitar XSS

@mdluo tiene una idea clara, alabanza 👍

@mdluo Lo siento, soy un novato en el front-end. En el tercer método que mencionaste, básicamente puedo lograr la parte del back-end con Spring boot + spring security, pero ¿cómo llevo las cookies al front-end fetch? Debido a que involucra dominios cruzados, algunas soluciones en Internet usan el parámetro credentials: "include" resolverlo, pero este parámetro solo puede resolver solicitudes GET. POST y otros problemas tienen problemas. Debido a que es la primera vez que lo usa, puede ser estúpido escribirlo usted mismo. El medio ambiente es:
Interfaz: puerto DVA 8000
Backend: Spring boot + Spring Security, X-CSRF-TOKEN y Cookie

@ yoster0520 Configure CORS en el backend. Si el frontend tiene varias direcciones, el backend debe determinar dinámicamente y devolver el único Access-Control-Allow-Origin acuerdo con la lista blanca, para que pueda traer cookies

¿Fue útil esta página
0 / 5 - 0 calificaciones