Segurança OpenID:Os RPs não garantem que a autenticação foi aprovada pelo provedor real
-
11-12-2019 - |
Pergunta
Descrição geral
Implementei um OP (OpenID Provider), usando DotNetOpenAuth.Estou testando-o em exemplos de RPs (partes confiáveis), como o login OpenID do Drupal e o OpenIdRelyingPartyWebForms
projeto no DotNetOpenAuth's Samples
solução.
O problema é que, pelo que sei, quando um navegador salta contra meu OP e envia uma solicitação de "autenticação bem-sucedida" (mode: id_res
, claimed_id: smth
, etc.) de volta ao RP, o RP não tenta realizar uma solicitação do lado do servidor ao OP e pergunta se realmente autenticou o usuário.Posso ver que há um openid.sig
assinatura retornada do OP, mas, novamente, não vejo como o RP poderia verificá-la, já que não trocou chaves com o OP.
Então a questão é: Existe alguma configuração do lado do OP que eu possa ativar para tornar o fluxo de trabalho seguro?
Detalhes técnicos
Estou usando o Wireshark para detectar o tráfego HTTP no lado RP.Não há HTTPS, então posso ver e ler todas as mensagens.Abaixo você pode ver o que acontece exatamente. B = Navegador, OP = Provedor OpenID, PR = Parte Confiante.Os nomes de domínio são substituídos por *.example.com.
(B -> PR) O usuário tenta visitar um recurso exclusivo para membros na terceira parte confiável.Ele insere o endpoint OP que o navegador publica no RP.
identificador_aberto: http://OP.example.com/OpenId/Provider.aspx?xrds
(RP –> OP –> RP) RP emite uma solicitação do lado do servidor para meu OP que retorna um documento XRDS.Não consigo ver nada semelhante à troca de chaves secretas aqui.
<?xml version="1.0" encoding="UTF-8"?> <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns:openid="http://openid.net/xmlns/1.0" xmlns="xri://$xrd*($v*2.0)"> <XRD> <Service priority="10"> <Type>http://specs.openid.net/auth/2.0/server</Type> <Type>http://openid.net/extensions/sreg/1.1</Type> <URI>http://OP.example.com/OpenId/Provider.aspx</URI> </Service> </XRD> </xrds:XRDS>
(RP -> B -> OP) Parte confiável 302-redireciona o usuário para OP's
/OpenId/Provider.aspx?[params]
URL, onde os parâmetros são os seguintes:openid.claimed_id: http://specs.openid.net/auth/2.0/identifier_select openid.identity: http://specs.openid.net/auth/2.0/identifier_select openid.assoc_handle: {634730422000625000}{jkQC1Q==}{32} openid.return_to: http://RP.example.com/login.aspx?ReturnUrl=%2FMembersOnly%2FDefault.aspx&dnoa.receiver=ctl00_Main_OpenIdLogin1&dnoa.UsePersistentCookie=Session&dnoa.userSuppliedIdentifier=http%3A%2F%2FOP.example.com%2FOpenId%2FProvider.aspx%3Fxrds openid.realm: http://RP.example.com/ openid.mode: checkid_setup openid.ns: http://specs.openid.net/auth/2.0 openid.ns.sreg: http://openid.net/extensions/sreg/1.1 openid.sreg.policy_url: http://RP.example.com/PrivacyPolicy.aspx openid.sreg.required: email,gender,postcode,timezone
(OP –> B –> RP) O provedor autentica o usuário e o redireciona 302 de volta ao RP com os seguintes parâmetros de URL:
ReturnUrl: /MembersOnly/Default.aspx dnoa.receiver: ctl00_Main_OpenIdLogin1 dnoa.UsePersistentCookie: Session dnoa.userSuppliedIdentifier: http://OP.example.com/OpenId/Provider.aspx?xrds openid.claimed_id: http://OP.example.com/OpenId/User.aspx/2925 openid.identity: http://OP.example.com/OpenId/User.aspx/2925 openid.sig: pWJ0ugjQATKGgRSW740bml9LDsSxFiJ+a9OLO6NlsvY= openid.signed: claimed_id,identity,assoc_handle,op_endpoint,return_to,response_nonce,ns.sreg,sreg.nickname,sreg.email openid.assoc_handle: {634730422000625000}{jkQC1Q==}{32} openid.op_endpoint: http://OP.example.com/OpenId/Provider.aspx openid.return_to: http://RP.example.com/login.aspx?ReturnUrl=%2FMembersOnly%2FDefault.aspx&dnoa.receiver=ctl00_Main_OpenIdLogin1&dnoa.UsePersistentCookie=Session&dnoa.userSuppliedIdentifier=http%3A%2F%2FOP.example.com%2FOpenId%2FProvider.aspx%3Fxrds openid.response_nonce: 2012-05-19T16:40:11ZSfsL4BK1 openid.mode: id_res openid.ns: http://specs.openid.net/auth/2.0 openid.ns.sreg: http://openid.net/extensions/sreg/1.1 openid.sreg.nickname: user@OP.example.com openid.sreg.email: user@OP.example.com
(RP -> OP) O RP executa uma solicitação HTTP do lado do servidor para o OP.Não há transferência de dados, apenas uma solicitação GET para o URL de identidade do usuário adquirido anteriormente.A propósito, por que faz esse pedido?
GET /OpenId/User.aspx/2925 HTTP/1.1
(OP -> PR) O OP responde com outro documento XRDS:
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns:openid="http://openid.net/xmlns/1.0" xmlns="xri://$xrd*($v*2.0)"> <XRD> <Service priority="10"> <Type>http://specs.openid.net/auth/2.0/signon</Type> <Type>http://openid.net/extensions/sreg/1.1</Type> <URI>http://OP.example.com/OpenId/Provider.aspx</URI> </Service> <Service priority="20"> <Type>http://openid.net/signon/1.0</Type> <Type>http://openid.net/extensions/sreg/1.1</Type> <URI>http://OP.example.com/OpenId/Provider.aspx</URI> </Service> </XRD> </xrds:XRDS>
(RP -> B) É isso.O usuário está autorizado e o RP mostra a ele o recurso exclusivo para membros.
Solução
Os PRs podem operar em com estado ou apátrida modos (também conhecidos como modos inteligente e burro, respectivamente).Confira fluxogramas de rede para cada.
Há uma troca única de chaves entre RP e OP, desde que o RP esteja operando em modo stateful.Se estiver no modo sem estado, você verá uma mensagem do RP para o OP após cada autenticação para verificar a assinatura da asserção.
Em relação à sua pergunta nº 5 (a solicitação HTTP HEAD para o identificador reivindicado), este é o RP DotNetOpenAuth verificando se o OP é autoritativo para a identidade que está afirmando.Como já havia extraído esse URL, o cache entra em ação e evita a transferência de conteúdo.
Outras dicas
Estou me sentindo estúpido agora, perdi algo básico - lá é uma troca de chaves entre RP e OP, mas acontece apenas uma vez, e então a chave é armazenada em cache em ambos os lados por algum tempo.
Portanto, minha implementação do provedor OpenID é segura :)