我正在调查谷歌在我的安卓应用程序中提供的SafetyNet。
首先,我简单地调用了Google,然后Base64按照SafetyNet提供的示例对这些部分进行了解码。
SafetyNet.getClient(this).attest(NONCE, <API KEY>)
.addOnSuccessListener(this, new OnSuccessListener<SafetyNetApi.AttestationResponse>() {
@Override
public void onSuccess(final SafetyNetApi.AttestationResponse attestationResponse) {
initialDataExtraction(attestationResponse.getJwsResult());
}
})
.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull final Exception exception) {
if (exception instanceof ApiException) {
final ApiException apiException = (ApiException) exception;
Log.e(TAG, "onFailure: " + apiException.getMessage() + " " + apiException.getStatusCode());
} else {
Log.e(TAG, "Error: ", exception);
}
}
});我提取JWS部分如下:
private byte[] initialDataExtraction(final String jwsResult) {
final String[] jwsResultParts = jwsResult.split("[.]");
if (jwsResultParts.length == 3) {
final byte[] header = Base64.decode(jwsResultParts[0], Base64.NO_WRAP);
final byte[] data = Base64.decode(jwsResultParts[1], Base64.NO_WRAP);
final byte[] signature = Base64.decode(jwsResultParts[2], Base64.NO_WRAP);
Log.d(TAG, "initialDataExtraction: header = " + new String(header, UTF_8));
Log.d(TAG, "initialDataExtraction: data = " + new String(data, UTF_8));
Log.d(TAG, "initialDataExtraction: signature = " + new String(signature, UTF_8));
return data;
} else {
Log.e(TAG, "initialDataExtraction: Failure: Illegal JWS signature format. The JWS consists of " + jwsResultParts.length + " parts instead of 3.");
return null;
}
}我使用android.util.Base64对这些部分进行解码,大多数情况下解码都可以正常完成。
偶尔我会收到这样的异常:
java.lang.IllegalArgumentException: bad base-64
at android.util.Base64.decode(Base64.java:161)
at android.util.Base64.decode(Base64.java:136)
at android.util.Base64.decode(Base64.java:118)当解码签名部分时。
在解码以查看此间歇性错误时,我做错了什么?
然后,我开始使用JWT库来解码令牌。
首先,我尝试了group: 'com.auth0.android', name: 'jwtdecode', version: '1.1.1'
我尝试的代码是
final JWT jwt = new JWT(jwsResult);它总是失败,并显示以下错误
com.auth0.android.jwt.DecodeException: The token's payload had an invalid JSON format.
at com.auth0.android.jwt.JWT.parseJson(JWT.java:235)
at com.auth0.android.jwt.JWT.decode(JWT.java:203)
at com.auth0.android.jwt.JWT.<init>(JWT.java:40)
Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY at line 1 column 23 path $.
at com.google.gson.Gson.fromJson(Gson.java:899)
at com.google.gson.Gson.fromJson(Gson.java:852)
at com.google.gson.Gson.fromJson(Gson.java:801)这个异常似乎是由于Auth0库无法解析标头4.1.6. "x5c" (X.509 Certificate Chain) Header格式引起的,这很奇怪,因为JWS Spec清楚地说明了值是由JSON aray表示的:-
The "x5c" (X.509 Certificate Chain) Header Parameter contains the
X.509 public key certificate or certificate chain [RFC5280]
corresponding to the key used to digitally sign the JWS. The
certificate or certificate chain is represented as a JSON array of
certificate value strings. 但是,如果我将相同的jws结果字符串复制并粘贴到一个纯java项目中,并使用compile 'com.auth0:java-jwt:3.3.0'并使用以下代码:
String token = "<JWS TOKEN>";
try {
final DecodedJWT jwt = JWT.decode(token);
System.out.println("Header = " + jwt.getHeader());
System.out.println("Payload = " + jwt.getPayload());
System.out.println("Signature = " + jwt.getSignature());
} catch (JWTDecodeException exception){
throw new RuntimeException(exception);
}成功解码Jws令牌。
我在我的安卓应用程序中做错了什么,导致auth0 Android jwt库无法正常工作?
然后,我在我的Android应用程序中尝试了'io.jsonwebtoken:jjwt:0.9.0'库。
当我执行这段代码时:
Jwts.parser().parse(jwsResult).getBody();它会失败,错误为:-
java.lang.IllegalArgumentException: A signing key must be specified if the specified JWT is digitally signed.
at io.jsonwebtoken.lang.Assert.notNull(Assert.java:85)
at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:331)我需要传递给Jwts的签名密钥是什么?我唯一的密钥是保存在Google API控制台中的API密钥,这是我应该使用的密钥吗?
当我按如下方式传递它时:
Jwts.parser().setSigningKey<API KEY>.parse(jwsResult).getBody();此操作失败,出现以下错误:-
java.lang.IllegalArgumentException: Key bytes can only be specified for HMAC signatures. Please specify a PublicKey or PrivateKey instance.
at io.jsonwebtoken.lang.Assert.isTrue(Assert.java:38)
at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:324)解码和使用从SafetyNet attest API调用收到的Jws结果的正确方法是什么?
我从这个问题Base64: java.lang.IllegalArgumentException: Illegal character中找到了java.lang.IllegalArgumentException: bad base-64问题的修复
在解码之前,只需替换jws token中的字符
token.replace('-', '+').replace('_', '/')发布于 2017-12-08 16:44:38
我发现这个库不仅做得很好,而且在Android上也运行得很好。
// https://mvnrepository.com/artifact/com.nimbusds/nimbus-jose-jwt
implementation group: 'com.nimbusds', name: 'nimbus-jose-jwt', version: '5.1'
try {
final JWSObject jwsObject = JWSObject.parse(jwsResult);
System.out.println("header = " + jwsObject.getHeader());
System.out.println("header = " + jwsObject.getHeader().getX509CertChain());
System.out.println("payload = " + jwsObject.getPayload().toJSONObject());
System.out.println("signature = " + jwsObject.getSignature());
System.out.println("signature = " + jwsObject.getSignature().decodeToString());
} catch (ParseException e) {
e.printStackTrace();
}这里提供了一些很好的例子:
https://stackoverflow.com/questions/47690811
复制相似问题