Google Safet yNet API JwsResult - это хешированная строка вместо JSON - PullRequest
3 голосов
/ 17 июня 2020

Я успешно внедрил Google Safet yNet API, даже есть успешный ответ. Проблема в том, что JWSResult из AttestationResponse является хешированной строкой, тогда как я ожидал получить в ответ 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()
    }
}

Ответы [ 2 ]

1 голос
/ 25 июня 2020

Это типичный ответ 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>

Вам нужно взять bar и Base64 декодировать, чтобы получить Safet yNet результат 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)
    }

Затем построить java, используя понравившуюся библиотеку JSON, например 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
}

Посмотрите на this для справки.

0 голосов
/ 28 июня 2020

Ответ 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 Safet yNet пример приложения

...