Sécurité OpenID :Les RP ne garantissent pas que l'authentification a été approuvée par le fournisseur réel
-
11-12-2019 - |
Question
Description générale
J'ai implémenté un OP (OpenID Provider), en utilisant DotNetOpenAuth.Je le teste avec des exemples de RP (parties de confiance), tels que la connexion OpenID de Drupal et le OpenIdRelyingPartyWebForms
projet dans le DotNetOpenAuth Samples
solution.
Le problème est que, pour autant que je sache, lorsqu'un navigateur rebondit sur mon OP et envoie une demande "d'authentification réussie" (mode: id_res
, claimed_id: smth
, etc.) au RP, le RP n'essaie pas d'effectuer une requête côté serveur à l'OP et de lui demander s'il a réellement authentifié l'utilisateur.Je peux voir qu'il y a un openid.sig
signature renvoyée par l'OP, mais encore une fois, je ne vois pas comment le RP pourrait la vérifier, car il n'a pas échangé de clés avec l'OP.
La question est donc : Existe-t-il un paramètre du côté de l'OP que je peux activer pour sécuriser le flux de travail ?
Détails techniques
J'utilise Wireshark pour détecter le trafic HTTP côté RP.Il n'y a pas de HTTPS, je peux donc voir et lire tous les messages.Ci-dessous, vous pouvez voir ce qui se passe exactement. B = Navigateur, PO = Fournisseur OpenID, PR = Partie utilisatrice.Les noms de domaine sont remplacés par *.example.com.
(B ->RP) L'utilisateur tente de visiter une ressource réservée aux membres sur la partie utilisatrice.Il saisit le point de terminaison OP que le navigateur publie sur le RP.
openid_identifier : http://OP.example.com/OpenId/Provider.aspx?xrds
(RP -> OP -> RP) RP envoie une requête côté serveur à mon OP qui renvoie un document XRDS.Je ne vois rien de similaire à l'échange de clé secrète ici.
<?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) La partie de confiance 302 redirige l'utilisateur vers les OP
/OpenId/Provider.aspx?[params]
URL, où les paramètres sont les suivants :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) Le fournisseur authentifie l'utilisateur et le redirige vers le RP avec les paramètres d'URL suivants :
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) Le RP effectue une requête HTTP côté serveur vers l'OP.Aucune donnée n'est transférée, juste une requête GET à l'URL d'identité d'utilisateur précédemment acquise.Au fait, pourquoi fait-il cette demande ?
GET /OpenId/User.aspx/2925 HTTP/1.1
(OP ->RP) L'OP répond avec un autre document 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) C'est ça.L'utilisateur est autorisé et RP lui montre la ressource réservée aux membres.
La solution
Les RP peuvent fonctionner dans avec état ou apatride modes (également appelés modes intelligents et stupides, respectivement).Vérifier organigrammes du réseau pour chaque.
Il existe un échange de clé unique entre le RP et l'OP, à condition que le RP fonctionne en mode avec état.En mode sans état, vous verrez un message du RP à l'OP après chaque authentification pour vérifier la signature de l'assertion.
Concernant votre question n°5 (la requête HTTP HEAD à l'identifiant revendiqué), il s'agit du RP DotNetOpenAuth vérifiant que l'OP fait autorité pour l'identité qu'il affirme.Puisqu'il avait précédemment extrait cette URL, le cache entre en jeu et évite le transfert de contenu.
Autres conseils
Je me sens stupide maintenant, j'ai raté quelque chose de fondamental, là est un échange de clé entre RP et OP, mais cela ne se produit qu'une seule fois, puis la clé est mise en cache des deux côtés pendant un certain temps.
Mon implémentation du fournisseur OpenID s'avère donc sécurisée :)