21

先週、OAuth2 JWT トークン検証例外に直面しています (そのため、誰もアプリケーションにアクセスできません):

java.security.SignatureException: 署名の長さが正しくありません: 256 を取得しましたが、128 を予期していgoogle-http-client 1.20.0ましJava 1.7.0た。これまでと同じ構成が機能しました-何かアイデアはありますか?

Stacktrace

java.security.SignatureException: Signature length not correct: got 256 but was expecting 128
    at sun.security.rsa.RSASignature.engineVerify(Unknown Source) ~[na:1.7.0_45]
    at java.security.Signature$Delegate.engineVerify(Unknown Source) ~[na:1.7.0_45]
    at java.security.Signature.verify(Unknown Source) ~[na:1.7.0_45]
    at com.google.api.client.util.SecurityUtils.verify(SecurityUtils.java:164) ~[google-http-client-1.20.0.jar:1.20.0]
4

6 に答える 6

7

ここでも同じ問題が発生しました。GoogleIdTokenVerifier のソース コードをプロジェクトに追加し、メソッドを変更しました。

 public boolean verify(GoogleIdToken googleIdToken) throws GeneralSecurityException, IOException {
    // check the payload
    if (!super.verify(googleIdToken)) {
      return false;
    }
    // verify signature
    for (PublicKey publicKey : publicKeys.getPublicKeys()) {
      try {
        if (googleIdToken.verifySignature(publicKey)) {
            return true;
          }
    } catch (Exception e) {
        System.err.println("Verify Token:" + e);
    }
    }
    return false;
  }

例外を処理するだけで、2 番目の証明書は正常に機能します。

編集:よりクリーンにしたい場合は、 Erik-zが提案したようにサブクラス化できます:

編集 2: 以下のコードを使用して動作させることはできません。上記の醜いハックに固執します。

package com.my.project.package;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.PublicKey;

import com.google.api.client.auth.openidconnect.IdTokenVerifier;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;

// Remember to remove this class later by making it deprecated
@Deprecated
public class GoogleIdTokenVerifier2 extends GoogleIdTokenVerifier {

    // Add constructors as needed
    public GoogleIdTokenVerifier2(HttpTransport transport, JsonFactory jsonFactory) {
        super(transport, jsonFactory);
    }

    @Override
    public boolean verify(GoogleIdToken googleIdToken) throws GeneralSecurityException, IOException {
        // check the payload
        if (!((IdTokenVerifier)this).verify(googleIdToken)) {
            return false;
        }
        // verify signature
        for (PublicKey publicKey : getPublicKeysManager().getPublicKeys()) {
            try {
                if (googleIdToken.verifySignature(publicKey)) {
                    return true;
                }
            } catch (Exception e) {
                System.err.println("Verify Token:" + e);
            }
        }
        return false;
    }
}
于 2015-06-11T13:04:50.377 に答える
5

これが最終的な解決策だとは思わないでください。ただし、確実に機能する一時的な回避策は、ベリファイアの対象ユーザーを tokenId に変更することです。

GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory).setAudience(Arrays.asList(clientId)).build();

GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
                    .setAudience(Arrays.asList(tokenResponse.getIdToken())).build();
于 2015-06-11T13:53:17.980 に答える
2

根本的な原因は Google 側にあり、JSON の証明書の順序が正しくありません。

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

次のように、それらの順序を調整できます。

http://test.gacivs.info/frontend/certs.json

その後、GooglePublicKeysManager.setPublicCertsEncodedUrl(...) メソッドを使用して、JSON のカスタム URL (または私の :) を指定できます。

final GoogleIdToken idToken = GoogleIdToken.parse(JSON_FACTORY, token);
final GooglePublicKeysManager manager = new GooglePublicKeysManager.Builder(HTTP_TRANSPORT, JSON_FACTORY).setPublicCertsEncodedUrl(CUSTOM_CERTS_URL).build();
final GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(manager).setAudience(Arrays.asList(CLIENT_ID)).build();
verifier.verify(idToken);

...そしてそれは機能します。

Googleが問題をすぐに修正してくれることを願っています... :)

于 2015-06-11T15:03:29.767 に答える
0

これは私の回答hereからコピーされたものですが、Google Cloud Endpoint を使用していない人にはより関連があります (この質問に一致)。問題はこれによって引き起こされます:

  • RSA には、鍵のサイズに応じて可変長の署名があります。
  • Google は署名に使用するキー ペアを更新しました。現在、キー ペアの 1 つが他の長さの署名とは異なる長さの署名を生成しています。
  • java.security.Signature.verify(byte[] signature)間違った長さの署名が渡された場合に例外をスローします (署名がキーと一致しない場合に通常行われる false を返す代わりに)

最も簡単な解決策は、検証呼び出し ( try...catch) をラップし、例外が発生した場合に false を返すことです。

http://android-developers.blogspot.com/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;
       }
   }
};

残念ながら、これをテストするための正確な設定がありません。これがうまくいくかどうか教えてください。

于 2015-06-11T16:10:25.797 に答える