Google Cloud Endpoints:verifyToken:签名长度不正确

Posted

技术标签:

【中文标题】Google Cloud Endpoints:verifyToken:签名长度不正确【英文标题】:Google Cloud Endpoints: verifyToken: Signature length not correct 【发布时间】:2015-08-27 04:59:43 【问题描述】:

今天早上,从我的 android 应用向我的 Google Cloud Endpoint 发出的每个 API 请求都开始出现以下异常:

com.google.api.server.spi.auth.GoogleIdTokenUtils verifyToken: verifyToken:签名长度不正确:得到 256 但期待 128

在我的 javascript 网络客户端上调用仍然可以正常工作。我没有更改服务器端代码或客户端代码。

最近该服务是否发生了任何可能导致这种情况发生的变化?

更新:第一次出现这种情况似乎是在 11:17:07 UTC

更新:不起作用的事情包括为 android 生成新的客户端 ID 并更新到 App Engine SDK 1.9.22

【问题讨论】:

这只是发生在我身上...... 3 小时前工作正常。 我们联系了 Google Enterprise 支持团队。他们告诉他们已经在努力解决这个问题。 他们告诉他们将在美国/太平洋时间 10:00 提供进一步的更新。一旦我收到他们的任何回复,我就会在此处发布。 这个问题应该只影响混合键长的组合键。当前提供的密钥集仅包括 2048 长度的密钥。由于缓存的密钥集,您可能仍会遇到中断,但如果您重新启动应用程序,问题可能会得到解决。 感谢现在似乎很好!这是一个很好的 7 小时恐慌 :) 感谢大家的更新 【参考方案1】:

原因

RSA 具有可变长度的签名,具体取决于密钥大小。 Google 更新了用于签名的密钥对,现在其中一个密钥对生成的签名长度与另一个不同 java.security.Signature.verify(byte[] signature) 如果传递了错误长度的签名,则抛出异常(而不是返回 false,这通常在签名与密钥不匹配时完成)

对我来说,解决方案是包装验证调用 (try...catch),然后返回 false。 您也可以自己对公钥进行早期检查,检查签名的长度是否与公钥模数的长度匹配。

如果您使用库来检查签名,请确保使用最新版本。

查看http://android-developers.blogspot.nl/2013/01/verifying-back-end-calls-from-android.html 上的示例代码,您将不得不更改:

GoogleIdToken token = GoogleIdToken.parse(mJFactory, tokenString);

JsonWebSignature jws = JsonWebSignature.parser(mJFactory).setPayloadClass(Payload.class).parse(tokenString);
GoogleIdToken token = new GoogleIdToken(jws.getHeader(), (Payload) jws.getPayload(), jws.getSignatureBytes(), jws.getSignedContentBytes()) 
   public boolean verify(GoogleIdTokenVerifier verifier)
  throws GeneralSecurityException, IOException 
       try 
           return verifier.verify(this);
        catch (java.security.SignatureException e) 
           return false;
       
   
;

很遗憾,我没有确切的设置来测试这个。

对于那些使用 Google Cloud Endpoint 的人,就像问题所述,我认为除了等到 Google 修复它之外,您几乎无能为力。幸运的是它现在已修复。 (从技术上讲,您可能会争辩说像现在所做的那样更改密钥是一种解决方法,并且 Google 提供的库需要修复。但它有效,所以这是一个好的开始)

【讨论】:

感谢您的信息。知道从哪里开始尝试修复它吗? @SanketBerde Google 生成密钥,然后他们只是在消息上签名...如果 Google 生成新密钥,也许会有所帮助,但对我们来说这不是解决方案 这绝对不是我们的问题吧?我们的配置有问题吗? @beetstra 你是指服务器端还是安卓端?这是一个 Play 商店部署的应用程序,因此我无法在客户端快速更改任何内容,因为它需要数小时才能推送给用户。 我尝试生成新的 Android 客户端 ID 和受众。没用,同样的错误。我注意到的是,从 Google Endpoints explorer 发出的 Endpoints 调用是有效的。所以这只是客户端 ID 的问题。【参考方案2】:

同样的问题,据我所知,公共证书 URL(现在?我猜以前不是这种情况,或者顺序改变了)返回两个键:

https://www.googleapis.com/oauth2/v1/certs

检查这些,第一个具有 1024 位密钥,第二个具有 2048 位密钥。我相信我从 android 客户端传入的令牌是由第二个证书使用 2048 位密钥签名的,因此“签名长度不正确:得到 256 但期待 128”。

查看 Google 验证程序源 (GoogleTokenVerifier.java),它似乎确实迭代了多个键:

// verify signature
for (PublicKey publicKey : publicKeys.getPublicKeys()) 
  if (googleIdToken.verifySignature(publicKey)) 
    return true;
  

假设键被正确解析(该代码看起来很合理,但实际上并未检查结果)。

正如 beestra 所指出的,此代码期望在无法验证的情况下返回 false,而是抛出异常。理想情况下,它应该在失败后继续迭代并使用第二个公钥进行验证,这应该可以工作。

要解决这个问题,似乎有两种选择:

    fork google api 客户端库并修复 在(您的)调用代码中复制验证 (GoogleIdTokenVerifier.verify(GoogleIdToken))

我不知道 2. 有多现实,使用了一些超级功能并且很多内部状态是私有的,必须复制所有这些。忙着调查……

更新:好的,看起来在我使用生产数据的测试中已修复,但尚未将其部署到生产中。这是斯卡拉

  val jsonFactory = new JacksonFactory()
  val transport = new NetHttpTransport()
  val googleIdTokenVerifier = new GoogleIdTokenVerifier(transport, jsonFactory)

  class DuplicateVerifier(builder: GoogleIdTokenVerifier.Builder) extends IdTokenVerifier(builder)
  val topIdTokenVerifier = new DuplicateVerifier(new GoogleIdTokenVerifier.Builder(transport, jsonFactory))
  val publicKeysManager = new GooglePublicKeysManager(transport, jsonFactory)
  def duplicateGoogleVerify(token: GoogleIdToken): Boolean = 
    // check the payload
    if (!topIdTokenVerifier.verify(token)) 
      false
     else 
      // verify signature
      import scala.collection.JavaConverters._
      publicKeysManager.getPublicKeys.asScala.map  k =>
        Try(token.verifySignature(k))
      .foldLeft(false)((c, x) => c || x.getOrElse(false))
    
  

如果不明显,请使用此方法而不是 Google 的方法:

// if (googleIdTokenVerifier.verify(token)) 
if (duplicateGoogleVerify(token)) 

如果有人需要,我稍后会尝试编写 Java 等价物。

【讨论】:

我认为您对公共证书 URL 的看法是正确的 - 截至 2015 年 3 月 15 日,它有 2 个相同大小的证书web.archive.org/web/20150315022911/https://www.googleapis.com/… 如果成功请提供JAVA等价物..我需要!!

以上是关于Google Cloud Endpoints:verifyToken:签名长度不正确的主要内容,如果未能解决你的问题,请参考以下文章

使用 Google Cloud Endpoints 时如何重启 Flask 服务器?

Google Cloud Endpoints 相当于 API 网关,还是 Endpoints 相当于微服务?

Google Cloud Endpoints:身份验证问题(错误 403)

如何在 Google Cloud Endpoints 中允许 CORS?

GWT 和 Google Cloud Endpoints

使用 Google Endpoints 在 Google Cloud Storage 上上传图片