Guía de integración de la API de Play Integrity

Programa de acceso anticipado (EAP)

Actualmente, la API de Play Integrity está disponible a través de un programa de acceso anticipado. No tiene disponibilidad general y aún se encuentra en desarrollo activo. Si deseas informar problemas o dejar comentarios, envía un correo electrónico a integrity-api-eap@google.com.

Condiciones del Servicio de la API de Play Integrity

Cuando accedes a la API de Play Integrity o la usas, aceptas las Condiciones del Servicio del kit de desarrollo de software de Play Core. Asegúrate de leer y entender todos los términos y las políticas aplicables antes de acceder a la API.

Descripción general

La API de Play Integrity unifica las funciones antiabuso de Google Play que puedes usar para detectar tráfico fraudulento y riesgoso. Ese tráfico podría provenir de versiones no autorizadas de tu app o juego, de dispositivos no confiables, o bien de otros entornos poco fiables. Si detectas este tráfico, puedes tomar las medidas adecuadas a fin de reducir los casos de abuso, como fraudes, engaños y accesos no autorizados. La API está disponible para apps y juegos. Para comprender el uso de la API en juegos, puedes mirar este video introductorio de la Cumbre de desarrolladores de Google para juegos 2021.

En la actualidad, esta API proporciona una respuesta firmada y encriptada que incluye la siguiente información:

Imagen de Integrity que destaca el modo en que funciona con dispositivos Android y Play
  • Integridad de la aplicación: Indica si interactúas con el objeto binario sin modificar que Google Play reconoce.
  • Detalles de la cuenta: Indica si la cuenta de usuario actual tiene licencia, lo que significa que este adquirió la app o el juego cuando instaló o pagó por ellos en Google Play.
  • Integridad del dispositivo: Indica si tu app se está ejecutando en un dispositivo Android genuino con los Servicios de Google Play.

Uso de la API de alto nivel

Diagrama que ilustra las relaciones entre la app, el backend de la app y la API de Play Integrity

En general, la API funciona de la siguiente manera:

  1. El backend de la app genera y envía un nonce único a la app.
  2. La app llama a la API de Integrity con el nonce y recibe un token firmado y encriptado que contiene las indicaciones de Play Integrity.
  3. La app envía el token a su backend.
  4. El backend de la app desencripta y verifica el token, y decide el procedimiento según los indicadores contenidos en la carga útil del token.
  5. El backend de la app envía los resultados de la decisión a la app.

Consideraciones de seguridad

Si bien la API de Play Integrity ayuda a garantizar la seguridad y protege contra la manipulación, asegúrate de realizar toda la desencriptación y verificación desde un entorno de servidor seguro. Un atacante podría extraer o quitar los detalles de seguridad del APK o el repositorio que se expongan a través de una app cliente. En particular, ten en cuenta lo siguiente:

  • La API debe llamarse principalmente para proteger acciones valiosas y no recurrentes que sean una parte integral de la experiencia del usuario (como acceder a un servicio o unirse a un servidor multijugador). No deberías obtener el token de integridad con demasiada frecuencia, en especial en dispositivos más antiguos, en los que se requiere más tiempo para generarlos. En promedio, una llamada por usuario activo por día resulta razonable, aunque un usuario que realice varias acciones valiosas en un día podría requerir varias llamadas.
  • Los nonces deben ser únicos e impredecibles para un atacante.
  • Toda la desencriptación y la verificación del token deben realizarse dentro de un entorno de servidor seguro. No se deben llevar a cabo desde la app cliente.
  • Nunca expongas las claves de desencriptación a la app cliente.
  • En lugar de enviar una sola respuesta de aprobación o error desde el servidor hacia la app, es mejor enviar una serie de indicadores y resultados de decisiones que sean más difíciles de replicar. Por ejemplo, puedes usar una serie de respuestas relacionadas, como Permitir, Permitir con límites, Permitir con límites después de que se complete el reCAPTCHA y Denegar.

La API de Play Integrity es ideal cuando se usa junto con otros indicadores como parte de tu estrategia general contra el abuso y no como tu único mecanismo antiabuso. La API siempre se debe usar junto con las prácticas recomendadas de seguridad adecuadas para tu app.

Límites de uso de la API

Las solicitudes a la API están sujetas a un máximo por app y por día según lo determinado por el nivel de uso asignado de la app que realiza la llamada. Las apps en el EAP se asignan automáticamente a un nivel de uso especial.

El nivel de EAP está limitado a 5 millones de solicitudes por app por día. Si necesitas una cantidad diaria superior, comunícate con integrity-api-eap@google.com.

La misma app distribuida en Google Play y a través de otras tiendas de aplicaciones y canales de distribución cuenta como una sola app en términos del uso de la API. Si la app que distribuyes en Play tiene un nombre de paquete diferente al de aquella que distribuyes en otros canales, comunícate con integrity-api-eap@google.com y registra el nombre de este último paquete como uno vinculado al nombre del paquete de Play.

Se proporcionará más información sobre los niveles de uso cuando la API tenga disponibilidad general. A partir de ese momento, las apps en el nivel de uso de EAP se migrarán a los niveles públicos.

Requisitos previos

Requisitos para la integración

  • Obtener claves del token de integridad
  • Tener la biblioteca de Play Core para EAP (core-integrity-1.10.1.aar) (puedes descargarla desde la carpeta de Drive)
  • Para la integración de Unity, contar con Unity 2017.4.40 o Unity 2018.4 o versiones posteriores (puedes descargar paquetes de Google específicos del EAP desde la carpeta de Drive)
  • Para la integración nativa, descargar la biblioteca nativa de Play Core específica del EAP (play-core-native-sdk-integrity-eap.zip) desde la carpeta de Drive

Requisitos del dispositivo

  • Android 4.4 (KitKat, nivel de API 19) o versiones posteriores
  • App de Play Store 24.6.31 o versiones posteriores
  • Servicios de Play V19 (12800000) o versiones posteriores

Cómo obtener las claves del token de integridad

Por motivos de seguridad, las claves que recibas estarán encriptadas. A continuación, se muestran los pasos que debes seguir a fin de obtener y desencriptar las claves del token de integridad:

  1. Crea un nuevo par de claves públicas/privadas. Ten en cuenta que la clave RSA debe ser de 2048 bits.

    $ openssl genrsa -aes128 -out private.pem 2048
    $ openssl rsa -in private.pem -pubout > public.pem
    
  2. Envía un correo electrónico con la clave pública a integrity-api-eap@google.com y espera a recibir las claves del token de integridad encriptadas (integrity_token_keys.enc).

  3. Usa tu clave privada para desencriptar las claves del token de integridad.

    $ openssl rsautl -decrypt -oaep -inkey private.pem \
        -in integrity_token_keys.enc > integrity_token_keys.txt
    $ cat integrity_token_keys.txt
    DECRYPTION_KEY=XXXXXXXXXXXXX
    VERIFICATION_KEY=YYYYYYYYYYYYY
    

Cómo integrar Play Core en tu app

La biblioteca de Play Core es la interfaz de tiempo de ejecución de tu app con Google Play Store. A fin de integrar Play Core en tu app, sigue las instrucciones en la Descripción general de la biblioteca de Google Play Core.

Java o Kotlin

Ten en cuenta que, durante el EAP, en lugar de usar la versión Maven de Google de la biblioteca, debes usar la versión disponible en la sección de requisitos previos.

Si usas un repositorio Maven local, agrega la siguiente dependencia al archivo build.gradle de tu app:

implementation com.google.android.play:core-integrity

Unity

En lugar de usar la versión más reciente del complemento de Unity para Play, debes importar en tu proyecto de Unity los archivos .unitypackage o .tgz disponibles en la sección de requisitos previos. Para obtener instrucciones de instalación, consulta el artículo de instalación de paquetes de Google para Unity.

Nativo

Consulta la guía de configuración del entorno de desarrollo de la biblioteca nativa de Play Core.

Cómo generar un nonce

Un nonce es un token único de un solo uso que se genera específicamente para una solicitud. Las nonces protegen las solicitudes a la API de Play Integrity de modo que no se repitan. Por ejemplo, si un usuario obtiene un token de la API de Play Integrity para una acción protegida específica, no debería poder volver a utilizarlo para otras acciones protegidas posteriores (lo que se conoce como ataque de repetición). Por este motivo, los nonces deben ser únicos e impredecibles.

La forma recomendada de crear un nonce es hacer que tu servidor de backend confiable genere un número aleatorio criptográficamente seguro y que no incluya información específica del cliente. Una alternativa menos segura, pero aceptable, es combinar datos como una marca de tiempo o un ID del usuario, calcular un hash criptográfico con estos valores, y enviar este valor como el nonce a la app cliente para usarlo luego.

Los valores de nonce se pasan como están a los sistemas de Google, por lo que es fundamental garantizar que no se incluya PII ni otros datos sensibles en el nonce de forma directa o indirecta. En algunos casos, se pueden usar datos con codificación hash a fin de recopilar datos sensibles; por lo tanto, en el caso de apps particularmente sensibles, no debes utilizar datos sensibles.

Los nonces se pueden generar en el servidor o en el cliente. Sin embargo, no se debe asumir que el cliente es confiable, ya que puede estar bajo el control de un atacante. Por lo tanto, generar el nonce de forma aleatoria en el servidor resulta más seguro que hacerlo en el cliente.

Nonces generados por el servidor

La solución más sólida consiste en generar nonces con un generador de números aleatorios criptográficamente seguros en un entorno de servidor seguro para cada solicitud entrante de cliente. En el siguiente diagrama, se muestra un ejemplo:

Ejemplo de generación de nonce con un servidor

El nonce es único e imposible de predecir, por lo que este enfoque ofrece una garantía sólida de que no se podrá repetir la solicitud.

Nonces generados por el cliente

Es posible que algunos clientes no puedan retener todas las solicitudes entrantes del servidor o que no toleren el retraso de un recorrido de ida y vuelta adicional. Para esos casos, en el siguiente ejemplo, se muestra otra solución que cambia algunas de las garantías de reproducción por simplicidad. En el ejemplo, se genera un hash para los parámetros de la solicitud, incluida la marca de tiempo:

Ejemplo de generación de nonce en un dispositivo cliente

La marca de tiempo debe incluirse en los parámetros de la solicitud de modo que las solicitudes idénticas no den como resultado el mismo nonce, lo que garantiza que cada uno de ellos sea único. Sin embargo, como la marca de tiempo y los parámetros de la solicitud se generan en el cliente, y no se sabe si este está bajo el control de un atacante, debes suponer que es posible que se produzca un comportamiento adverso.

Debes elegir la técnica de generación de nonce en función del valor de la acción que proteges y de la amenaza aparente a la aplicación.

Cómo obtener el token de integridad

Después de generar un nonce, puedes obtener un token de integridad creando primero un IntegrityManager, como se muestra en los siguientes ejemplos. Usa el administrador a fin de llamar a requestIntegrityToken(), y proporciona el nonce a través del método setNonce() en el compilador de IntegrityTokenRequest asociado.

Ejemplo del lenguaje de programación Java

// Receive the nonce from the secure server.
String nonce = ...

// Create an instance of a manager.
IntegrityManager integrityManager =
    IntegrityManagerFactory.create(applicationContext);

// Request the integrity token by providing a nonce.
Task<IntegrityTokenResponse> integrityTokenResponse =
    integrityManager
      .requestIntegrityToken(
          IntegrityTokenRequest.builder().setNonce(nonce).build());

Ejemplo de Unity

IEnumerator RequestIntegrityTokenCoroutine()
{
    // Receive the nonce from the secure server.
    var nonce = ...

    // Create an instance of a manager.
    var integrityManager = new IntegrityManager();

    // Request the integrity token by providing a nonce.
    var tokenRequest = new IntegrityTokenRequest(nonce);
    var requestIntegrityTokenOperation =
        integrityManager.RequestIntegrityToken(tokenRequest);

    // Wait for PlayAsyncOperation to complete.
    yield return requestIntegrityTokenOperation;

    // Check the resulting error code.
    if (requestIntegrityTokenOperation.Error != IntegrityErrorCode.NoError)
    {
        AppendStatusLog("IntegrityAsyncOperation failed with error: " +
                        requestIntegrityTokenOperation.Error);
        yield break;
    }

    // Get the response.
    var tokenResponse = requestIntegrityTokenOperation.GetResult();
}

Ejemplo nativo

/// Create an IntegrityTokenRequest opaque object.
const char* nonce = RequestNonceFromServer();
IntegrityTokenRequest* request;
IntegrityTokenRequest_create(&request);
IntegrityTokenRequest_setNonce(request, nonce);

/// Prepare an IntegrityTokenResponse opaque type pointer and call
/// IntegerityManager_requestIntegrityToken().
IntegrityTokenResponse* response;
IntegrityErrorCode error_code = IntegrityManager_requestIntegrityToken(request, &response);

...

/// Proceed to polling iff error_code == INTEGRITY_NO_ERROR
if (error_code != INTEGRITY_NO_ERROR) {
    /// Remember to call the *_destroy() functions.
    return;
}

...

/// Use polling to wait for the async operation to complete.
IntegrityResponseStatus response_status;
IntegrityErrorCode error_code = IntegrityTokenResponse_getStatus(response, &response_status);
if (error_code == INTEGRITY_NO_ERROR && response_status == INTEGRITY_RESPONSE_COMPLETED) {
    const char* integrity_token = IntegrityTokenResponse_getToken(response);
    SendTokenToServer(integrity_token);
}

...

/// Remember to free up resources.
IntegrityTokenRequest_destroy(request);
IntegrityTokenResponse_destroy(response);
IntegrityManager_destroy();

Cómo desencriptar el token y verificar la integridad

El nonce proporcionado forma parte del token de respuesta firmado que se muestra. Puedes obtener ese token usando el método IntegrityTokenResponse#token(). Desencripta y verifica el token en un entorno de servidor seguro y nunca dentro de la app.

Formato del token

El token es un Token web JSON (JWT) anidado, que es la Encriptación web JSON (JWE) de la Firma web JSON (JWS). Los componentes de JWE y JWS se representan mediante la serialización compacta.

Los algoritmos de encriptación y firma son compatibles con varias implementaciones de JWT:

  • La JWE usa A256KW para alg y A256GCM para enc.
  • JWS usa ES256.

En el siguiente ejemplo, se muestra el modo en que se decodifica la clave AES y la clave EC pública con codificación DER para la verificación de firma desde Play Console o por correo electrónico a claves específicas del lenguaje (Java, en nuestro caso) en el backend de la app. Ten en cuenta que las claves están codificadas en Base64 mediante marcas predeterminadas.

// base64OfEncodedDecryptionKey is provided through Play Console / over email.
byte[] decryptionKeyBytes =
    Base64.decode(base64OfEncodedDecryptionKey, Base64.DEFAULT);
// Deserialized encryption (symmetric) key.
SecretKey decryptionKey =
    new SecretKeySpec(
        decryptionKeyBytes,
        /* offset= */ 0,
        AES_KEY_SIZE_BYTES,
        AES_KEY_TYPE);

// base64OfEncodedVerificationKey is provided through
//  Play Console / over email.
byte[] encodedVerificationKey =
    Base64.decode(base64OfEncodedVerificationKey, Base64.DEFAULT);
// Deserialized verification (public) key.
PublicKey verificationKey =
    KeyFactory.getInstance(EC_KEY_TYPE)
        .generatePublic(new X509EncodedKeySpec(encodedVerificationKey));

A continuación, usa estas claves para desencriptar el token de integridad (la parte de la JWE) y, luego, verificar y extraer la parte JWS anidada.

JsonWebEncryption jwe =
 (JsonWebEncryption)JsonWebStructure.fromCompactSerialization(integrityToken);
jwe.setKey(decryptionKey);

// This also decrypts the JWE token.
String compactJws = jwe.getPayload();

JsonWebSignature jws =
    (JsonWebSignature) JsonWebStructure.fromCompactSerialization(compactJws);
jws.setKey(verificationKey);

// This also verifies the signature.
String payload = jws.getPayload();

La carga útil resultante es un token de texto sin formato que contiene indicadores de integridad.

También debes verificar la parte de requestDetails de la carga útil de JSON; para ello, asegúrate de que el nonce y el nombre del paquete coincidan con lo que se envió en la solicitud original y que la marca de tiempo no esté inactiva.

JSONObject requestDetails =
    new JSONObject(payload).getJSONObject("requestDetails");
String requestPackageName =
    requestDetails.getString("requestPackageName");
String nonce = requestDetails.getString("nonce");
long timestampMillis = requestDetails.getLong("timestampMillis");
long currentTimestampMillis = ...;

if (!requestPackageName.equals(expectedPackageName)
    // See "Generate nonce" section of the doc on how to store/compute
    // the expected nonce.
    || !nonce.equals(expectedNonce)
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
  // The token is invalid!
  ...
}

Formato de la carga útil que se muestra

La carga útil es un archivo JSON de texto sin formato y contiene indicadores de integridad junto con información que proporciona el desarrollador.

La estructura general de la carga útil es la siguiente:

{
    requestDetails: { ... }
    appIntegrity: { ... }
    deviceIntegrity: { ... }
    accountDetails: { ... }
}

En las siguientes secciones, se describe cada campo con mayor detalle.

Campo de detalles de la solicitud

El campo requestDetails contiene información que se proporcionó en la solicitud, incluido el nonce. Estos valores deben coincidir con los de la solicitud original.

requestDetails: {
    // Application package name this attestation was requested for.
    // Note that this field might be spoofed in the middle of the
    //  request.
    requestPackageName: "com.package.name"
    // base64-encoded web-safe no-wrap nonce provided by the developer.
    nonce: "aGVsbG8gd29scmQgdGhlcmU"
    // The timestamp in milliseconds when the request was made
    //  (computed on the server).
    timestampMillis: 1617893780
}

Campo de integridad de la aplicación

El campo appIntegrity contiene información relacionada con el paquete.

appIntegrity: {
    // PLAY_RECOGNIZED, UNRECOGNIZED_VERSION, or UNEVALUATED.
    appRecognitionVerdict: "PLAY_RECOGNIZED"
    // The package name of the app.
    // This field is populated iff appRecognitionVerdict != UNEVALUATED.
    packageName: "com.package.name"
    // The sha256 digest of app certificates on device.
    // This field is populated iff appRecognitionVerdict != UNEVALUATED.
    certificateSha256Digest: ["6a6a1474b5cbbb2b1aa57e0bc3"]
    // The version of the app.
    // This field is populated iff appRecognitionVerdict != UNEVALUATED.
    versionCode: 42
}

appRecognitionVerdict puede tener los siguientes valores:

  • PLAY_RECOGNIZED: La app y el certificado coinciden con las versiones que distribuye Google Play.
  • UNRECOGNIZED_VERSION: El certificado o el nombre del paquete no coinciden con los registros de Google Play.
  • UNEVALUATED: No se evaluó la integridad de la aplicación. Se omitió un requisito necesario (p. ej., el dispositivo no es suficientemente confiable).

Campo de integridad del dispositivo

El campo deviceIntegrity contiene un solo valor, deviceRecognitionVerdict, que representa la eficacia con la que un dispositivo puede aplicar de manera forzosa la integridad de la app.

deviceIntegrity: {
    // "MEETS_DEVICE_INTEGRITY" is one of several possible values.
    deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"]
}

De forma predeterminada, deviceRecognitionVerdict puede tener una de las siguientes etiquetas:

  • MEETS_DEVICE_INTEGRITY: La app se está ejecutando en un dispositivo Android GMS con Servicios de Google Play. El dispositivo pasa las verificaciones de integridad del sistema y cumple con los requisitos de compatibilidad de Android.
  • MEETS_VIRTUAL_INTEGRITY: La app se está ejecutando en un entorno virtual de Android con los Servicios de Google Play, como Android en PC (AoPC). El entorno cumple con los requisitos principales de compatibilidad de Android y pasa las verificaciones de integridad de Google Play. Si no participas actualmente en el Programa de acceso anticipado de Android en PC, puedes ignorar esta etiqueta.
  • Sin etiquetas (por ejemplo, un valor en blanco): La app se está ejecutando en un dispositivo que tiene señales de ataque (como trampas de API) o de vulneración del sistema (como un dispositivo con permisos de administrador), o bien en un dispositivo no físico (como un emulador) que no pasa las verificaciones de integridad de Google Play.

Los socios pueden enviar un correo electrónico a integrity-api-eap@google.com a fin de habilitar la recepción de etiquetas adicionales posibles en deviceRecognitionVerdict:

  • MEETS_BASIC_INTEGRITY: La app se está ejecutando en un dispositivo que pasa las verificaciones básicas de integridad del sistema. Es posible que el dispositivo no cumpla con los requisitos de compatibilidad de Android y que no esté aprobado para ejecutar los Servicios de Google Play. Por ejemplo, puede que el dispositivo esté ejecutando una versión no reconocida de Android, que tenga un bootloader desbloqueado o que el fabricante no lo haya certificado.
  • MEETS_STRONG_INTEGRITY: La app se está ejecutando en un dispositivo Android GMS con Servicios de Google Play y tiene una garantía sólida de integridad del sistema, como un almacén de claves de la copia de seguridad en hardware. El dispositivo pasa las verificaciones de integridad del sistema y cumple con los requisitos de compatibilidad de Android.

La respuesta de integridad puede incluir varias etiquetas para el mismo dispositivo si se cumplen cada uno de los criterios de esas etiquetas. Si habilitas la recepción de varias etiquetas, podrás crear una estrategia de aplicación en función de los diferentes niveles de confiabilidad de los dispositivos.

Por ejemplo, considera un dispositivo que muestra MEETS_BASIC_INTEGRITY, MEETS_DEVICE_INTEGRITY, y MEETS_STRONG_INTEGRITY. Este dispositivo podría ser más confiable que uno que solo muestra MEETS_BASIC_INTEGRITY, y tu respuesta se puede personalizar según corresponda.

Ten en cuenta que ciertas condiciones del entorno, como una conexión a Internet inestable o un dispositivo sobrecargado, pueden hacer que fallen las verificaciones de integridad del dispositivo. Esto puede provocar que no se generen etiquetas para un dispositivo que sea de confianza. Para mitigar estas situaciones, asegúrate de incluir una opción de reintento.

Campo de detalles de la cuenta

El campo accountDetails contiene un solo valor, licensingVerdict, que representa el estado de la licencia de la app o el del derecho de acceso a esta última.

accountDetails: {
    // This field can be LICENSED, UNLICENSED, or UNEVALUATED.
    licensingVerdict: "LICENSED"
}

licensingVerdict puede tener los siguientes valores:

  • LICENSED: El usuario tiene derecho de acceso a la app (p. ej., el usuario la instaló o la compró desde Google Play o a través de Play Pass).
  • UNLICENSED: El usuario no tiene derecho de acceso a la app (p. ej., el usuario transfirió la app o nunca la adquirió desde Google Play).
  • UNEVALUATED: No se evaluó la información de las licencias porque se omitió un requisito necesario (p. ej., el dispositivo no es lo suficientemente confiable o la aplicación es desconocida para Google Play).

Códigos de error

Task<IntegrityTokenResponse> integrityTokenResponse = ...;
integrityTokenResponse.addOnFailureListener(error -> ...);

En la próxima tabla, se enumeran los errores que puede mostrar la API y los pasos siguientes sugeridos.

Código de error Descripción Acción
API_NOT_AVAILABLE La API de Integrity no está disponible. Es posible que la versión de Play Store sea antigua o que la aplicación no esté incluida en la lista de entidades permitidas para usar esta API.
  1. Asegúrate de que la app se incluya en la lista de entidades permitidas para usar la API.
  2. Pídele al usuario que actualice la app de Play Store.
PLAY_STORE_NOT_FOUND No se encontró ninguna app oficial de Google Play Store en el dispositivo. Pídele al usuario que instale una versión adecuada de Play Store.
NETWORK_ERROR No se encontró ninguna red disponible. Pídele al usuario que compruebe la conectividad de red.
PLAY_STORE_ACCOUNT_NOT_FOUND No se encontró ninguna cuenta de Play Store en el dispositivo. Pídele al usuario que se autentique en Google Play Store.
APP_NOT_INSTALLED No se instaló la app que realiza la llamada. Ocurrió un problema; es posible que sea un ataque. No se pueden realizar acciones.
PLAY_SERVICES_NOT_FOUND Los Servicios de Play no están disponibles o deben actualizarse. Pídele al usuario que instale o actualice los Servicios de Play.
APP_UID_MISMATCH El UID (ID del usuario) de la app que realiza la llamada no coincide con el del Administrador de paquetes. Ocurrió un problema; es posible que sea un ataque. No se pueden realizar acciones.
TOO_MANY_REQUESTS La app que realiza la llamada envía demasiadas solicitudes a la API y se limitaron. Vuelve a intentarlo con una retirada exponencial.
CANNOT_BIND_TO_SERVICE No se pudo realizar la vinculación al servicio de Play Store. Esto puede deberse a que el dispositivo tiene instalada una versión anterior de Play Store. Pídele al usuario que actualice la app de Play Store.
NONCE_TOO_SHORT La longitud del nonce es demasiado corta. El nonce debe tener un mínimo de 16 bytes (antes de la codificación en Base64). Vuelve a intentarlo con un nonce más largo.
NONCE_TOO_LONG La longitud del nonce es demasiado larga. El nonce debe tener un máximo de 500 bytes (antes de la codificación en Base64). Vuelve a intentarlo con un nonce más corto.
GOOGLE_SERVER_UNAVAILABLE Error interno del servidor de Google desconocido. Vuelve a intentarlo con una retirada exponencial. Considera informar un error.
NONCE_IS_NOT_BASE64 El nonce no tiene un formato compatible con el atributo no-wrap, seguro para la Web ni está codificado en Base64. Vuelve a intentarlo con el formato correcto de nonce.
INTERNAL_ERROR Error interno desconocido. Vuelve a intentarlo con una retirada exponencial. Considera informar un error.

Códigos de error específicos nativos

El prefijo INTEGRITY_ se antepone a los códigos de error nativos a fin de evitar posibles conflictos de nombre. Además de los códigos de error mencionados con anterioridad, la API nativa también incluye los siguientes:

Código de error Descripción Acción
INTEGRITY_INITIALIZATION_NEEDED No se inicializó IntegrityManager. Primero, invoca a IntegrityManager_init().
INTEGRITY_INITIALIZATION_FAILED Se produjo un error durante la inicialización de la API de Integrity. Vuelve a intentarlo con una retirada exponencial. Considera informar un error.
INTEGRITY_INVALID_ARGUMENT Se pasó un argumento no válido a la API de Integrity. Vuelve a intentarlo con el argumento correcto.

Protección de la integridad durante la instalación (EAP)

Invitamos a los desarrolladores que participan en el programa de acceso anticipado de la API de Play Integrity a que también se unan al programa de acceso anticipado de protección de la integridad durante la instalación a fin de fortalecer su estrategia antiabuso. Esta protección no requiere ningún trabajo por parte del desarrollador después de que se envíen los requisitos de instalación. Tu app está mejor protegida cuando combinas la protección durante la instalación con la verificación de la integridad de la app en el tiempo de ejecución con la API de Play Integrity.

Descripción general

Con la protección de la integridad durante la instalación, puedes reducir las instalaciones de versiones desconocidas y no autorizadas de tu app o juego. Primero, debes especificar los requisitos de instalación para el nombre del paquete de tu app. Luego, cada vez que se instale una app con el nombre de tu paquete desde cualquier fuente en un dispositivo Android con licencia GMS que ejecute Android 11 o versiones posteriores, la plataforma de Android la evaluará comparándola con una copia sin conexión de los requisitos de instalación. Si no se cumplen los requisitos, se generará un error de verificación de la instalación.

Requisitos de instalación

Para usar la protección durante la instalación, debes proporcionar una lista de certificados de firma permitidos con el nombre del paquete de tu app (incluidos los certificados de depuración a fin de garantizar que puedas continuar con la prueba). Cuando tu app se instala con uno de tus certificados de firma, la instalación procede con normalidad. Cuando la app tiene un certificado de firma desconocido, la instalación falla y genera un error de verificación de la instalación.

Existen dos requisitos de instalación opcionales adicionales que puedes solicitar:

  • Puedes pedir que el nombre de tu paquete nunca se instale mediante adb.
  • Puedes solicitar que la app esté preinstalada siempre (en otras palabras, que no sea una instalación nueva).

Otros factores que considerar

Debes tener en cuenta los siguientes factores cuando uses la protección durante la instalación:

  • La protección de integridad durante la instalación verifica cada instalación desde cualquier fuente en dispositivos Android con licencia de GMS que ejecuten los Servicios de Google Play y Android 11 (nivel de API 30) y versiones posteriores. Esta protección no puede alcanzar las instalaciones de apps en dispositivos Android modificados o con permisos de administrador.
  • Recuerda proporcionar todos los certificados de firma permitidos para tu app. Si alguna tienda de aplicaciones autorizada vuelve a firmar tu app, asegúrate de incluir esos certificados de firma en la lista de entidades permitidas. Con respecto a las pruebas, puedes enviar certificados de firma de desarrollo como certificados de firma permitidos o puedes usar el uso compartido interno de apps a fin de instalar las compilaciones de prueba (ya que se permiten las instalaciones de uso compartido interno de apps).
  • Los requisitos de instalación nuevos, actualizados o eliminados tardan en propagarse a los dispositivos. Pueden demorar hasta dos semanas en enviarse, y los dispositivos los reciben en diferentes momentos, según su configuración de actualización, y el acceso a los datos y a la conexión Wi-Fi. Los Servicios de Google Play tratarán de volver a actualizar los requisitos en caso de que no se puedan propagar inicialmente.
  • Si los usuarios intentan instalar una app que se rechazó debido a los requisitos de instalación, la plataforma de Android genera un mensaje de INSTALL_FAILED_VERIFICATION_FAILURE que se interpreta y se muestra en la IU según el instalador específico o bien como un mensaje de error durante la transferencia.

Cómo solicitar la protección durante la instalación

Para unirte al EAP de protección de la integridad durante la instalación, envía los requisitos de instalación mediante este formulario de Google. En el caso de las apps nuevas, la protección durante la instalación se aplicará a todos los números de versión. Para las apps existentes, se aplicará desde el número de versión que hayas especificado.

A fin de quitar tu app del EAP de protección de la integridad durante la instalación, comunícate con el administrador de socios de Google. Ten en cuenta que los requisitos de instalación que se quiten tardan en propagarse a los dispositivos.

Herramientas de protección de Play Integrity adicionales

Considera usar las siguientes herramientas de protección de la integridad, además de la API de Play Integrity, como parte de tu estrategia antiabuso.

Cómo excluir de la distribución los dispositivos poco confiables

Puedes evitar que tu app esté disponible para instalarse desde Google Play en dispositivos que no pasen las verificaciones de integridad. Esta opción evita que dispositivos desconocidos y poco confiables descarguen la app desde Google Play. Sin embargo, si el usuario tiene acceso a uno o más de tus archivos APK, podrá instalar tu app directamente.

Para configurar las reglas de exclusión de dispositivos, haz lo siguiente:

  1. Ve a la página Catálogo de dispositivos de Play Console.
  2. En el menú desplegable, donde dice Dispositivos compatibles, elige Dispositivos excluidos.
  3. En la esquina superior derecha, selecciona Administrar reglas de exclusión.
  4. Junto a la API de SafetyNet Attestation, selecciona una opción:
    • No excluir: Esta opción está seleccionada de forma predeterminada.
    • Excluir dispositivos que no cumplan con los requisitos básicos de integridad: Esto equivale a excluir dispositivos que no muestren el elemento MEETS_BASIC_INTEGRITY en la respuesta de la API de Play Integrity.
    • Excluir todo: Esto equivale a excluir dispositivos que no muestren MEETS_DEVICE_INTEGRITY en la respuesta de la API de Play Integrity.
  5. Haz clic en Aplicar.

Protección automática de la integridad

La protección automática de la integridad (AIP) es una alternativa de un clic a la API de Play Integrity que protege las apps y los juegos que se pueden ejecutar sin conexión por completo. Con AIP, Google Play agrega verificaciones en el tiempo de ejecución al código de tu app a fin de restringir las modificaciones y las redistribuciones, y hace que sea difícil quitar esas verificaciones mediante técnicas avanzadas de ofuscación y contra ingeniería inversa. Si falla la verificación del instalador, se podrá solicitar a los usuarios que descarguen tu app de Google Play. Si falla la verificación de modificaciones, no se ejecutará la app.

La AIP se puede combinar con la API de Play Integrity como parte de tu estrategia antiabuso a fin de dificultar que los atacantes puedan modificar, volver a empaquetar y redistribuir tu app con cambios. Obtén más información en nuestra guía sobre la protección automática de la integridad.

Si deseas solicitar acceso a la AIP, comunícate con tu administrador de socios de Google. Una vez que tu cuenta tenga acceso, podrás activar y desactivar la AIP para la app desde la página de Integridad de la app en Play Console.

Comentarios

Si deseas informar problemas o dejar comentarios, envía un correo electrónico a integrity-api-eap@google.com.

Registro de cambios de la guía de integración

Versión Descripción Fecha
2.0.0 17/08/21
1.1.0
  • Se agregó un vínculo al video de presentación en la descripción general.
  • Se agregó la API nativa a la carpeta de descargas.
  • Se agregó información acerca del uso de un nombre de paquete diferente dentro y fuera de Play en los límites de uso de la API.
  • Se agregó Android en PC (AoPC) como ejemplo de la etiqueta virtual en el campo de integridad del dispositivo.
14/07/21
1.0.1
  • Se agregaron códigos de error y detalles de la API nativa.
06/07/21
1.0.0
  • Versión inicial.
02/07/21