谷歌的OpenID标识符取决于“消费者”域名而不同。如果需要更改域名,如何避免问题?

9

我目前正在测试OpenID实现,发现Google会为不同的消费主机名/域名发送不同的标识符,即使是同一用户。例如,当请求站点是localhost时,Google发送的标识符与请求站点是127.0.0.1时发送的标识符不同,但是它们都属于同一用户。

注意:我尚未使用公共域名测试此问题,但我不认为行为会有任何不同。

我对Google的行为感到担忧,因为如果我们将来选择更改网站域名,那么用户将无法再使用Google的OpenId作为身份提供者登录到网站。这似乎是一个大问题。我是否遗漏了什么,或者所有OpenID消费站点都面临着这个潜在问题?

我还使用MyOpenId进行了测试,但MyOpenId创建的标识符是固定的,因此这对他们来说不是问题。


2
http://blog.stackoverflow.com/2009/04/googles-openids-are-unique-per-domain/ - Quintin Par
这个问题解决了吗? - Jus12
3个回答

5

3
看起来,谷歌返回的OpenID网址取决于所使用的openid.realm值。此外,我刚试过使用设置为http://MYREALMopenid.return_to设置为http://localhost/openid.php的领域进行OpenID流程,但收到了HTTP 400 Bad Request的响应消息。显然,谷歌检查领域是否与“返回”URL具有相同的域(和可能的端口)。

一个解决方法是存储与OpenID相关联的Gmail地址。每当您请求Google OpenID时,请始终通过属性交换的http://axschema.org/contact/email类型请求用户的电子邮件地址。如果您更改了域,可以根据电子邮件地址将新的OpenID URL与其帐户关联。

注意:务必验证HMAC-SHA1签名。否则,任何人都可以构造电子邮件地址“返回”到您的Web应用程序的OpenID checkauth操作,从而允许他们接管某人的帐户,如果他们知道目标的Gmail地址。

当用户在转换后首次使用其Google帐户登录时,迁移过程如下:

  1. https://www.google.com/accounts/o8/ud 发送 POST 请求,并使用以下参数:

     +---------------------+----------------------------------+
     | openid.ns           | http://specs.openid.net/auth/2.0 |
     | openid.mode         | associate                        |
     | openid.assoc_type   | HMAC-SHA1                        |
     | openid.session_type | no-encryption                    |
     +---------------------+----------------------------------+
     

    (根据需要替换 openid.realm=http://NEWREALM)

    响应将类似于:

     ns:http://specs.openid.net/auth/2.0
     session_type:no-encryption
     assoc_type:HMAC-SHA1
     assoc_handle:B5hJNa39Cl39BXSOKMqkPpk03rJmE0GI6EhHBkvfLOBFAMMQX67HjuFq
     expires_in:46800
     mac_key:F5XUXvoYutLvFv4IzJS0diytLmbe
     
  2. 在重定向到服务 URI (https://www.google.com/accounts/o8/ud),模式为 'checkid_setup' 时,确保发送之前获取的 assoc_handle,并通过属性交换要求用户的电子邮件地址。换句话说,请务必发送以下附加参数:

     +----------------------+----------------------------------------------------------+
     | openid.assoc_handle  | B5hJNa39Cl39BXSOKMqkPpk03rJmE0GI6EhHBkvfLOBFAMMQX67HjuFq |
     | openid.ns.ax         | http://openid.net/srv/ax/1.0                             |
     | openid.ax.mode       | fetch_request                                            |
     | openid.ax.type.email | http://axschema.org/contact/email                        |
     | openid.ax.required   | email                                                    |
     +----------------------+----------------------------------------------------------+
     

    "返回" 请求将包括重要参数 openid_signedopenid_sigopenid_ext1_value_email

  3. 按照 OpenID Authentication 2.0 规范的生成签名过程 进行操作。如果 HMAC-SHA1 签名的 Base64 编码与 openid_sig 值不同,则签名无效。请注意,此示例中的 MAC 密钥为 F5XUXvoYutLvFv4IzJS0diytLmbe。使用 Google 服务器在关联请求中发送的内容。

 

Google联合登录文档页面指出http://axschema.org/contact/email“请求用户的Gmail地址”。假设一旦创建了Google账户,那么“Gmail”电子邮件地址就是固定的。但是,如果这个假设不成立,那么使用此过程就不安全,因为恶意用户可以将联合登录服务返回的电子邮件地址更改为他们想要窃取的帐户的电子邮件地址。

为了保险起见,在激活新的OpenID之前,向该电子邮件地址发送电子邮件验证请求。验证链接将包含与新OpenID相关联的nonce。点击链接后,新的OpenID将完全与用户的帐户相关联,因为收到nonce将验证电子邮件地址和新的OpenID URL之间的关联。

另请参见:openid.sig--它是如何生成的?


关于存储电子邮件(我这样做),但使用HMAC-SHA1进行检查不确定,因为我正在使用DonNetOpen Auth库来进行openid验证,所以该库可能会执行此操作。 - Omu
@ChuckNorris:看起来DotNetOpenAuth.OpenId命名空间中有处理关联的类,但我不确定在OpenID认证过程的哪个阶段使用它们。OpenID 2.0“返回”请求包含一个assoc_handle,Web应用程序可以使用它来验证信息是否来自服务。Web应用程序只需使用模式“check_authentication”向服务URI发出POST请求,并引用openid.signed参数值中提到的所有参数。请参见11.4.2. 直接与OpenID提供者验证 - Daniel Trebbien
@ChuckNorris:我猜只要确保如果返回的身份标识以“https://www.google.com/accounts/o8/”开头,那么服务URI就是“https://www.google.com/accounts/o8/ud”。换句话说,不允许任何OpenID提供程序发送Google OpenID。请确保它是Google的。 - Daniel Trebbien
@ChuckNorris:为了澄清我所说的“在哪个阶段”,验证签名有两种方法(请参见11.4. 验证签名)。如果之前已经建立了关联,您的 Web 应用程序可以自行验证签名(这是我的答案使用的方法)。否则,在“返回”请求后,它将直接与 OpenID 提供者(第 11.4.2 节)验证签名。 - Daniel Trebbien

1

还有另一种可能的解决方法。在进行间接身份验证请求(重定向到服务URI)时,即使领域设置为新领域,也将 OpenID URL 作为openid.claimed_idopenid.identity参数的值发送。

在我的开发机器上,我将域“thiscomputer”别名为127.0.0.1。当我从Google的OpenID提供程序请求身份验证时,领域为“http://thiscomputer”,openid.identityopenid.claimed_id都设置为http://specs.openid.net/auth/2.0/identifier_select,我得到了如下返回:

https://www.google.com/accounts/o8/id?id=VGwSBXN7Q00X4G9CTAsLPMJ3m6JaPljpkrURAUZJ

然后我向OP请求身份验证,领域为'http://localhost',openid.identityopenid.claimed_id都设置为http://specs.openid.net/auth/2.0/identifier_select。我得到了如下返回结果:

https://www.google.com/accounts/o8/id?id=VGwSBXNwzPQk-puNdfZl4tP-s7JNHPA3WmMHozHJ

然后我向OP请求身份验证,领域为'http://localhost',openid.identityopenid.claimed_id都设置为https://www.google.com/accounts/o8/id?id=VGwSBXN7Q00X4G9CTAsLPMJ3m6JaPljpkrURAUZJ(当领域为'http://thiscomputer'时,这是我的Google帐户的OpenID身份)。 我得到了以下回复:

https://www.google.com/accounts/o8/id?id=VGwSBXN7Q00X4G9CTAsLPMJ3m6JaPljpkrURAUZJ

也就是说,当领域为'http://thiscomputer'时,我得到了与之前相同的OpenID身份URL。因此,即使我将依赖OpenID的Web应用程序从'thiscomputer'迁移到'localhost',我仍然可以使用旧的OpenID身份URL。

只要您知道用户的旧OpenID身份URL(例如存储在cookie中),此解决方案就可以正常工作。

注意:我尝试将openid.identityopenid.claimed_id设置为不同的值(例如,一个是http://specs.openid.net/auth/2.0/identifier_select,而另一个是https://www.google.com/accounts/o8/id?id=VGwSBXN7Q00X4G9CTAsLPMJ3m6JaPljpkrURAUZJ或者一个是https://www.google.com/accounts/o8/id?id=VGwSBXN7Q00X4G9CTAsLPMJ3m6JaPljpkrURAUZJ,而另一个是https://www.google.com/accounts/o8/id?id=VGwSBXNwzPQk-puNdfZl4tP-s7JNHPA3WmMHozHJ),但Google的OP服务响应“您请求的页面无效。”


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接