Как-то пятничным вечером я сидел за домашним компом с чашкой черного чая, писал статью и думал о жизни. Работа спорилась, но голова начинала к тому времени заметно притормаживать. И вот когда за окном стало уже совсем темно, я решил отправить статью отдыхать до завтрашнего дня, да и самому пойти спать. Но вместо того, чтобы сохранить все в черновик, как полагается, сонный
Понял я это не сразу, а только спустя несколько минут, зайдя напоследок обновить свой профиль. Ощущение было, как будто не выключил газ на кухне и все вот-вот умрут. Я молился, чтобы ее можно вернуть в черновики или хотя бы удалить. Кстати, последнего, как оказалось, сделать уже нельзя, если материал попал в общее обозрение. Впоследствии говорил на этот счет с тех поддержкой, но мне порекомендовали просто смириться с провалом)
Не буду томить — статья в итоге успешно вернулась в гнездо — но какой-то добрый самаритянин уже успел поставить ей плюс. Но что самое интересное, несмотря на то, что статьи больше не было на сайте, рейтинг, полученный за нее, остался у меня в профиле.
Это не могло не натолкнуть на мысль воспроизвести ситуацию в промышленных масштабах.
У меня тогда как раз накопился один инвайт, которым я решил поделиться с другом и заодно проверить теорию. Разумеется, кликать по одной статье за раз — это скучно и, тем более, не подобает уважающему себя разработчику. К тому же, не слишком безопасно, потому что есть риск просто попасться.
Будем автоматизировать.
Подслушиваем Habrahabr
Нам надо получить следующие методы: создание статьи, публикация, голосование и скрытие статьи в черновиках.
Процесс авторизации проходить не будем, поскольку он сложный, с кучей переадресаций, да и достаточно просто вытащить все cookie и прикинуться ветошью браузером.
В качестве веб прокси будем использовать Charles для Mac. Крайне удобная вещь. Если вы разработчик, то рекомендую иметь её в своем джентельменском наборе. Позволяет также слушать трафик с любого подручного девайса, если вы, например, отлаживаете мобильное приложение.
В рамках одной сессии успешно получаем все необходимые нам методы.
Как оказалось, за создание, публикацию и удаление статей отвечает один и тот же запрос, но с разными параметрами. Можно создать пост в качестве черновика или сразу его опубликовать. И именно здесь прописывается будет ли ваш пост в песочнице, переводом или ходовой публикацией. Может быть, это даст возможность обойти требования к публикации в песочнице, но не проверял. Скорее всего, сервер просто развернет домой с какой-нибудь забавной ошибкой.
Проверяем на практике
Уже практически праздную победу, делаю запрос на создание поста:
params = {
:id => '',
:post_type => 'simple',
:flow => 5,
:hubs => [20742],
:title => 'test1',
:text => 'test1',
:tags_string => 'test1'
}
response = HTTParty.post('https://habrahabr.ru/json/topic/?action=save', headers: headers, body: params)
# Получаем id поста для последующего использования
params[:id] = JSON.parse(response.body)['redirect'].split('/')[2]
Flow равное 5 и Hubs равное 20742 — это не случайные числа, а вполне осознанно выбранный наименее популярный поток 'Разное' и хаб 'Читальный зал', чтобы снизить вероятность быть уличенным в афере.
Но тем не менее, Habr нам почему-то отвечает отказом:
{
"system_errors": [
"Неизвестный тип публикации"
]
}
Странно. Ведь все параметры верны, post_type установлен и точно совпадает с нужным и все поля на месте. Проверяем запрос из прокси — работает. А из кода — ошибка.
Как оказалось после веселой отладки, если отсутствует заголовок Referer, то любой запрос к API падает. Юзабилити на высоте. И еще один забавный случай: независимо от того какое значение указано в поле draft, публикация все равно будет создаваться черновиком:
Даже если стоит 0 или вообще абракадабра.
Но если поля вообще нет, то статья уже публикуется в общий поток.
Хорошо, пост создали, можно голосовать. Тут все тоже довольно просто и завелось с первого раза:
vote_headers = {
'Cookie' => HTTP::Cookie.cookie_value(vote_jar.cookies(habr_uri)),
'User-Agent' => 'Mozilla/5.0',
'Referer' => 'https://habrahabr.ru/top/',
'Content-Type' => 'application/x-www-form-urlencoded',
'Accept' => 'application/json'
}
vote_body = {
# Помните прошлый запрос?
'ti' => params[:id],
'tt' => 2,
'v' => 1
}
uri = URI.parse('https://habrahabr.ru/json/vote/')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.path, vote_headers)
request.body = URI.encode_www_form(vote_body)
# Только для отладки
puts http.request(request).body
Запрос через HTTParty отчаянно отказывался работать с голосованием, пришлось пилить его через net/http. Аргументы, конечно, не самые говорящие в API, но в целом все понятно: id публикации и два магических параметра. Элементарно.
Автоматизируем
Теперь все вместе. Достаем через прокси наши Cookies, сначала для одного аккаунта, с которого будем постить, а потом для второго, с которого будем голосовать.
Запускаем запросы последовательно друг за другом и все, вроде как, хорошо. И тут я понял, что для смены аккаунтов мне пришлось явно разлогиниться на сайте. Но при этом моя сессия все равно продолжала работать из кода.
То есть, мои куки никто и не думал обнулять на бэкенде. Хабр, как-то нехорошо так поступать со своими пользователями. Не секьюрно.
Оставим все как есть, и запустим процедуру в цикле. Крутим без какого-либо delay, но на второй же итерации натыкаемся на забавную ошибку с пасхалкой:
{
"system_errors": [
"Повтор на втором игроке!"
]
}
Кто постарше помнит, что раньше была такая передача 'Пойми меня', где дети по цепочке объясняли друг другу слова. И если двое сделали это одинаково, то ведущий говорил: 'повтор на таком-то игроке!'. Ссылка на запись игры.
Мне кажется, это многое говорит о возрасте тех, кто разрабатывал хабр.
Постепенно увеличиваем задержку, и методом перебора выясняем, что таймаут на создание постов стоит 30 секунд. Запускаем цикл и уходим пить любимый кетчуп чай.
Не будем наглеть, остановимся на 30 баллах, исчеркав все черновики хабра:
122 место, неплохо. Осталось чуть-чуть до первой сотни. А вот и сами тестовые посты:
Как можно заметить, на сайте нет никакого упоминания о вашей деятельности, посты никто не видел, кроме вас самих, но рейтинг при этом присутствует.
Заключение
Вот таким нехитрым способом можно незаметно накрутить своему товарищу рейтинг.
Возможно, хабру стоит поставить ограничение на несколько публикаций в день, чтобы этой особенностью не злоупотребляли. И я бы еще все-таки сделал сброс сессии при логауте.
Спасибо за внимание.
P.S. Не баньте меня, пожалуйста. Баньте его — sp1nfox, это ему рейтинг накручивали.
Автор: Mehdzor