2

我已经成功实现了 Google SafetyNet API,甚至得到了成功的响应。问题是JWSResultfromAttestationResponse是一个散列字符串,而我的期望是得到一个 JSON 作为响应。

请问我需要先从哪里找问题?

attest()是调用的代码:

    fun callSafetyNetAttentationApi(context: Activity, callback: SafetyNetCallback) {

    if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS) {

        val nonce: ByteArray? = getRequestNonce("Safety Net Sample: " + System.currentTimeMillis())
        val client = SafetyNet.getClient(context)

        nonce?.let {
            val task: Task<AttestationResponse> = client.attest(it, BuildConfig.SAFETY_NET_KEY)

            task.addOnSuccessListener { response -> safetyNetSuccess(response, callback) }
                    .addOnFailureListener { callback.isDeviceTrusted(false) }

        } ?: kotlin.run {
            callback.isDeviceTrusted(false)
        }

    } else {
        MaterialDialog.Builder(context)
                .title("The app cannot be used")
                .content("Please update Google Play Services and try again.")
                .cancelable(false)
                .positiveText("Dismiss")
                .onPositive { dialog, which -> context.finish() }
                .show()
    }
}
4

2 回答 2

1

这是执行后您将收到的典型 JSON 响应safetyNetClient.attest(nonce, apiKey)

{
   "jwsResult": "foo.bar.zar",
   "uid": "11426643",
   "authCode": "H3o28i\/ViJUPRAW\/q4IUe1AMAbD-2jYp82os9v",
   "app": 1,
   "androidId": "vece15a43449afa9"
}

foo.bar.zar是一个 base64 编码的字符串,类似于aisnfaksdf.8439hundf.ghbadsjn,其中每个部分对应于:

<Base64 encoded header>.<Base64 encoded JSON data>.<Base64 encoded signature>

您需要进行barBase64 解码才能获得 SafetyNet 结果 JSON:

    private fun extractJwsData(jws: String?): ByteArray? {
        val parts = jws?.split("[.]".toRegex())?.dropLastWhile { it.isEmpty() }?.toTypedArray()
        if (parts?.size != 3) {
            System.err.println("Failure: Illegal JWS signature format. The JWS consists of "
                    + parts?.size + " parts instead of 3.")
            return null
        }
        return Base64.decode(parts[1], Base64.DEFAULT)
    }

然后使用你喜欢的 JSON 库构造 java 对象,例如 GSON:

val model = Gson().fromJson(extractJwsData(jws).toString(), SafetyNetApiModel::class.java)

在哪里SafetyNetApiModel

class SafetyNetApiModel {
    @SerializedName("nonce")
    var nonce: String? = null

    @SerializedName("timestampMs")
    var timestampMs: Long? = null

    @SerializedName("apkPackageName")
    var apkPackageName: String? = null

    @SerializedName("apkCertificateDigestSha256")
    var apkCertificateDigestSha256: List<String>? = null

    @SerializedName("apkDigestSha256")
    var apkDigestSha256: String? = null

    @SerializedName("ctsProfileMatch")
    var ctsProfileMatch: Boolean? = null

    @SerializedName("basicIntegrity")
    var basicIntegrity: Boolean? = null
}

看看这个以供参考。

于 2020-06-25T08:45:51.133 回答
0

JWS 响应始终是签名结果。获得 JWS 响应后,您必须使用 nonce 从服务器端代码验证它,然后服务器将验证请求,如果它是有效请求,则返回 JSON 响应,如下所示

查看链接将 JWS 响应发送到服务器以进行验证

对于示例应用程序:

private OnSuccessListener<SafetyNetApi.AttestationResponse> mSuccessListener =
        new OnSuccessListener<SafetyNetApi.AttestationResponse>() {
            @Override
            public void onSuccess(SafetyNetApi.AttestationResponse attestationResponse) {
                /*
                 Successfully communicated with SafetyNet API.
                 Use result.getJwsResult() to get the signed result data. See the server
                 component of this sample for details on how to verify and parse this result.
                 */
                mResult = attestationResponse.getJwsResult();
                Log.d(TAG, "Success! SafetyNet result:\n" + mResult + "\n");

                    /*
                     TODO(developer): Forward this result to your server together with
                     the nonce for verification.
                     You can also parse the JwsResult locally to confirm that the API
                     returned a response by checking for an 'error' field first and before
                     retrying the request with an exponential backoff.
                     NOTE: Do NOT rely on a local, client-side only check for security, you
                     must verify the response on a remote server!
                    */
            }
        };

阅读成功响应中的注释,此代码来自GitHub SafetyNet 示例应用程序

于 2020-06-28T17:56:45.353 回答