
Стартапам нужно ответственнее относиться к безопасности
Слишком немногие люди знают, как создавать безопасные приложения — обычно разработчики торопятся выйти на рынок, подвергая риску своих пользователей. Однажды друзья сказали мне, что увидели рекламу нового приложения для дейтинга под названием Cerca. Очевидно, дейтинг-приложениям нужно много личной информации, поэтому я решил убедиться, что мои друзья в безопасности.
Я скачал приложение и запустил Charles Proxy (для приложения iPhone), чтобы перехватывать сетевые запросы и контролировать происходящее внутри приложения.
Для начала давайте выполним вход. Приложение использует вход на основе OTP (код отправляется по номеру телефона), поэтому я решил проверить ответ на запрос одноразового пароля. БУМ – OTP находился непосредственно в ответе, то есть к аккаунту любого пользователя можно получить доступ, зная только телефонный номер.

Однако мне теперь нужно как-то узнать, кому принадлежит аккаунт, я не могу просто перебирать номера. Я перешёл к конечной точке api.cercadating.com и воспользовался directory fuzzer, чтобы составить список путей, надеясь найти нужные конечные точки. Без соответствующего заголовка приложения я не мог получить доступ ни к одной из частей сайта:

Поэтому я передал заголовок при помощи Gobuster, и к моему (не очень сильному) удивлению оказалось, что раскрыты все конечные точки; это удалось выяснить благодаря найденной конечной точке /docs, передававшей openapi.json!

Я запустил Burp Suite и использовал инструменты сопоставления и замены, чтобы заголовок версии приложения и токен носителя (извлечённый из Charles Proxy) передавались автоматически. И тут всё стало ещё любопытнее.
Некоторые незащищённые конечные точки, похоже, влияли только на бизнес-логику, например, та, которую можно было использовать для принудительного «мэтча» между двумя пользователями:

Но другие, например, получение конечной точки профиля пользователя (user/{user_id}), казались более любопытными. Эта конечная точка получает валидный ID пользователя и возвращает всю личную информацию (в том числе и телефонные номера, которых благодаря уязвимости OTP достаточно для полного захвата аккаунта). Я написал короткий скрипт на Python для подбора валидных ID и смог создать список всех пользователей; формат ответа выглядел примерно так:
{ "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 порядковых ID, он ничего не находил, то прекращал выполнение. Так что, возможно, их больше (сами владельцы Cerca заявили о 10 тысячах пользователей за первую неделю), но мне удалось найти 6117 пользователей; 207 из них ввели информацию из удостоверяющих личность документов, а 19 указали, что учатся в Йеле.

Это просто безумная утечка! У меня появился доступ к сексуальным предпочтениям, интимным сообщениям и всевозможной личной информации десятков тысяч (согласно данным самого Cerca) ничего не подозревающих пользователей. В своей политике конфиденциальности Cerca заявляет: «Мы используем шифрование и другие стандартные меры для защиты вашей информации», но это, очевидно, не так. Это подвергает существенному риску безопасность и конфиденциальность пользователей. Учитывая то, что я просто студент колледжа и это мой хобби-проект, возможно, существуют и другие критические уязвимости.
Последствием использования такой уязвимости станет полное нарушение конфиденциальности с потенциально очень серьёзным ущербом в реальной жизни. Разработчикам нужно научиться делать безопасные приложения и не говорить, что их приложения безопасны, хотя это не так. Особенно, когда дело касается дейтинг-приложений! Нельзя ожидать. что пользователи будут заниматься всеми проверками, которые выполнил я. Кто знает, сколько людей уже имели доступ ко всем этим данным до того, как их обнаружил я. Кто-то мог уже скачать полную базу данных с личной информацией более чем шести тысяч пользователей и личные чаты. Если какой-то злоумышленник получит доступ к этой информации, то это может привести к краже личности, преследованиям или шантажу. Подобные уязвимости очень страшны, они во мгновение могут сломать чью-то жизнь. Разработчики должны отдавать высокий приоритет защите пользовательских данных, а не просто публиковать приложение, надеясь на его популярность. Я занялся поиском этой уязвимости не для того, чтобы написать пост, но поскольку разработчики Cerca не отвечали на мои письма и не уведомила своих пользователей, я решил, что справедливо будет опубликовать эти сведения. Я не хочу никого взламывать, а просто стремлюсь к повышению безопасности Интернета!
Хронология и ответственное раскрытие: выявив эти уязвимости, 23 февраля 2025 года я связался с командой Cerca по почте. На следующий день (24 февраля) у нас состоялся продуктивный видеозвонок, в котором мы обсудили уязвимости, потенциальные способы их устранения и дальнейшие шаги. В беседе команда Cerca признала серьёзность этих проблем, выразила благодарность за ответственное раскрытие и уверила меня, что должным образом устранит уязвимости и проинформирует пользователей.
С тех пор я пробовал связаться с ними несколько раз (5 марта и 13 марта), желая узнать новости об устранении проблемы и уведомлении пользователей. К сожалению, на дату публикации моего поста (21 апреля 2025 года) никаких ответов я не получил. Насколько я знаю, Cerca не признала публично наличие инцидента и не проинформировала пользователей об уязвимости, несмотря на данные мне обещания. Также разработчики больше не связывались со мной после видеозвонка и игнорировали все мои последующие письма.
Однако мне удалось самостоятельно убедиться, что описанные в этом посте уязвимости были пропатчены, что позволяет мне опубликовать свои находки.
ссылка на оригинал статьи https://habr.com/ru/articles/908918/
Добавить комментарий