Как я обошёл запрет на Messages API через документацию Вконтакте

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

С чего всё началось


Все мы знаем, что у ВК есть API, и я уверен, что большинство людей пыталось им воспользоваться в своих целях. Лично у меня полно проектов, связанных с ним: штук 5 мощных ботов, составление масштабных датасетов из постов групп и т.д. И не удивительно, что мои знакомые просили меня пару раз выкачать песни из вложений диалога, фотографии или же сохранить текст переписок с каким-нибудь человеком в отдельный файл.

Но однажды пришло «оно», и с того момента выполнение таких небольших просьб перестало быть тривиальной задачей:

image

И вот, пару дней назад, чтобы раз и навсегда избавиться от этой проблемы, я решил написать свою обёртку через http запросы, притворяясь обычным пользователем, дабы иметь такой же мощный инструмент, как официальный API для раздела messages.

Переходим к делу


Итак, начал я с авторизации. Вооружившись сниффером https и Firefox-ом, я смог пройти все «ступеньки» авторизации и получить финальные куки. С этого момента оставалось только понять, как именно делаются запросы. Было выяснено, что большинство данных получается POST запросом от https://vk.com/wkview.php, просто каждый раз меняются параметры для разных ситуаций. Мне удалось написать функции для выкачки абсолютно всех видов вложений, но не будем вдаваться в подробности этого, потому что в один момент всё кардинально изменилось.

Ссылка на файл для получения куки авторизации (Писал только для двухфакторной аутентификации, так как она стоит у большинства людей)


Неожиданное открытие


Я работал на ноутбуке, когда ко мне подошёл знакомый и спросил, чем я занимаюсь. Так как у меня не получилось ему объяснить всю проблему быстро на пальцах, я открыл официальную документацию на разделе messages, и обомлел, когда увидел, что находится под главным описанием у этих «запрещённых» методов:

image

Нет, вы поймите меня правильно, я не первый раз вижу эту возможность. Я много раз пользовался ею у других методов, но я даже и подумать не мог, что функция «пример запроса» останется у методов раздела messages. И ещё более сильным было моё удивление, когда я проснифферил трафик. Это были просто обычные запросы к API, только на сайте, у которых лишь слегка отличались названия параметров в веб-форме и был какой-то хэш-айди.

image

За несколько минут я понял, что хэш-айди — это просто строка, находящаяся в атрибуте data-hash атрибута кнопки, а ещё через пару минут я уже вовсю пытался реализовать эмуляцию «тестовых запросов» и до конца не верил, что будет работать. Ведь наверняка у этих запросов есть какое-то ограничение по количеству или что-то подобное. Но каково же было моё удивление, когда этот скрипт в 30 строк (не считая получения куки), который был написан на коленках, смог за 4 минуты выкачать полторы тысячи картинок из вложений диалога.

image

Прикладываю использованный код
import requests, pickle, re, json

with open('cookies_vk_auth.pickle', 'rb') as handle:
    cookies_final = pickle.load(handle)

session = requests.Session()
peer_id = int(input('Введите айди пользователя:  '))

response = session.get(f'https://vk.com/dev/messages.getHistoryAttachments', cookies=cookies_final)
hash_data =  re.findall(r'data-hash="(\S*)"', response.text)[0]

session = requests.Session()
response = session.post(f'https://vk.com/dev',
            data=f'act=a_run_method&al=1&hash={hash_data}&method=messages.getHistoryAttachments¶m_count=20¶m_max_forwards_level=45¶m_media_type=photo¶m_peer_id={peer_id}¶m_photo_sizes=0¶m_preserve_order=0¶m_v=5.103', cookies=cookies_final)

count=20

for i in range(200):
    response_json = json.loads(json.loads(response.text[4:])['payload'][1][0])['response']['items']

    for photo in response_json:
        ph = photo['attachment']['photo']['sizes'][-1]['url']
        r = session.get(ph, timeout=10)
        
        if r.status_code == 200:
            with open(f'D://dev/'+str(ph.split('/')[-1]), 'wb') as f:
                f.write(r.content)

    m_id = photo['message_id']
    response = session.post(f'https://vk.com/dev',
            data=f'act=a_run_method&al=1&hash={hash_data}&method=messages.getHistoryAttachments¶m_count=20¶m_start_from={m_id}¶m_max_forwards_level=45¶m_media_type=photo¶m_peer_id={peer_id}¶m_photo_sizes=0¶m_preserve_order=0¶m_v=5.103', cookies=cookies_final)


Я был на столько поражён, что на этом моменте я решил остыть и попробовать реализовать какой-нибудь другой метод (вдруг я просто ошибся). Я взялся за метод History и результат был аналогичным. Только пришлось поставить задержку в 0.1 секунды, чтобы сервер не выдавал ошибку о слишком большом количестве запросов. (Если кто-то будет повторять, прошу не забыть, что при смене метода нужно также менять и url на документацию, откуда берётся hash-data). То есть этот способ действительно давал возможность получить доступ к разделу messages через официальную документацию, используя лишь пароль и логин пользователя. Для достоверности я попробовал проделать те же шаги на другом аккаунте и получил тот же результат.

Подводим итоги


И так, думаю, все уже осознали, что это — брешь в защите наших персональных данных, которая висела в документации целый год и не известно сколько людей уже воспользовались ей. Причём эта брешь очень крупная, и её нужно скорее закрыть. И чтобы ещё раз доказать, что это не должно так работать, процитирую самих разработчиков ВК:

Если Вы планируете начать разработку мессенджера, после 15 февраля 2019 года для этого потребуется получить в Поддержке тестовый доступ, подразумевающий работу методов секции Messages с ключами администраторов Вашего Standalone-приложения.


То есть даже для получения токена внутреннего приложения, который будет иметь доступ к переписке пользователя, нужно личное разрешение от ВК, что уж говорить о доступе с обычным паролем и логином.

Моё личное мнение


Запрет раздела messages не привнёс кардинальных изменений в безопасность пользователей. Он всего-лишь обозначил границу и отсёк группу «недо-хакеров», которые даже не понимая того, что делают, могли получить полный доступ к данным. Для остальных же людей, более опытных в программировании, получение доступа к перепискам — это всего лишь вопрос времени. И я уже в первой части статьи доказал на собственном примере, создав программку для выкачивания вложений, что появление библиотеки, которая сможет притворяться пользователем, не за горами. Может я и сам доведу её до конца, а разработчикам ВК нужно быть готовыми к этому и придумать способы распознавания слишком подозрительной активности пользователей, если для них конфиденциальность наших данных действительно важна.

P.S.

Также прошу не судить за этот незакоментированный код, он писался быстро и на коленках) А также большое спасибо друзьям, которые помогали мне с написанием первой статьи.

© Habrahabr.ru