Разработка
Как сломанные OTP и открытые конечные точки могут превратить приложение для знакомств в кошмар
Люди должны научиться создавать безопасные приложения, а не утверждать, что их приложения безопасны, когда это не так.
Стартапы должны серьезно относиться к безопасности.
Слишком мало людей знают, как создавать безопасные приложения, и спешка на рынке подвергает потребителей риску. Некоторые из моих друзей говорили, что получили сообщения от нового приложения для знакомств под названием Cerca. Очевидно, что приложения для знакомств требуют много личной информации, поэтому я хотел убедиться, что данные моих друзей в безопасности, прежде чем они начнут пользоваться этим приложением.
Я загрузил приложение и запустил Charles Proxy (вместе с приложением для iPhone), чтобы перехватить сетевые запросы и посмотреть, что это приложение делает «под капотом».
Прежде всего, давайте войдем в систему. Они используют только вход на основе OTP (просто отправляют текстовый код на номер телефона), поэтому я пошел проверить ответ от срабатывания одноразового пароля. БУМ — сам OTP код находится прямо в ответе, что означает, что любой человек может получить доступ к аккаунту, используя только его номер телефона.
Однако теперь мне нужно было найти способ определить, у кого есть аккаунт — я не хочу просто угадывать номера телефонов. Поэтому я обратился к конечной точке api.cercadating.com
и с помощью фаззера каталогов перечислил пути, надеясь найти соответствующие конечные точки. Я не смог получить доступ ни к одной части сайта без соответствующего заголовка из приложения:
Поэтому я подделал этот заголовок с помощью Gobuster и, к моему (не слишком сильному) удивлению, все конечные точки были открыты, благодаря обнаруженной конечной точке /docs
, в которой лежал openapi.json
!
Я включил Burp Suite и использовал инструменты match-and-replace, чтобы всегда передавать этот заголовок app-version вместе с токеном, который я извлек из Charles. И все стало еще интереснее.
Некоторые незащищенные конечные точки, похоже, затрагивали только бизнес-логику — например, эту я мог использовал, чтобы заставить двух людей сойтись друг с другом:
Но другие, например конечная точка получения профиля (user/{user_id}
), показались более интересными. Эта конечная точка принимает действительный идентификатор пользователя и возвращает всевозможную личную информацию (включая номера телефонов, необходимые для полного перехвата аккаунта, благодаря уязвимости OTP). Я написал быстрый скрипт на Python, чтобы выяснить действительные идентификаторы пользователей, и все, БАЦ — я в деле. Я мог получить данные всех пользователей, формат ответа выглядел примерно так:
{ "status": "success", "message": "string", "results": 0, "data": { "first_name": "string", "last_name": "string", "gender": "MALE", "interested_genders": [ "MALE" ], "city": "string", "latitude": 0, "longitude": 0, "university_email": "user@example.com", "university_email_verified": false, "industry": "string", "profession": "string", "date_of_birth": "2025-02-21", "height": 0, "university_id": 0, "university_name": "string", "profile_completed": false, "national_id_verified": false, "mobile_verified": false, "email_verified": false, "premium": false, "premium_expiry": "2025-02-21T21:31:06.213Z", "active": true, "paused": false, "onboarded": false, "profile_type": "PROFESHIONAL", "mobile_number": "string", "email": "user@example.com", "user_type": [ "user" ], "user_id": 0, "remaining_searches": 0, "profile_images": [], "university": { "id": 0, "name": "string" }, "score": [], "match_preferences": [], "user_prompts": [], "mutual_contact_previews": [], "mutual_contact_preview_data": [], "mutual_contact_count": 0, "created_at": "2025-02-21T21:31:06.213Z", "updated_at": "2025-02-21T21:31:06.213Z", "zodiac_info": {}, "distance_km": 0, "final_score": 0, "age": 0 }, "meta": {} }
Теперь я не только мог выяснить все действительные телефонные номера, привязанные к аккаунтам (который затем может было перехватить с помощью неправильной конфигурации OTP), но и все эти персональные данные находились в открытом доступе без необходимости входа с OTP! Но дальше — хуже: поле national_id_verified
кажется особенно пугающим. Конечно, они хранят в системе и вашу паспортную или идентификационную информацию, например, вот так:
{ "status": "success", "message": "string", "results": 0, "data": { "verification_type": "PASSPORT", "document_number": "string", "front_side_url": "string", "back_side_url": "string", "selfie_url": "string", "status": "pending", "id": 0, "user_id": 0 }, "meta": {} }
Это доступно только для пользователя, вошедшего в систему, но поскольку я мог войти как любой пользователь, я мог увидеть идентификационные данные любого человека, если он их предоставил (опять же, я этого не делал). Я мог не только увидеть личные сообщения любого человека с потенциальными кандидатами, но и его паспортные данные!
Я запустил простой скрипт, чтобы посмотреть, о скольких пользователях я могу получить информацию, сколько из них зарегистрированы как студенты Йельского университета (я предполагаю, что могло бы быть и больше студентов, возможно, они просто не указали свой университет), и сколько пользователей ввели свои идентификационные данные. Скрипт, по сути, просто считал, сколько действительных пользователей он видит; если после 1000 последовательных идентификаторов он не находил ни одного, то останавливался. Так что их могло быть и больше (сами Cerca заявляли о 10 тысячах пользователей в первую неделю), но я смог найти 6117 пользователей, 207 из которых ввели свои идентификационные данные, а 19 утверждали, что они студенты Йельского университета.
Невероятная утечка данных! У меня есть доступ к сексуальным предпочтениям, интимным сообщениям и всевозможным персональным данным от (по словам самих Cerca) десятков тысяч ничего не подозревающих пользователей. Cerca в своей политике конфиденциальности утверждает, что «мы используем шифрование и другие стандартные меры для защиты ваших данных», но это явно неправда. Это создает значительные риски для безопасности и конфиденциальности пользователей. Учитывая, что я всего лишь студент колледжа, случайно заглянувший в эту тему, вполне возможно, что существуют и другие критические уязвимости (хотя полный захват аккаунта уже устанавливает довольно высокую планку).
Последствия этой уязвимости — полное вторжение в частную жизнь с потенциально очень вредными последствиями в реальном мире. Люди должны научиться создавать безопасные приложения, а не утверждать, что их приложения безопасны, когда это не так. Особенно это касается приложений для знакомств! Нельзя ожидать, что все пользователи сделают проверку, которую я провел в этой статье. Кто знает, сколько людей уже имели доступ ко всем этим данным до того, как я их обнаружил? Кто-то мог уже скачать полную базу данных с личной информацией и интимными чатами 6,000+ пользователей и использовать ее в своих целях. Если кто-то со злым умыслом завладеет этой информацией, это может привести к краже личных данных, преследованию, шантажу — чему угодно.
Подобные уязвимости очень страшны, они могут разрушить жизнь в одночасье. Люди должны уделять первостепенное внимание защите пользовательских данных, а не просто выпускать приложение, которое, по их мнению, может стать виральным. Я не ставил перед собой задачу найти эту уязвимость, чтобы написать этот пост, но поскольку Cerca не ответила ни на одно из моих писем после нашего разговора и не предупредила никого из своих пользователей, я решил, что это честный пост, который стоит опубликовать. Я не стремлюсь никого победить, просто хочу, чтобы интернет был безопаснее!
-
Новости3 недели назад
Видео и подкасты о мобильной разработке 2025.22
-
Новости2 недели назад
Видео и подкасты о мобильной разработке 2025.24
-
Вовлечение пользователей4 недели назад
Небольшое изменение в интерфейсе Duolingo, которое меняет все
-
Маркетинг и монетизация4 недели назад
Институциональные покупки: понимание и обнаружение