Dva: amostra de autenticação oauth2

Criado em 5 set. 2016  ·  26Comentários  ·  Fonte: dvajs/dva

Há algum exemplo de OAuth2 do dva, como organizar modais e como verificar as permissões?

Comentários muito úteis

Quanto à resposta de @ u0x01 , eu disse muitas informações confusas e inúteis

Na verdade, pode ser resumido da seguinte forma:

  1. Lançar o access_token diretamente para o front end em vez de Session é porque ele precisa compartilhar a interface com o modo Client.Este tipo de interface geralmente não suporta a verificação de Session, ou é inconveniente para gerenciar Session em um sistema distribuído.

  2. A segurança contra ataques XSS e CSRF deve ser analisada separadamente

    2.1 Para evitar CSRF, o front-end coloca o access_token no cabeçalho HTTP para enviar, e o back-end suporta apenas a verificação do cabeçalho.Ao mesmo tempo, é suficiente projetar bem a interface. Porque o site de terceiros não pode enviar cabeçalhos HTTP adicionais apenas por meio do formulário, e o JS do site de terceiros não pode enviar dados para seu próprio site (quando o CORS está configurado corretamente)

    2.2 Para prevenir XSS, o front-end que armazena access_token é realmente inseguro e pode ser lido por JS à vontade e enviado entre domínios; e cookies com HttpOnly definidos são recursos de credenciais. Navegadores modernos têm restrições entre domínios muito limitadas nas credenciais. Estritamente, quase não há como obtê-lo. Mas, em última análise, prevenir XSS não deveria significar prevenir injeção de script + evitar citar scripts externos não confiáveis?Este HttpOnly só pode ser considerado um remédio

  3. A medida mais segura é atuar como um proxy de ingresso no back-end e definir Access-Control-Allow-Origin do CORS para permitir apenas nomes de domínio de front-end. Depois que o usuário faz login com sucesso, a sessão de HttpOnly é retornada e um código aleatório como X-CSRF-TOKEN é adicionado ao campo de cabeçalho. Este código aleatório existe com o access_token obtido da interface OAuth . O front-end usa Ajax ou fetch para enviar dados com o Cookie e este cabeçalho. Depois que o back-end verifica a validade do Cookie, ele precisa verificar a validade do cabeçalho X-CSRF .Isso pode basicamente impedir que o CSRF e o XSS comum roubem as permissões

Em suma, o gerenciamento de front-end do access_token não pode ser considerado rudemente inseguro

Atualização 1:

O middleware ou back-end usa jwt para criptografar access_token e, ao mesmo tempo, detecção de injeção de formulário e CSP para prevenir XSS

Todos 26 comentários

A verificação do oauth2 não é feita por redirecionamento de url? Tudo bem se você fizer login avaliando o cookie.

Parte do OAuht2 é feita por meio de access_token, não url, formato RESTFul puro

Seria melhor se houvesse um exemplo de integração dva e Spring Boot Oauth2: D

@soulmachine Eu uso isso e vou resolver isso

@WhatAKitty passa o access_token, onde o access_token está armazenado? Armazenado em local / seeionStorage terá riscos de segurança XSS.

@ u0x01 é armazenado no localstorage. Na verdade, não há muito risco. Access_token tem um limite de tempo. Você não pode fazer login novamente após o tempo limite e não há permissão de refresh_token. Além disso, não há outra maneira, outras informações relacionadas são consultadas e todas são armazenadas no armazenamento local.

@WhatAKitty Agora os hackers usam ou escrevem ferramentas automatizadas para atacar. O período de validade de duas horas do access_token é suficiente para fazer muitas coisas. Como você chegou à conclusão de que "não há muito risco"?
Em segundo lugar, o refresh_token não é colocado no localstorage, onde você o coloca?
O access_token é mais adequado para APP. O lado JS puro não deve usar o esquema access_token. Ainda há o risco de ataques entre sites.
A solução mais segura agora é adicionar apenas http ao set-cookie.
Ao verificar o login, traga o cookie para o servidor para obter o status de visualização. Se ele falhar, ele irá diretamente para a página de login.
Segurança também é produtividade, que é mais importante do que Taishan, então você não pode ser preguiçoso aqui.

@ u0x01 refresh_token , não vou dar para o cliente js. Portanto, ele deve ser recertificado assim que expirar. Posso não ter deixado isso claro antes, porque nosso aplicativo é assim: access_token é apenas uma chave que permite o acesso. Se você deseja acessar recursos específicos, deve passar pela autenticação do usuário. Este processo é protegido por SSL, então você não vai aparecer. Disse vários riscos.
Quanto à solução mais segura que você disse, também considerei o uso de cookies, mas uma: não tornei o servidor compatível com OAUTH2 e LOGIN PASSWORD ao mesmo tempo, porque não consigo retornar um access_token depois de fazer login com LOGIN PASSWORD., Pode haver outras maneiras, mas eu não encontrei. Segundo: devido ao requisito de tempo do projeto, esta opção só pode ser selecionada como um meio-termo. Portanto, este plano parece um pouco impróprio, mas na verdade não haverá problemas de segurança.

@WhatAKitty nunca ouviu falar de SSL "pode ​​proteger sites contra ataques de XSS / CSRF", não existe uma relação direta entre os dois.
Se você pode garantir que o sistema do seu site está 100% livre de vulnerabilidades XSS / CSRF, você pode armazená-lo em localStorage e permitir que JS acesse as credenciais diretamente. (Mas nunca vi nenhuma empresa que se atrevesse a votar que seu sistema não tinha brechas de segurança)

E não entendo o que significa acessar recursos específicos, que devem ser autenticados pelo usuário. Na especificação OAuth2, obter access_token significa que o usuário (ou Provedor) aprovou esta autorização.

Além disso, você mencionou:
因为没法在使用 LOGIN PASSWORD 登录后给我返回一个access_token
É um mal-entendido da especificação OAUth2 e um uso incorreto.

O método LOGIN PASSWORD é essencialmente um processo no qual o UA solicita autenticação diretamente do provedor OAUth2, consulte RFC6749 . Neste momento, o código_de_ autorização deve ser obtido. Depois que o UA obtiver o código_de_ autorização, ele será enviado ao cliente para verificar a validade do provedor OAUth2. Se a verificação for aprovada, o cliente obterá o access_token do provedor OAUth2. Neste momento, o Cliente pode usar access_token para acessar recursos. O cliente então emite um SessionID para o UA.
(Cliente aqui se refere ao servidor ou APP da parte comercial, não ao usuário final, o usuário final é o Proprietário do Recurso e o UA é o navegador)

Em suma, SessionID deve ser usado para autenticar usuários, mesmo se SessionID não for usado, access_token deve ser colocado no cookie http apenas:

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. 

Se você realmente deseja expor o access_token ao cliente, o método de compromisso é:

// 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")
    }

Mas eu ainda recomendo colocá-lo apenas no cookie. JS usa o método GET / seeion para determinar se você fez o login. Outros recursos são acessados ​​normalmente. O servidor irá pular para a página de login diretamente após descobrir que o access_token expirou :

// 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.")
    }

Claro, se você acha que o sistema do seu site não tem valor de ataque, eu não disse nada.

Este tipo de pensamento "aparentemente impróprio, mas na verdade não haverá problemas de segurança". Não sei quanta perda isso trará para o seu empregador no futuro:
Inventário de vazamentos de segurança da informação corporativa
Um milhão de informações de clientes foram vendidas em tempo real (o problema de vazamento de segurança da informação desta empresa não foi completamente resolvido até agora, foi banido por uma série de grandes empresas de comércio eletrônico, como um clube de produto)

A segurança da informação ainda tem um longo caminho a percorrer.

@ u0x01
Deixe-me falar sobre o que respondi antes. Pode não estar claro. No processo de obtenção de access_token, não apenas client_id e client_secret (pode não ser necessário), mas também um nome de usuário e senha.

Pode proteger o site de ataques de XSS / CSRF

Há CSRF foi desativado. Quanto ao XSS, todo o conteúdo armazenado no banco de dados será transferido automaticamente e os campos ilegais serão filtrados. Embora possa haver omissões, é impossível eliminá-lo completamente. A segurança da informação não é absolutamente segura. O mesmo é válido para Microsoft e Apple Não acredito em você. O sistema pode atingir 100% de segurança.

Mesmo se você não usar SessionID, você deve colocar access_token apenas no cookie http

Http apenas não é absolutamente seguro.

É um mal-entendido da especificação OAUth2 e um uso incorreto.

Não sei se isso é considerado um uso incorreto, mas é possível que meu próprio aplicativo solicite uma página de autorização. Depois que o usuário faz login, ele obtém a página de autorização e concorda em acessá-la? É muito problema? Por enquanto, nenhum site faz isso para seus próprios aplicativos, certo?

Além disso, meu método de autenticação ideal pode ser diferente do que você disse, porque meu próprio servidor fornece serviços de autenticação OAuth2. Então eu acho que para o meu cliente de navegador, é assim: UA solicita AS, AS descobre que não está autenticado, pula para LOGIN, e depois que o usuário faz login, ele obtém com sucesso a permissão para acessar o servidor (isso pode ser access_token, ou pode ser) Você pode abrir diretamente as permissões de acesso do serviço de recursos) e, em seguida, os usuários podem direta / indiretamente (access_token) solicitar recursos no servidor de recursos no lado js.

Em outras palavras, meu método de autenticação ideal é para o nosso próprio UA. Acho que se for um terceiro, pode ser necessário usar o authorize_code que você mencionou para obter a página de autorização que o usuário pode acessar.

O acima é meu método de autenticação ideal, mas infelizmente meu nível é limitado e não consigo obter o efeito que desejo por meio do OAuth2 do Spring.

Não sei quanto dano isso trará para o seu empregador no futuro

Em primeiro lugar, gostaria de salientar que o nosso projecto é muito urgente e a arquitectura só recentemente recuperou, se fosse possível, não seria eu capaz de lutar pela excelência? Porém, o tempo não permite, seu chefe permite que você arraste o projeto do cliente enquanto joga segurança técnica? A realidade costuma ser cruel. Seu chefe pode não se importar com a segurança de seus clientes. Eles estão mais preocupados com os interesses. A única coisa que posso fazer é garantir o máximo de segurança possível.

@ u0x01 Na verdade, para mim, também quero fazer a arquitetura que projetei sem quaisquer problemas de segurança, mas a realidade é:

  1. Não posso atender a esse requisito com meu nível técnico pessoal. Não sou um especialista técnico.
  2. Falta de um verdadeiro especialista técnico para me orientar, se alguém estiver disposto a me orientar, acho que ficarei feliz

Até agora, todas as minhas tecnologias foram exploradas por uma pessoa sem orientação.Algumas soluções que faltam são de fato minhas deficiências.

@WhatAKitty
Já que seu projeto está com pressa e o chefe não liga, apenas faça de acordo com suas idéias agora.

Mas é possível que seu próprio aplicativo solicite uma página de autorização. Depois que o usuário fizer login, obtenha a página de autorização e concorde em acessá-la? É muito problema? Por enquanto, nenhum site faz isso para seus próprios aplicativos, certo?

Consulte as especificações relevantes do OAuth2, OAuth2 tem o conceito de permissão implícita.

Em outras palavras, meu método de autenticação ideal é para o nosso próprio UA. Acho que se for um terceiro, pode ser necessário usar o authorize_code que você mencionou para obter a página de autorização que o usuário pode acessar.

OAuth2 não parece ter o conceito de um terceiro.

Além disso, o que você está fazendo com a proteção CSRF desativada ... Isso não é cavar um buraco para você mesmo?
Eu não disse que apenas http é absolutamente seguro. O principal problema de segurança que apenas http resolve é impedir que js leia cookies. A cooperação com SSL pode impedir que terceiros monitorem cookies (no caso de ataques não man-in-the-middle).

@WhatAKitty
Eu costumava ser do ponto de vista do chefe, mas na verdade, é bom ter alguns problemas de segurança. Por um lado, seu chefe prestará atenção nas questões de segurança e, por outro lado, você deixará uma refeição para o engenheiro de segurança da informação.

Os engenheiros de segurança da informação devem agradecer aos programadores que deliberadamente deixam bugs :)

@ u0x01 Parece que você conhece bem o OAuth2? É possível criar um grupo? Não encontrei muitas informações de aplicativos nesta área e não tive muito tempo para coletá-las. Posso fazer algumas perguntas.

@ u0x01 O back-end não tem estado e não há nenhuma sessão. Você precisa usar o token para redis para determinar se ele expirou.Posso perguntar onde o token está seguro?

@longzb stateless ≠ sessão nenhuma, você mencionou

Use o token para redis para determinar se ele expirou

Na verdade, o access_token é usado como uma sessão. Recomenda-se aprender sobre a definição e métodos de trabalho da sessão.

Onde está o token seguro?

Colocá-lo no cookie http_only pode impedir que JS adquira diretamente o cookie, reduzindo assim o valor e a possibilidade de ataques XSS / CSRF.

@ u0x01 Hmm. Eu fui para o Baidu ontem. Vou colocar cookies, é melhor ficar mais seguro.

Este artigo é bom sobre análise implícita.
Hoje estou terminando a amostra SSM + ANTD. Depois de ler este artigo, sinto que a maneira mais segura é usar o servidor implícito para solicitar o servidor de autenticação e obter o token, e solicitar implicitamente ao servidor implícito para obter os recursos do servidor de recursos.

Como este artigo disse, a autorização implícita é arriscada, como o phishing, é fácil para o hacker fingir ser um cliente seguro para solicitar recursos.

Mas, para fazer isso, o dva precisa oferecer suporte à renderização do lado do servidor. Agora que o antd oferece suporte, o dva já oferece suporte? @sorrycc

Você não está se preocupando com as coisas certas

Protegendo informações localizadas no cliente?

Você não precisa fazer nada depois que a informação chega ao seu cliente (ex .: seu navegador) para protegê-la. Você pode armazenar o token de acesso em um cookie, em um campo oculto em sua página da web, no cache local html5 ou claramente visível no meio da página e não muda nada (exceto navegação de ombro ...).

Se preocupar com o token de acesso quando estiver no cliente é como abrir o bloco de notas para escrever sua senha de e-mail e depois se preocupar que um invasor possa roubar essas informações de um local remoto. Isso não acontece. A menos que seu computador já esteja comprometido, mas neste ponto você já perdeu.

Onde faz sentido se preocupar?

Normalmente, suas informações são vulneráveis ​​quando estão em trânsito. No caso do OAuth2 (fluxo implícito), o token de acesso estará em trânsito em dois locais:

do servidor de autorização para o seu navegador
do seu navegador para o servidor de recursos
Proteger as informações enquanto elas estão em trânsito é tão fácil quanto usar TLS em qualquer lugar. O que você já deveria estar fazendo, pois está usando OAuth2 e é exigido pelo protocolo.

Agora o verdadeiro problema

A maneira como você pretende usar o OAuth2 provavelmente não é a maneira que você deveria usá-lo.

Para entender por que provavelmente você usará indevidamente OAuth2, você precisa saber sobre os fluxos. OAuth2 define 4 fluxos de autorização

Código de autorização (apenas um bom, mas ... continue lendo)
Implícito (falso senso de segurança)
Credenciais de senha do proprietário do recurso (ideia horrível)
Credenciais do cliente (não aplicável ao seu caso)
Como você está usando um cliente javascript, o único fluxo que funciona para você é o fluxo implícito e agora inicia os problemas.

Problemas de fluxo implícito

Existem muitos, mas vamos apenas falar sobre o mais crítico. O token de acesso não está vinculado a um cliente específico! Da seção de especificações 10.16:

Para clientes públicos que usam fluxos implícitos, esta especificação não fornece nenhum método para o cliente determinar para qual cliente um token de acesso foi emitido.
Isso abre as portas para que o invasor se faça passar por você, o proprietário do recurso, e obtenha acesso ao servidor do recurso. Vamos continuar lendo a seção 10.16:

O proprietário de um recurso pode delegar voluntariamente o acesso a um recurso, concedendo um token de acesso ao cliente mal-intencionado de um invasor. Isso pode ser devido a phishing ou algum outro pretexto. Um invasor também pode roubar um token por meio de algum outro mecanismo. Um invasor pode então tentar personificar o proprietário do recurso, fornecendo o token de acesso a um cliente público legítimo.

No fluxo implícito (response_type = token), o invasor pode facilmente trocar o token na resposta do servidor de autorização, substituindo o token de acesso real por aquele previamente emitido para o invasor.

Os servidores que se comunicam com aplicativos nativos que dependem de receber um token de acesso no canal de apoio para identificar o usuário do cliente podem ser comprometidos de forma semelhante por um invasor criando um aplicativo comprometido que pode injetar tokens de acesso roubados arbitrários.

Qualquer cliente público que presume que apenas o proprietário do recurso pode apresentá-lo com um token de acesso válido para o recurso está vulnerável a esse tipo de ataque.
Na verdade, esse primeiro ataque não é nem mesmo um ataque, mas apenas uma "falha" no fluxo implícito ...

O próximo ataque

Agora começam os grandes problemas. Você parece estar tentando usar o fluxo implícito do OAuth2 como uma forma de autenticação de usuário final delegada que não se destina a fornecer. Voltar para a seção de especificações 10.16

Autenticar proprietários de recursos para clientes está fora do escopo desta especificação. Qualquer especificação que use o processo de autorização como uma forma de autenticação de usuário final delegada para o cliente (por exemplo, serviço de login de terceiros) NÃO DEVE usar o fluxo implícito sem mecanismos de segurança adicionais que permitiriam ao cliente determinar se o token de acesso foi emitido para seu uso (por exemplo, restringindo a audiência do token de acesso).
Neste ponto, o jogo acabou para você.

Como montar esse ataque?

É muito simples. Digamos que seu serviço REST requer um token de acesso do Facebook. Tudo o que um invasor precisa fazer é hospedar um serviço, por exemplo stackoverflow, e exigir um token de acesso do Facebook. Quando você dá ao token de acesso do Facebook para stackoverflow, stackoverflow (nosso invasor) agora pode se passar por você com seu serviço REST.

Tudo isso porque os tokens de acesso não estão vinculados a um cliente específico.

Uma solução

Não use o fluxo implícito e, em vez disso, use o fluxo do código de autorização. O que significa que seu aplicativo 100% do lado do cliente não precisará mais ser um aplicativo 100% do lado do cliente.

Por que você não está usando o servidor que está servindo o cliente angularjs ao seu usuário para lidar com o fluxo OAuth2?

Referência: http://tools.ietf.org/html/rfc6749

@WhatAKitty Se um determinado identificador do navegador de cada usuário for único, o usuário trará automaticamente esse identificador ao enviar a solicitação e não pode ser alterado. O back-end pode vincular o token a esse identificador ao solicitar o token pela primeira vez. Uma vez que a próxima solicitação não corresponda ao ID do navegador armazenado no token, ela será considerada uma solicitação ilegal. .
Portanto, gostaria de perguntar: existe esse logotipo quando o navegador o solicitar? ?

@longzb geralmente usa JSESSIONID ou pode ser personalizado. Por exemplo, oschina usa seu próprio id

@WhatAKitty @soulmachine @longzb

Quando os modos Senha e Cliente do OAuth2.0 são usados ​​ao mesmo tempo, um proxy de entrada pode ser adicionado ao servidor back-end para armazenar o access_token, e esse proxy também pode ser usado como o CORS front-end (Spring Boot Oauth2 parece interceptar o preflight do CORS)

O modo de senha de front-end precisa apenas enviar o nome de usuário e a senha ao agente. O agente obtém autorização e armazena o access_token. Em seguida, o SESSION_ID gerado pelo agente é retornado ao front-end e o agente precisa gerenciar o expiração e atualização do access_token. A única coisa exposta ao front-end é Lembrar-me etc. são apenas diferentes na cabeça de Set-Cookie: Expires=

O modo Cliente do cliente apenas não precisa acessar o proxy, basta ir diretamente para a interface OAuth para obter autorização

Quanto à resposta de @ u0x01 , eu disse muitas informações confusas e inúteis

Na verdade, pode ser resumido da seguinte forma:

  1. Lançar o access_token diretamente para o front end em vez de Session é porque ele precisa compartilhar a interface com o modo Client.Este tipo de interface geralmente não suporta a verificação de Session, ou é inconveniente para gerenciar Session em um sistema distribuído.

  2. A segurança contra ataques XSS e CSRF deve ser analisada separadamente

    2.1 Para evitar CSRF, o front-end coloca o access_token no cabeçalho HTTP para enviar, e o back-end suporta apenas a verificação do cabeçalho.Ao mesmo tempo, é suficiente projetar bem a interface. Porque o site de terceiros não pode enviar cabeçalhos HTTP adicionais apenas por meio do formulário, e o JS do site de terceiros não pode enviar dados para seu próprio site (quando o CORS está configurado corretamente)

    2.2 Para prevenir XSS, o front-end que armazena access_token é realmente inseguro e pode ser lido por JS à vontade e enviado entre domínios; e cookies com HttpOnly definidos são recursos de credenciais. Navegadores modernos têm restrições entre domínios muito limitadas nas credenciais. Estritamente, quase não há como obtê-lo. Mas, em última análise, prevenir XSS não deveria significar prevenir injeção de script + evitar citar scripts externos não confiáveis?Este HttpOnly só pode ser considerado um remédio

  3. A medida mais segura é atuar como um proxy de ingresso no back-end e definir Access-Control-Allow-Origin do CORS para permitir apenas nomes de domínio de front-end. Depois que o usuário faz login com sucesso, a sessão de HttpOnly é retornada e um código aleatório como X-CSRF-TOKEN é adicionado ao campo de cabeçalho. Este código aleatório existe com o access_token obtido da interface OAuth . O front-end usa Ajax ou fetch para enviar dados com o Cookie e este cabeçalho. Depois que o back-end verifica a validade do Cookie, ele precisa verificar a validade do cabeçalho X-CSRF .Isso pode basicamente impedir que o CSRF e o XSS comum roubem as permissões

Em suma, o gerenciamento de front-end do access_token não pode ser considerado rudemente inseguro

Atualização 1:

O middleware ou back-end usa jwt para criptografar access_token e, ao mesmo tempo, detecção de injeção de formulário e CSP para prevenir XSS

@mdluo tem uma ideia clara, elogio 👍

@mdluo Desculpe, sou um novato no front end. No terceiro método que você mencionou, posso basicamente obter a parte de back-end com Spring boot + spring security, mas como faço para trazer cookies para a busca de front-end? Por envolver domínio cruzado, algumas soluções na Internet usam o parâmetro credentials: "include" resolvê-lo, mas este parâmetro só pode resolver solicitações GET. POST e outros problemas têm problemas. Como é a primeira vez de usá-lo, pode ser estúpido escrevê-lo você mesmo. O ambiente é:
Front end: porta DVA 8000
Back-end: Spring boot + Spring security, X-CSRF-TOKEN e Cookie

@ yoster0520 Configure CORS no back-end. Se o front-end tiver vários endereços, o back-end deve determinar dinamicamente e retornar apenas Access-Control-Allow-Origin acordo com a lista de permissões, para que possa trazer cookies

Esta página foi útil?
0 / 5 - 0 avaliações