Que es esto?
En este artículo, me centraré en las cosas que encontré y pensé en el proceso que pasé en mi aventura con, posiblemente, la aplicación de citas más popular, Tinder.
Lo más probable es que esto no lo ayude a encontrar una cita/pareja, pero espero que despierte cierta curiosidad por comprender cómo funcionan las cosas detrás de escena en la aplicación Tinder.
Si eres alguien relacionado con Tinder,por favor lee la conclusión al final.
Publicar resaltado:
Puede ver TODAS las imágenes de las personas a las que les has gustado DE FORMA NÍTIDA mirando la respuesta de la solicitud tentadora que se dispara cuando haces clic en el botón que abre la lista de aquellas personas.Pero espera, quién eres?
Me alegra que lo preguntes, soy Elian Cordoba y, como mi amigo Sam, soy un desarrollador web de full-strack, hago principalmente Angular, Ionic y Node, pero no me asusta ningun framework/ biblioteca/ herramienta JS que está en tendencia al momento de leer esto.
Puede encontrarme en github y contactarme a través de [correo electrónico] (mailto: business.eliancordoba@gmail.com).
Cómo terminé aquí?
Siempre trato de curiosear para ver si puedo encontrar cosas interesantes, esta vez fue el turno de Tinder. Empecé a usar la versión web porque ~~ me sentía solo ~~ por alguna razón me desconecté de la versión móvil y no pude volver a iniciar sesión (en la web puedes usar Facebook para hacerlo).
Una vez dentro, me llamó la atención el botón con la cantidad de personas a las que le había gustado (aunque no todos lo tendrían😕).
Después de hacer clic en él,se abrió una página con la lista de personas, pero con una captura, sus fotos de perfil estaban borrosas.
Para verlos correctamente, debe pagar una suscripción mensual.
Entonces pensé, lo más probable es que estas fotos salieran borrosas del backend de Tinder, verdad?
Bueno...no, vienen nítidas y obtienen el efecto en el frontend con una clase CSS, ay!
Esto es bastante malo para ellos porque cualquiera puede obtener una de las principales características doradas de Tinder de forma gratuita con bastante facilidad*.
Además, esto no fue complicado de evitar**, ya podrían haber almacenado una imagen borrosa o aplicar el efecto antes de enviarla.
Algo como sharp puede hacer el trabajo correctamente, suponiendo que estén usando Node.js para el backend, si no lo hacen, pero aún así les gusta ese paquete, un microservicio funcionaría multa bien.
Casualmente, momentos después de descubrir esto, alguien me dió like y al observar la respuesta actual pude ver su foto y luego la reconocí en mi lista de deslizamiento.
Para ser honesto, terminó siendo una espada de doble filo porque también descubrí que le gusté a una chica muy linda y, por alguna razón, no devolví su like 😔
- No es tan bueno como la función real, no puedes ver la información del perfil de la persona, como el nombre o la biografía.
** Ambas soluciones que voy a mencionar, como muchas cosas en la vida, tienen compensaciones, la primera usarían más almacenamiento por usuario y también la deberán actualizar cada vez que el usuario actualice su foto principal de perfil. El segundo es la sobrecarga en la respuesta, lo que puede ser un problema teniendo en cuenta la cantidad de usuarios que tienen, aunque no todos lo provocarán.
Otra cosa interesante es que la solicitud teasers (La que obtiene la lista de personas que le gustaron) no solo tiene la URL de la imagen del retrato, sino todas las URL de sus imágenes, ay!
Esto podría haberse evitado haciendo una proyección en la consulta o eliminando las propiedades no utilizadas.
Los datos adicionales * cargan tanto la respuesta que lo hacen pesar 4 veces más.
- Para ser honesto, no estoy 100% seguro de lo que se usa en el frontend porque no trabajo en Tinder pero, sabiendo que la solicitud se dispara cuando haces clic en el botón para ver a quién le gustaste y solo muestran una imagen es segura suponer que podrían omitir todos los demás datos.
** El reclamo de peso adicional 4x proviene de tomar la respuesta original (~ 54 KB) y eliminar todas las demás propiedades excepto la imagen del retrato (Tamaño final ~ 11.5 KB).
Dame más 🔥
Con este tipo de momento eureka mi curiosidad ya alta aumentó aún más, lo siguiente que quería saber era cómo funcionaba el deslizamiento de Tinder.
Cuando carga la página, se activa la solicitud principal, lo que trae consigo un array de 16 usuarios (se activa nuevamente si los desliza a todos). Recuerda esto, volveremos en un momento.
Lo siguiente que intenté fue hacer un like y un pass fueron ... GET s ...en serio? De todos modos, las URL son:
GET - api.gotinder.com/like/ID_PERSON
GET - api.gotinder.com/pass/ID_PERSON
Y el super like es:
POST - api.gotinder.com/like/ID_PERSON/super
No encontré ninguna utilidad para el pass y superlike pero una muy buena para el like, de nuevo, sigue leyendo, todavía necesitamos una pieza extra para resolver uno de los rompecabezas!
Jugueteando con el almacenamiento persistente 💽
Otra de las características premium útiles de Tinder es que puedes rehacer un deslizamiento, también podemos hackearlo para obtenerlo gratis usando lo que acabamos de aprender.
Para hacerlo, vaya al almacenamiento IndexDB y luego**_ keyval _**:
A la izquierda en Firefox , a la derecha en Chrome
Busque la clave _ persist::recs_ que tendrá la siguiente estructura:
{
"previouslySwiped": [
{
"id": "5d61ab62a0d7e91610c0b0c6",
"rating": "like",
"timestamp": 1566769731872,
"sNumber": 793832917
},
{
"id": "5c6b475172e7651200a590b2",
"rating": "dislike",
"timestamp": 1566781244135,
"sNumber": 691913683
},
....
]
}
Tip:
Para reproducir y modificar cualquier solicitud, vaya a la pestaña de Network, haga clic derecho sobre ella y luego Copy as fetch . Luego vaya a la consola, péguelo y presione enter. Al final de la publicación hay un gif haciendo exactamente esto.Entonces, solo tenemos que tomar el ID de la persona a la que queremos mostrar nuestro interés y ponerla en la solicitud like:
fetch(
'https://api.gotinder.com/like/5a94cc13b191566e1c13a85e?locale=en&s_number=489904711',
{
credentials: 'omit',
headers: { ... }, // !important, copy the headers from a recent 'like' request, as they your session data
referrer: 'https://tinder.com/',
referrerPolicy: 'origin',
body: null,
method: 'GET',
mode: 'cors'
}
);
En una nota al margen, también descubrí que cuando tienes una coincidencia *, te permite chatear con esa persona, al hacer clic en su perfil, se activa el usual get by ID.
Esto es útil porque si desea rehacer un me gusta pero no está seguro de qué ID es el correcto, con esto puede verificarlo.
fetch('https://api.gotinder.com/user/ID?locale=en', { // The ID goes here
credentials: 'omit',
headers: {...}, // Same thing here as explained in the last last example
referrer: 'https://tinder.com/',
referrerPolicy: 'origin',
body: null,
method: 'GET',
mode: 'cors'
});
- Es ese hermoso momento cuando le gustas a alguien y también sucede que a ti también te gusta. Realmente maravilloso
Hackear la sección 'guardar perfil' 🕵️
Por supuesto, cuando puede actualizar algunos valores existentes, existe la posibilidad de que los desarrolladores no validen en el backend lo que está enviando, por lo que podría alterar la carga útil para hacer algo como:
{
"firstName": "Elian",
"lastName": "Cordoba",
"account": {
"balance": 9007199254740991 // Gotta stay safe
}
}
Lo más probable es que su home banking tenga esto cubierto, pero Tinder no es un home banking, así que intenté de todos modos.
Descubrí que en la versión web de Tinder no puedes cambiar tu ciudad (en la aplicación móvil puedes), pero puedes editar la carga útil para hacerlo:
Tip:
Puedes crear tus propias ciudades! Haga una actualización de perfil para copiar la solicitud y luego modifique la carga útil.{
"user": {
"city": {
"name": "Area 51",
"region": "20 september never forget"
}
}
}
Para ser justos, es difícil de validar, ya que depende de alguna biblioteca o servicio del frontend para obtener los valores válidos (en este caso, muy probablemente, la API de Google Map)._
Para evitar esto, también tendrían que llamar al mismo servicio en el backend para verificar si lo que el usuario está enviando es válido, pero, seamos honestos, no creo que crear sus propias ciudades sea tan importante para hacer eso._ _
Además, el número de teléfono se almacena como... phone_id ¯_(ツ)_/¯
Solo por diversión, traté de hacer algo de XSS pero resulta que tienen eso cubierto.
Random bits
-
Estaba hablando con una chica después de un partido y, por alguna razón, borró todas sus fotos ~~ No, no fue porque la asusté ~~ pero yo había copiado su perfil como JSON ~~ Ok, eso puede considerarse espeluznante ~~ y por eso intenté obtener una de sus URL de imágenes y... todavía estaban allí. Lo más probable es que Tinder tenga los derechos de retenerlos por un tiempo (tal vez para siempre, leer los términos y condiciones para niños), pero es un recordatorio de que dejamos muchos datos en Internet, incluso cuando dejamos de usar ese sitio / aplicación.
-
La solicitud superlike se valida en el backend de Tinder, intenté modificar los datos de mi perfil para agregarme algunos de estos potenciadores, pero también son validadas.
-
Cuando ingresas un código incorrecto en la entrada del código promocional, el código de estado de la respuesta será 500, soy el único que lo siente como una microagresión? Bromas aparte, esta tiene algunas implicaciones, si tienen algún monitoreo de errores, es probable que registre errores 5XX, por lo que podría activar algunas alarmas enviando esta solicitud por correo no deseado. No, no lo hagas.
-
No te puedes gustar a tí mismo 😢
-Cuando alguien le guste, más temprano que tarde, lo encontrará, si por alguna razón, no desea darle "me gusta" o "no me guste" (coward), puede volver a cargar la página, no se preocupe, volverá a aparecer más tarde. Si quiere estar seguro de eso, simplemente guarde su ID para que pueda activar la coincidencia a través de la consola (Ejemplo a continuación).
-
Lamentablemente, la respuesta de teasers no viene con el ID de la persona, de lo contrario, podríamos haber reproducido la función de pago completo no solo al obtener las fotos sino también toda su información.
-
Para mejorar tus posibilidades de conocer a alguien, puedes
socializarhacer un script!!!
async function partnerFinder() {
const carefullySelectedCandidates = await fetch(...); // The 'core' request
const ids = carefullySelectedCandidates.data.results.map(user => user._id);
await Promise.all(ids.map(id => fetch(...id))); // The 'like' request
partnerFinder(); // Oh sh*t, here we go again
}
Hay un límite de 100 me gusta que no parece activarse si usas el sitio normalmente, pero si haces cientos de solicitudes por minuto, lo más probable es que te detengan. Así que combina este 'script' con un CRON job que se ejecute cada X* tiempo y listo. Además, será mejor si los haces uno por uno y con algún retraso aleatorio en el medio, ya sabes, para tratar de distraer cualquier posible DDos simple o detector de bot.
- X es lo que sea que Tinder dice que es el tiempo de reinicio de los Me gusta.
Conclusión
Para ser claros, el objetivo de esta publicación no es hacer que Tinder pierda dinero o promover este tipo de comportamiento (Explotar funciones pagas de forma gratuita), en mi opinión, podría considerarse una versión suave de la piratería.
Mi objetivo fue y siempre será aprender, en este caso, mediante ingeniería inversa del sitio de Tinder, una habilidad que considero muy importante para el desarrollo de software.
** No divulgué estos hallazgos porque, por lo que sé, no están relacionados con la seguridad. **
Ya terminé con este proyecto de 'investigación', pensé en hacer una extensión para revelar automáticamente las imágenes o para agradar a las personas, pero contradice lo que dije en el último párrafo, eso no significa que alguien haga algo relacionado a esto no lo comprobaré, solo házmelo saber!
Finalmente, me gustaría animar a todos a que siempre intenten ver qué sucede debajo del capó, ver qué se solicita y qué se responde (a veces llevan datos adicionales que no deberían estar allí), a las fuentes (los sitios pueden actualizar su código con source maps, ouch), verifique la consola en busca de registros y variables, etc.
Me gusta pensar en eso, como una búsqueda del tesoro, nunca se sabe lo que encontrarás!