
Стартапам нужно ответственнее относиться к безопасности
Слишком немногие люди знают, как создавать безопасные приложения — обычно разработчики торопятся выйти на рынок, подвергая риску своих пользователей. Однажды друзья сказали мне, что увидели рекламу нового приложения для дейтинга под названием 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 не признала публично наличие инцидента и не проинформировала пользователей об уязвимости, несмотря на данные мне обещания. Также разработчики больше не связывались со мной после видеозвонка и игнорировали все мои последующие письма.
Однако мне удалось самостоятельно убедиться, что описанные в этом посте уязвимости были пропатчены, что позволяет мне опубликовать свои находки.
corvair
Так скрыли они дыру или устранили?