История о слабой внутренней безопасности в разгар скандалов и новых правил.

Несмотря на то, что они продвигают умные свидания с помощью науки и машинного обучения, их сайт было так легко взломать за 15 минут.

Заявление об ограничении ответственности:

Я не фанат онлайн-знакомств, и на моих устройствах не установлено никаких приложений для онлайн-знакомств. Я пробовал несколько самых известных онлайн-приложений для знакомств, и они мне не понравились. Я люблю подходить к людям где угодно и здороваться.

Так почему я подписался на это?

Они продвигали его в подполье как сайт знакомств, основанный на науке. Это действительно заинтриговало меня увидеть, как это работает.

Вы регистрируетесь, отвечаете на десятки вопросов о себе, а затем они показывают вам несколько совпадений с размытыми фотографиями, говоря, что они совместимы с вами примерно на 95%. Не платя за полное членство, вы сможете только смотреть, насколько вы совместимы, улыбаться людям и отправлять заранее определенные сообщения, такие как «Если бы вы были знамениты, кем бы вы были?» или «Если бы у вас был последний день в жизни, что бы вы сделали?». Если бы они ответили, вы бы не узнали, что они ответили, и не смогли бы отправить личное сообщение, если только вы не заплатите.

Этот сайт знакомств стоит более 50 фунтов стерлингов в месяц за возможность просматривать фотографии и отправлять сообщения людям. Это, безусловно, связано с тем, что они предоставляют такие умные услуги.

Сегодня вечером, когда я работал над своим стартапом DeveloperHub.io - сервисом для создания вашей собственной красивой документации по продукту, справочника по API, руководств пользователя в размещенных центрах разработчиков (порталах) - я получил сообщение от кого-то со стопроцентной совместимостью, как утверждает сайт знакомств. , поэтому я был очень заинтригован, узнав, кто она такая.

Сайт знакомств даже не позволяет прочитать сообщение. Поэтому я подумал: хм, давайте посмотрим, насколько умны эти «умные» люди.

Если вы не технический специалист, перейдите к разделу Мораль истории ниже.

Пусть начнется обратный инжиниринг

Я подумал, что первое, что я могу сделать, это увидеть входящий и исходящий сетевой трафик из приложения. Я использую приложение на своем iPhone. Итак, я установил на свой Mac прокси, Charles, и запустил Wi-Fi iPhone через этот прокси.

Я могу видеть профиль и каждую деталь, которую она ввела о себе. Довольно жутковато, но ладно, в любом случае это вид отображается в приложении. Но подождите, они просто отправили полный профиль девушки по незащищенному протоколу HTTP? Хм…

Есть список размытых фотографий, но я не мог легко получить доступ к не размытым фотографиям. Нет проблем, оставлю это на потом.

Кажется, что все важные запросы выполняются по SSL. Я активировал Charles SSL Proxy и установил сертификат Charles SSL на свой iPhone, но он просто не работал, и приложение больше не могло подключиться. Похоже, они проделали хорошую работу, зная, что я не использую надлежащие сертификаты SSL и что я выполняю атаку человека в середине.

Веб приложение

Я сказал, что если приложение iOS немного сложно взломать, давайте попробуем веб-приложение. Я захожу на их сайт и захожу в систему. Я почти видел тот же интерфейс, те же размытые лица, тот же почтовый ящик, который я не мог прочитать.

В Chrome довольно легко читать запросы HTTPS, и я так и сделал. Отфильтровал вкладку «Сеть» до XHR, посмотрел на запросы GET и вуаля… Вот только что полученное мной сообщение чата в почтовом ящике!

[
  {
    "messageId": "b123738-5123-4123-9123-1232333b1234",
    "type": "CHAT",
    "value": "Hi Zed! I feel like I should send an interesting message but I'm all Mondayed out. How are you?",
    "createdTimeStamp": 1523914585468,
    "readTimeStamp": 1523914778123,
    "sender": false
  },
  {
    "messageId": "ABC1235C-AABC-4ABC-8ABC-1ABC4EBC7ABC",
    "type": "SMILE",
    "createdTimeStamp": 1523883156123,
    "readTimeStamp": 1523886591123,
    "sender": true
  }
]

Ха! Это было просто.

Ладно, круто, но я все равно не могу ни определить, кто этот человек, ни ответить. Поскольку мы зашли так далеко, возможно, мы сможем пойти еще дальше.

На этом этапе - я начал писать этот пост на Medium, потому что понял, что их безопасность не кажется изумительной.

Отправка сообщения - это сработает?

Если мне нужно отправить сообщение, первое, что мне нужно сделать, это посмотреть, как выглядит отправка сообщения. Итак, я переключился на любого другого человека, который есть в моем списке совпадений, нажал кнопку, чтобы отправить заранее определенное сообщение, выбрал одного из них «Если бы вы знаменит, кем бы вы были?» И отправил его.

Тем временем я сохранял журнал сетевых запросов Chrome.

Хорошо, просматривая только что созданные запросы PUT и POST, я нигде не могу найти слово «знаменитый». Это то, что сообщение не отправляется, или что-то еще происходит?

В одном из запросов POST, которые произошли после того, как я отправил сообщение, полезная нагрузка была:

{
  "logs": [
    {
      "logMessage": "Message Sent (Soft ACK) - on server sender",
      "method": "WEBSOCKET",
      "logLevel": "INFO",
      "additionalInfo": "{\"messageId\":\"12351f23-fABC-4ABC-9ABC-ABCc123a0ABC\",\"matchId\":12309078132}"
    }
  ]
}

Websocket. Черт побери, чат происходит через веб-сокеты (я этого и ожидал). Посмотрим, что делает веб-сокет.

Проверка веб-сокетов

Переходя к фильтрации веб-сокетов на вкладке «Сеть Chrome», мы обрадовались, что нужно было отслеживать только один веб-сокет.

Хорошо, давайте сделаем самое простое и отфильтруем по слову «известные».

Блин, «знаменитых» в вебсокете тоже не бывает. Перебирая сообщения, пытаясь понять отправляемый XML (кто, черт возьми, использует XML в наши дни для связи через веб-сокеты?), Похоже, что это:

  • Открытие соединения
  • Аутентификация в сервисе websocket
  • Подключение к клиенту Jabber и настройка конфигурации здесь и там
  • Тогда отправьте сообщение!

<message xmlns=”jabber:client” to=”[email protected]” id=”84123ff6-f123-4123-9123-c123458a0abc" type=”chat”><body>{“message”:{“messageId”:”84123ff6-f123-4123-9123-c123458a0abc",”type”:”CEQ”,”value”:”62"}}</body><request xmlns=”urn:xmpp:receipts”/><data><accesstoken>84123ff6-f123-4123-9123-c123458a0abc</accesstoken><header name=”User-Agent” value=”Mozilla/5.0 (Macintosh; Intel Mac OS X 10THUMB5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"/><header name=”X-xyz-gdid”/><resourceid>12309078132</resourceid></data></message>

Замечательно, теперь, когда я понимаю, как работает рассылка, давайте попробуем повторить это.

Я установил расширение Simple Websocket Client Chrome, скопировал URL-адрес веб-сокета, открыл соединение с веб-сокетом, и это было успехом. Следующие шаги:

  • Хорошо, давайте сделаем первый запрос на открытие соединения. Хороший.
  • Аутентифицируйте. Хороший.
  • Подключитесь к клиенту Jabber и установите эти параметры. Хороший.

Ха, это просто. Хорошо, как нам сообщить об этом матче?

Глядя на полезную нагрузку JSON, кажется, что существует объект сообщения, а затем предварительно определенное сообщение имеет идентификатор, и мы его отправляем. Я решил попробовать установить для ключа сообщения значение «Привет!», Просто чтобы попробовать.

{“message”:"Hey There!"}

Аааа, ошибка.

<error code=’400' type=’modify’><bad-request xmlns=’urn:ietf:params:xml:ns:xmpp-stanzas’/><text xmlns=’urn:ietf:params:xml:ns:xmpp-stanzas’>Can not instantiate value of type [simple type, class com.xyz.services.comm.api.message.Message] from String value (&apos;Hey there!&apos;); no single-String constructor/factory method
at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@b5a4c95; line: 1, column: 2] (through reference chain: com.xyz.services.comm.api.message.ClientMessageWrapper[&quot;message&quot;])</text></error></message>

Хм, интересно. Не ожидал такой схемы. Давай еще раз посмотрим. Я отправляю заранее определенный идентификатор сообщения, поэтому он должен где-то существовать. Давайте посмотрим на список заранее определенных сообщений.

Я открыл список, чтобы отправить больше сообщений, проверил HTML и выяснил, что это сообщение имеет идентификатор 62.

Хорошо, я вижу, где я ошибся, messageId - это какой-то другой идентификатор, а значение 62 для предварительно определенного сообщения. Что насчет типа «CEQ», что мне установить?

Я вспомнил, что просматривая запросы GET, видел такое. Вот:

Теперь я вижу, что делать, просто установил тип на ЧАТ и значение для моего сообщения чата. Давай попробуем.

Ответ:

<message xmlns=’jabber:client’ from=’[email protected]/android.phone.emulator’ to=’1231232yr2_3–[email protected]/android.phone.emulator’ xml:lang=’en’ id=’123f7–32' type=’chat’><data/><received xmlns=’urn:xmpp:receipts’ id=’81231236-f5ce-abcd-9abc-c6e12312312c0'/></message>

О ДА, Я ПОЛУЧИЛ ЧЕК. Обновите страницу почтового ящика, и вуаля, мы написали сообщение.

Поговори с моей спичкой

Последний кусочек головоломки - знать, как разговаривать с кем-нибудь на этом веб-сайте, а не только с этим человеком. Кажется, что у человека, с которым я болтаю, нет никакого идентификатора, кроме как во фрейме веб-сокета сообщения. Кажется, что адрес чата, который выглядит как адрес электронной почты, является идентификатором человека, которому я отправляю сообщения.

to=”[email protected]

Откуда мне взять этот идентификатор.

Скопируйте расширенную информацию профиля в Sublime Text. Найдите адрес чата в тексте. Ах, это зашифрованный идентификатор пользователя. Хорошо, давай попробуем.

{“message”:{“messageId”:”84123ff6-f123-4123-123b-c6123e8a1230",”type”:”CHAT”,”value”:”Good evening Sophie! Haha already tired? Interesting messages are over-rated anyway 😜”}}

Что ж, это был провал, я отправил его той же девушке, на которой я тестировал. Ха. Не надо было добавлять имя, теперь оно будет выглядеть супер-странно… Виииллл. Давай еще раз попробуем.

После долгого просмотра всех этих идентификаторов и адресов чата выясняется, что это идентификатор ресурса:

<resourceid>12309078132</resourceid>

Пробный номер 2:

Найдите идентификатор этого ресурса. Хорошо, это незашифрованный идентификатор пользователя. Очень просто. Отредактируйте идентификатор ресурса и вуаля. Мы получили сообщение милашке!

Зачем останавливаться здесь

Я начал думать, ну развлекается. Как насчет того, чтобы сейчас попытаться увидеть эти размытые фотографии. В массиве JSON профиля есть список фотографий, и URL-адреса выглядят так:

https://images.xyz.com/photos/v2/photo/NORMAL/I1/d5abcttnp5yxjytb227v6fp56p.jpg?blur=60&crop=faces&fit=crop&g=2&h=160&ixlib=java-1.1.1&w=160&s=cda2e652b4182b123a1f5f6781daa36a

Я пытался изменить параметры запроса, но всегда получал пустое изображение.

Я подумал, может быть, если у меня будет платная учетная запись, тогда я смогу увидеть, как сопоставить размытые изображения с исходными изображениями. Что ж, я не собираюсь этого делать.

Так что мы можем сделать?

💡💡💡💡💡💡💡💡💡

Просто проверьте мою фотографию в профиле, из чего состоит URL?

На самом деле, я сделал:

https://www.xyz.com/photos/v1/photo/THUMB/I3/1236VKj18jtm5Ih8Cr2pSAabc.jpg

Что это за параметры? Давайте распечатаем мой профиль на jsonprettyprint.com, скопируем в Sublime Text и произведем поиск. Оказывается, на веб-сайте есть способ нумерации изображений I1, I2, I3 и так далее, этот длинный идентификатор - мой encryptedUserId, фотографии имеют версии (1 или 2), а размеры определяются THUMB, ICON, NORMAL, и так далее. Так:

https://www.xyz.com/photos/v<version>/photo/<SIZE>/<IMAGE-NUMBER>/<ENCRYPTED-USER-ID>.jpg

Это просто, давайте применим это к изображению другого совпадения. И вуаля, у нас есть изображение.

Является ли этот сервис таким небезопасным, как я думаю?

Хорошо, давайте проверим, насколько это небезопасно. Можем ли мы читать профили других людей, даже не сравнивая их с ними? Давайте посмотрим.

Чтобы получить чей-то профиль, HTTP-запрос GET выглядит так:

https://www.xyz.com/publicapi/v2/matchprofile/<match-id>/profile

Если мы скопируем CURL из сети Chrome, мы получим такую ​​чушь:

curl 'https://www.xyz.com/publicapi/v2/matchprofile/12303942525/profile?' -H 'authorization: Bearer 12339f23-2302-4e6f-b9ae-1f9c99a6e123' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-US,en;q=0.9,ar;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10THUMB5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36' -H 'x-xyz-gdid: ' -H 'accept: application/json' -H 'Connection: keep-alive' -H 'content-type: application/json' -H 'x-xyz-platform: desktop' --compressed

Хорошо, давайте изменим одно число в идентификаторе матча и посмотрим, сможем ли мы получить данные.

404 Не Найдено.

Повторите попытку с другими номерами: 404 Not Found.

Это хорошо. Можем ли мы получить эти профили, используя идентификатор пользователя? Я не понимаю, как мы можем это сделать сейчас. Без проблем. Я не буду тратить на это больше времени, моя точка зрения доказана.

Мораль истории

Я не хакер и не хочу причинять вред. Я просто понимаю, как работают веб-сервисы. Реверс-инжиниринг, который я только что сделал, на 99% выполнен в Chrome без каких-либо других инструментов. Получить функции полноправного членства в сервисе, который требует такой высокой оплаты, было так просто, поскольку большая часть безопасности выполнялась во внешнем интерфейсе, а не в серверной части. Это крепость с высокими стенами и открытыми воротами, внутри которой нет стражи.

Рекомендации своим инженерам (если им было интересно):

  • Ради бога, используйте только безопасные соединения. Отправка чьего-либо профиля через HTTP недопустима.
  • Настройте разрешения в вашей системе обмена сообщениями Jabber. Проверьте, отправляется ли сообщение с CHAT действием, что отправляющий пользователь действительно является премиум-участником.
  • Отфильтруйте вашу messages конечную точку (которая показывает разговоры), чтобы показывать сообщения только в том случае, если пользователь является премиум-участником.
  • Не показывайте изображения без проверки членства. Вы можете перенаправить свой веб-сервер (Jetty) при запросе изображения, проверить членство и подавать его размытым, если пользователь не является пользователем премиум-класса, или обычным пользователем, если он им является.
  • И, что наиболее важно, сделайте свою безопасность изнутри!

Ваше членство можно легко заменить расширением Chrome, которое заменяет URL-адреса для фотографий, заменяет HTML-код почтового ящика в соответствии с тем, что вы получаете в запросах, и отправляет сообщения с помощью вашего веб-сокета.

Почему все это имеет значение?

После скандала с Facebook я бы рекомендовал каждой компании нанять несколько этичных хакеров, чтобы понять, где ваш сервис небезопасен. В вашей политике конфиденциальности указано, что у вас есть обширные меры безопасности, включая использование SSL, что вы будете проявлять разумную осторожность в обеспечении безопасной передачи информации, но вы также заявляете, что не несете ответственности за любое непреднамеренное раскрытие информации.

Мы живем в эпоху, когда сбор данных технически прост для компаний, а пользователи готовы безрассудно и без колебаний раскрывать свои данные, не зная о расплывчатой ​​ политике конфиденциальности, стоящей за ними. Объем данных, которые вы собираете о пользователях, огромен, и вы несете за это большую ответственность. Если вы не можете защитить эти данные, не собирайте их.

Общий регламент защиты данных (GDPR) выйдет 25 мая 2018 года. Когда постановление вступит в силу, вам лучше не отправлять профиль любого европейца на небезопасный уровень, поскольку вас могут оштрафовать на 20 миллионов евро или 4% от вашего глобальный оборот, в зависимости от того, что больше.

Обновление (25 мая 18): Здравствуйте, GDPR!

Мои надежды

Я надеюсь, что благодаря GDPR ваша осведомленность об объеме данных, которые собираются о вас, повысится. С большей осведомленностью люди начнут нерешительно предоставлять информацию о себе, которая может быть ненужной для работы служб, и компании будут вынуждены быть более прозрачными в отношении того, как они используют данные.

Помните, что с GDPR вы можете запросить копию своих данных в удобочитаемом формате у любого поставщика услуг, и этот запрос должен быть выполнен в течение 72 часов.

Как только начнут появляться новости о штрафах компаний, компании начнут применять методы защиты своих систем. В конце концов, кажется, что только 27% предприятий считают, что GDPR применим к их бизнесу, а половина предприятий Великобритании знают о GDPR.

Примечание. Я размыл и заменил все вхождения названия веб-сайта и всю идентифицирующую информацию об участниках, относящихся к ним. Этот пост не предназначен для веб-сайта и не предназначен для причинения им вреда.

Если вам понравилась эта история, 👏 👏 👏 за нее ниже!