¿Por qué es importante configurar la carga útil del desarrollador con la facturación en la aplicación?

78

Estoy usando la versión 3 de la API de facturación integrada en la aplicación. Tengo un solo artículo administrado, no consumible. Todavía no he lanzado esta función en mi aplicación, por lo que quiero decidir sobre el contenido de la carga útil de compra antes de que haya compras.

De "Prácticas recomendadas de seguridad" :

Establecer la cadena de carga útil del desarrollador al realizar solicitudes de compra

Con la API de facturación integrada en la aplicación versión 3, puede incluir un token de cadena de 'carga útil del desarrollador' al enviar su solicitud de compra a Google Play. Por lo general, esto se usa para pasar un token de cadena que identifica de manera única esta solicitud de compra. Si especifica un valor de cadena, Google Play devuelve esta cadena junto con la respuesta de compra. Posteriormente, cuando realiza consultas sobre esta compra, Google Play devuelve esta cadena junto con los detalles de la compra.

Debes pasar un token de cadena que ayude a tu aplicación a identificar al usuario que realizó la compra, para que luego puedas verificar que se trata de una compra legítima de ese usuario. Para los artículos consumibles, puede usar una cadena generada aleatoriamente, pero para los artículos no consumibles debe usar una cadena que identifique de forma única al usuario.

Cuando reciba la respuesta de Google Play, asegúrese de verificar que la cadena de carga útil del desarrollador coincida con el token que envió anteriormente con la solicitud de compra. Como medida de seguridad adicional, debe realizar la verificación en su propio servidor seguro.

Con razón o sin ella, he decidido no tomar la "precaución de seguridad adicional" de configurar un servidor para realizar la verificación de compra. Y no guardo mi propio registro de la compra, siempre llamo a la API de facturación. Entonces, ¿realmente hay alguna razón para que yo haga esta verificación de carga útil? La API de verificación en sí misma ciertamente verifica la identidad de un usuario antes de informar sobre un artículo como comprado, y si un atacante ha comprometido un dispositivo (ya sea la aplicación o la API de Google Play), no veo ningún beneficio de hacer una verificación adicional en la identificación del usuario en el dispositivo donde se puede eludir fácilmente. ¿O hay alguna razón para hacer esto en la que no estoy pensando?

Travis
fuente

Respuestas:

70

Si no mantiene un registro, no hay forma de verificar que lo que obtiene es lo que envió. Entonces, si agrega algo a la carga útil del desarrollador, puede confiar en que es legítimo (lo cual es una suposición razonable si la firma verifica), o no confiar en él por completo y solo usarlo como referencia, pero no para validar el estado de la licencia, etc. Si almacena el correo electrónico del usuario, por ejemplo, puede usar el valor en lugar de pedirle que lo ingrese nuevamente, lo cual es un poco más fácil de usar, pero su aplicación no se romperá si no está allí.

Personalmente, creo que toda esta parte de las 'mejores prácticas' es confusa y está tratando de hacer que usted haga el trabajo que la API realmente debería estar haciendo. Dado que la compra está vinculada a una cuenta de Google, y Play Store obviamente guarda esta información, solo deberían proporcionarle esto en los detalles de la compra. Obtener una identificación de usuario adecuada requiere permisos adicionales que no debería necesitar agregar solo para cubrir las deficiencias de la API de IAB.

Entonces, en resumen, a menos que tenga su propio servidor y una lógica adicional especial, simplemente no use la carga útil del desarrollador. Debería estar bien, siempre que la API de IAB v3 funcione (que, desafortunadamente, es un gran 'si' en este momento).

Nikolay Elenkov
fuente
4
Un año y medio después de su respuesta inicial, ¿sigue sintiendo lo mismo? No estoy seguro de si se han realizado cambios detrás de escena en la API desde ... y no puedo decir que confíe en la documentación de Google en este momento.
Alex Lockwood
6
Sigo pensando que IAP debería proporcionar seguridad de forma transparente y no debería ser necesario utilizar la carga útil del desarrollador. Tal vez lo haga ahora, pero no lo he mirado (ni siquiera lo he usado) durante bastante tiempo. Mis aplicaciones todavía usan IAP original principalmente porque proporciona notificaciones de compra que puedo rastrear en mi propio servidor, lo que el "nuevo" IAP no hace.
Nikolay Elenkov
2
Creo que es necesario validar en el servidor, por supuesto, lo que V3 hace bastante difícil si no tiene un usuario "conectado" con algún tipo de identificador de cuenta (el suyo o el de 3-d) .Iba a intentar tal vez API V2 PERO ... Tenemos la intención de desactivar el servicio de facturación integrada en la aplicación versión 2 el 27 de enero de 2015, después de lo cual los usuarios ya no podrán comprar suscripciones ni elementos integrados en la aplicación a través de la API de la versión 2. Le recomendamos encarecidamente que migre sus aplicaciones para que utilicen la API de la versión 3 antes de noviembre de 2014, para que los usuarios tengan tiempo suficiente para actualizar sus aplicaciones a la nueva versión.
inteist
@Nikolay Elenkov, ¿cuál es tu sugerencia por ahora? Estoy de acuerdo con usted en que toda esta práctica recomendada debería estar del lado de Google.
stuckedoverflow
30

Debe pasar un token de cadena que ayude a su aplicación a identificar al usuario que realizó la compra ...

Si su aplicación proporciona su propio inicio de sesión e identidad de usuario, que es diferente de las cuentas de Google a las que está conectado el teléfono, entonces necesitará usar la carga útil del desarrollador para adjuntar la compra a una de sus cuentas que realizó la compra. De lo contrario, alguien podría cambiar de cuenta en su aplicación y beneficiarse de las cosas compradas.

p.ej

Supongamos que nuestra aplicación tiene inicio de sesión para usuarioA y usuarioB. Y la cuenta de Google de Android del teléfono es X.

  1. userA, inicia sesión en nuestra aplicación y compra una membresía vitalicia. Los detalles de la compra se almacenan en la cuenta de Google X.
  2. userA cierra sesión y userB inicia sesión en nuestra aplicación. Ahora, userB también se beneficia de la membresía vitalicia, ya que la cuenta de Google de Android sigue siendo X.

Para evitar dicho uso indebido, vincularemos una compra a una cuenta. En el ejemplo anterior, estableceremos la carga útil del desarrollador como "usuarioA" cuando el usuarioA esté realizando la compra. Entonces, cuando el usuario B inicia sesión, la carga útil no coincidirá con el usuario que inició sesión (usuario B), e ignoraremos la compra. Por lo tanto, el usuario B no puede obtener beneficios de una compra realizada por el usuario A.

therealsachin
fuente
Buena respuesta. Pero, ¿y si no tenemos ningún mecanismo de inicio de sesión de uso? ¿Entonces simplemente no usamos la carga útil?
tasomaniac
7
Después de rascarme la cabeza por un tiempo sobre este problema de ID de usuario, creo que lo que señala podría ser la intención real de la cadena de carga útil. Simplemente está muy mal explicado en la documentación de Google.
Pooks
Entonces, el usuario gmail hará el truco y se puede usar comodeveloperPaylod
Sami Eltamawy
3
@keybee Ese es exactamente el punto. En el caso que mencionaste, si no usamos la carga útil de desarrollo, tendremos que otorgar funciones premium a userB cuando la facturación en la aplicación devuelva "Ya tienes este artículo" (ya que no tenemos forma de saber si fue el usuario B quien hizo la compra en primer lugar). Si el usuario B tiene que comprar en el mismo dispositivo donde el usuario A compró, el usuario B tiene que cambiar a su propia cuenta de Google y realizar la compra.
therealsachin
3
@therealsachin Entiendo esto, pero si verifico mi servidor y bloqueo al usuario B, no tendrá la oportunidad de comprar una membresía con otra cuenta, porque Google Play está verificando primero con la cuenta principal, por lo que 2 usuarios en el mismo dispositivo no lo harán. trabajo. Sin embargo, esto solo puede ser un problema cuando el usuario A necesita una cuenta más por alguna razón. Nunca podrá realizar otra compra con la misma cuenta de Google, ni siquiera con una carga útil diferente. - El caso ideal sería para mí que, en caso de una nueva carga útil, pudiera comprar la suscripción nuevamente.
keybee
21

También hay otro enfoque para el manejo de la carga útil del desarrollador. Como dijo Nikolay Elenkov, es demasiada sobrecarga requerir una identificación de usuario y establecer permisos adicionales para el perfil de usuario en su aplicación, por lo que este no es un buen enfoque. Entonces, veamos lo que dice Google en la última versión de la aplicación de muestra TrivialDrive en las muestras de facturación en la aplicación v3:

  • ADVERTENCIA: Generar localmente una cadena aleatoria al iniciar una compra y verificarla aquí puede parecer un buen enfoque, pero esto fallará en el caso de que el usuario compre un artículo en un dispositivo y luego use su aplicación en un dispositivo diferente, porque en el otro dispositivo no tendrá acceso a la cadena aleatoria que generó originalmente.

Por lo tanto, la cadena aleatoria no es una buena idea si va a verificar el artículo comprado en otro dispositivo, pero aún así no dicen que no sea una buena idea para verificar la respuesta de compra. Yo diría: use la carga útil del desarrollador solo para verificar la compra enviando una cadena única aleatoria, guárdela en preferencias / base de datos y en la respuesta de compra verifique esta carga útil del desarrollador. En cuanto a consultar el inventario (compras en la aplicación) al inicio de la actividad, no se moleste en verificar la carga útil del desarrollador, ya que eso podría suceder en otro dispositivo donde no tiene almacenada esa cadena única aleatoria. Así lo veo yo.

Dokker
fuente
4
Gracias, estoy implementando este enfoque (y he votado a favor :) porque parece un buen compromiso, pero creo que hay un problema con la lógica como se describe. Si la verificación de la carga útil falla en la compra, entonces Google Play todavía cree que eres el propietario del artículo, por lo que solo tienes que reiniciar la aplicación, leerá el inventario y, sin la verificación de la carga útil, te entregará el artículo. Una solución es consumir el artículo si la verificación de la carga útil falla en la compra, pero luego ha tomado el dinero del usuario, lo que puede generar correos electrónicos desagradables si esto sucede inocentemente ...
Georgie
Si proporciona la identificación del dispositivo como carga útil, puede implementar ventas "por licencia de dispositivo". Así, si el usuario ha realizado la compra en un dispositivo no podrá utilizarlo en otro. Esto podría ser útil para vender la versión completa de una aplicación, p. Ej. antivirus.
bancer
Leer el comentario de @Georgie. De lo contrario, pasará mucho tiempo pensando que es una mala idea.
Halvor Holsten Strand
16

Depende de cómo verifique el developerPayload. Hay dos escenarios: verificación remota (usando el servidor) y local (en el dispositivo).

Servidor

Si está utilizando un servidor para la developerPayloadverificación, puede ser una cadena arbitraria que se puede calcular fácilmente tanto en el dispositivo como en el servidor. Debería poder identificar al usuario que ha realizado la solicitud. Suponiendo que cada usuario tiene el correspondiente accountId, developerPayloadse puede calcular como combinación con purchaseId(nombre de SKU) de esta manera:

MD5(purchaseId + accountId)


Dispositivo

developerPayload no debería ser el correo electrónico del usuario . Un buen ejemplo de por qué no debería utilizar el correo electrónico como carga útil es el servicio Google for Work. Los usuarios pueden cambiar su correo electrónico asociado con la cuenta. Lo único constante es accountId. En la mayoría de los casos, el correo electrónico estará bien (por ejemplo, las direcciones de Gmail son inmutables en este momento), pero recuerde diseñar para el futuro.

Varios usuarios pueden usar el mismo dispositivo, por lo que debe poder distinguir quién es el propietario del artículo. Para la verificación del dispositivo developerPayloades una cadena que identifica de forma única al usuario, por ejemplo:

MD5(purchaseId + accountId)


Conclusión

Generalmente, developerPayloaden ambos casos puede ser solo el accountId. Para mí, parece seguridad a través de la oscuridad . El MD5 (u otro algoritmo de hash) purchaseIdes solo una forma de hacer que la carga útil sea más aleatoria sin mostrar explícitamente que estamos usando la identificación de la cuenta. El atacante tendría que descompilar la aplicación para comprobar cómo se calcula. Si la aplicación está ofuscada, aún mejor para ti.

La carga útil no proporciona ninguna seguridad . Se puede falsificar fácilmente con el enfoque de "dispositivo" y sin ningún esfuerzo en la verificación del "servidor". Recuerde implementar la verificación de firmas con su clave pública disponible en la consola de la cuenta de editor de Google.

* Una publicación de blog de lectura obligatoria sobre el uso de la identificación de la cuenta en lugar del correo electrónico.

tomrozb
fuente
1
¿Qué es accountId? & ¿Cómo obtener el ID de cuenta? ¿Es posible mantener el mismo ID de cuenta para la cuenta de Google Play múltiple (al cambiar de cuenta) para obtener más detalles? github.com/googlesamples/android-play-billing/issues/2
Sarath Kumar
5

En el video de Google IO sobre IAB v3 dado por el autor de la muestra trivial de manejo, esto se abordó brevemente hacia el final del video. Es para evitar ataques de reproducción, por ejemplo, el atacante olfatea el tráfico, roba el paquete que contiene una compra exitosa y luego intenta reproducir el paquete en su propio dispositivo. Si su aplicación no verifica la identidad del comprador a través de la carga útil de desarrollo (idealmente en su servidor) antes de lanzar el contenido premium (también idealmente desde su servidor), el atacante tendrá éxito. La verificación de la firma no puede detectar esto porque el paquete está intacto.

En mi opinión, esta protección parece ideal para aplicaciones con conectividad de cuenta en línea como Choque de clanes (la carga útil viene naturalmente ya que tienes que identificar a los usuarios de todos modos), especialmente cuando la piratería compromete el juego multijugador con efectos de gran alcance que no sean un simple caso localizado de piratería. . Por el contrario, si los hacks del lado del cliente en la apk ya pueden desbloquear el contenido premium, esta protección no es muy útil.

(Si el atacante intenta falsificar la carga útil, la verificación de la firma debería fallar).

Kevin Lee
fuente
¿Puedo usar firebase con el inicio de sesión de Google y la base de datos en tiempo real con campos de account_id, almacenamiento de developer_payload en db en tiempo real verificándolos mientras el usuario abre la aplicación (con preferencia compartida adicional para la instalación fuera de línea)?
Dhaval Jotaniya
5

Actualización de finales de 2018: la biblioteca oficial de facturación de Google Play no expone intencionalmente el developerPayload. Desde aqui :

El campo developerPayload es un campo heredado, mantenido para mantener la compatibilidad con implementaciones antiguas, pero como se menciona en la página de Compra de productos de facturación en la aplicación ( https://developer.android.com/training/in-app-billing/purchase-iab -products.html ), este campo no siempre está disponible cuando se realizan tareas relacionadas con la facturación integrada en la aplicación. Y como la biblioteca fue diseñada para representar el modelo de desarrollo más actualizado, decidimos no admitir developerPayload en nuestra implementación y no tenemos planes de incluir este campo en la biblioteca.

Si confía en alguna implementación importante de su lógica de facturación en la aplicación en developerPayload, le recomendamos que cambie este enfoque, ya que este campo dejará de estar disponible en algún momento (o pronto). Los enfoques recomendados son usar su propio backend para validar y rastrear detalles importantes sobre sus pedidos. Para obtener más detalles, consulte la página de seguridad y diseño ( https://developer.android.com/google/play/billing/billing_best_practices.html ).

Chris Lacy
fuente
Esto me resuelve la pregunta ... Está en desuso, por lo que no debería usarse
smitty1
3

Luché con este. Dado que una cuenta de Google Play solo puede poseer uno de los elementos "administrados", pero podría tener varios dispositivos (tengo tres), el comentario anterior de alguien de que vendes un "por dispositivo" no funcionará ... poder ponerlo en su primer dispositivo, y nunca en otros ... Si compra una actualización premium, debería funcionar en todos sus teléfonos / tabletas.

Detesto la idea de obtener la dirección de correo electrónico del usuario, pero realmente no encontré ningún otro método confiable. Así que agarro la primera cuenta que coincide con "google.com" en la lista de cuentas (sí, un permiso para agregar a su manifiesto), y luego inmediatamente la hash para que ya no se pueda usar como una dirección de correo electrónico, pero proporciona un "lo suficientemente único "token. Eso es lo que envío como Carga útil del desarrollador. Dado que la mayoría de las personas activan su dispositivo con su ID de Google Play, es muy probable que los tres dispositivos obtengan el mismo token (utilizando el mismo algoritmo hash en cada dispositivo).

Incluso funciona en KitKat con múltiples "usuarios". (Mi identificación de desarrollador está en un usuario, mi identificación de prueba en otro y cada usuario en su propia caja de arena).

Lo he probado en seis dispositivos con un total de 3 usuarios y cada uno de los dispositivos de los usuarios ha devuelto el mismo hash, y los diferentes usuarios tienen distintos hashes, cumpliendo las pautas.

En ningún momento estoy almacenando la dirección de correo electrónico del usuario, se pasa directamente desde el código para obtener los nombres de las cuentas a la función hash y solo el hash se guarda en el montón.

Probablemente todavía exista una solución mejor que respete aún más la privacidad de los usuarios, pero hasta ahora no la he encontrado. Voy a poner una descripción muy clara de cómo uso la dirección de correo electrónico de los usuarios en mi política de privacidad una vez que se publique la aplicación.

Tkraindesigns
fuente
6
Todo eso es genial, pero requiere permisos de CUENTAS, lo cual es una exageración innecesaria aquí. Por qué demonios Google no podía hacer accesible un hash de la cuenta utilizada para hacer una compra ... Esa sería la solución más limpia para eso. Ahora está simplemente "roto".
inteist
Hice algo similar a esto, pero ahora, con Android 6, la aplicación tiene que pedirle al usuario que otorgue el permiso de Contactos, lo cual es una experiencia terrible para el usuario cuando inicia la aplicación por primera vez. Tal vez implemente una opción Restaurar compras en su lugar. Además, si obtiene la primera cuenta de google.com, puede tener problemas si el usuario tiene más de una cuenta en su teléfono y las reorganiza (por ejemplo, elimine la cuenta A y luego agréguela más tarde, pero ahora no es la primera cuenta) . Sucede, aunque es cierto que rara vez. Entonces, ¡también debes usar el Selector de cuentas! ¡Yuch!
snark
1

Esto a menudo responde a una definición de producto (su aplicación). Por ejemplo para el caso de las suscripciones. ¿Podrá el mismo usuario utilizar la suscripción en todos los dispositivos que tenga? Si la respuesta es sí. No comprobamos la carga útil.

Para consumibles. Suponga que una compra en su aplicación le da 10 monedas virtuales. ¿El usuario podrá usar estas monedas en diferentes dispositivos? ¿4 en un dispositivo y 6 en otro? Si queremos trabajar solo en el dispositivo que realizó la compra tenemos que verificar la carga útil, por ejemplo, con una cadena autogenerada y almacenada localmente.

Basándonos en estas preguntas, tenemos que decidir cómo implementar la verificación de carga útil.

Saludos

Santiago

Santiago SR
fuente