У меня осталось 15 минут до конца обеденного перерыва (это важно), завтра выходной, а потому прошу мой пост приравнивать к пятничному.
В своем недавнем посте товарищ ParadoxFilm исследовал связи между участниками одной из групп «ВКонтакте», саму группу оставив анонимной. Поскольку в статье фигурировали реальные люди — участники группы, анонимизация по названию меня удивила. Процесс «деанонимизации» — под катом.
Итак, есть три
Первым делом я открыл контакты юзеров — если уж истина где-то рядом, почему бы ей не быть там? Один товарищ упоминает КВН с выступающей командой ВШЭ, другой там учился (третий состоит в группе dotNet разработчиков, привет, коллега). Окей, ищем группы по названию «ВШЭ». Результатов десятки, но поиск контакта удобно сортирует их по числу участников. Группы с 16 000 юзеров нет. Шерлок Холмс знал бы самые часто используемые синонимы, но мое имя даже на Ш не начинается.
Так что я расчехлил свою привычную VS2015 с Dark Theme, и скачал VkNet библиотеку — она первая попалась в гугле. Обновил все необходимые NuGet пакеты, сориентировал проект на .net framework 4, накидал код
private static readonly int[] UserIds = { 97723, 206186029, 105522823 };
private static readonly VkApi Api = new VkApi();
static void Main(string[] args)
{
var zeroUserGroups = GetUserGroups(UserIds[0]);
Thread.Sleep(1000);
Console.WriteLine($"Groups for id {UserIds[0]}: {zeroUserGroups.Count}");
var firstUserGroups = GetUserGroups(UserIds[1]);
Thread.Sleep(1000);
Console.WriteLine($"Groups for id {UserIds[1]}: {firstUserGroups.Count}");
var secondUserGroups = GetUserGroups(UserIds[2]);
Thread.Sleep(1000);
Console.WriteLine($"Groups for id {UserIds[2]}: {secondUserGroups.Count}");
// Тут мы ищем группы, встречающиеся в наборах всех юзеров.
// Эх, надо было сразу вместо групп идентификаторы выделять
var groupsIntersection = zeroUserGroups
.Where(group => firstUserGroups.Any(insGroup => insGroup.Id == group.Id))
.Where(group => secondUserGroups.Any(insGroup => insGroup.Id == group.Id))
.ToList();
}
private static ReadOnlyCollection<Group> GetUserGroups(long userId)
{
GroupsGetParams getUserGroupParams = new GroupsGetParams() {UserId = userId};
return Api.Groups.Get(getUserGroupParams);
}
и словил
В итоге в самом начале метода Main появился код
ApiAuthParams authParams = new ApiAuthParams
{
ApplicationId = myAppId,
Login = "my@mail.com",
Password = "myPagePassword",
Settings = Settings.All
};
Api.Authorize(authParams);
В итоге все заработало, я получил лист из двух групп: 25205856, 66036248. Вторая группа называется «The Вышка», в ней сейчас 15968 человек. Среди них, кстати, и автор первоначальной статьи.
Удачи тебе в IT, бро.
P.S. Процесс поиска занял 45 минут, «за 15 минут я еще и бутерброд доесть успею».
Комментарии (16)
LoadRunner
23.06.2016 15:20+5А вот и здравый смысл:
1. Открываем все три профиля.
2. Делаем те же выводы про ВШЭ.
3. Открываем «Интересные страницы» третьего профиля и смотрим на список.
4. The Вышка у меня оказалась в самом верху и только у неё около 16к подписчиков.
5. За минуту проверяем в первых двух профилях её наличие в аналогичном разделе.Oxoron
23.06.2016 15:26Шампанского этому господину!
Не знал, что «Интересные страницы» в контакте приравнены к группам.LoadRunner
23.06.2016 15:34Мне просто повезло :)
Интересная страница — это что-то между личной страницей и группой.
Давно заметил, что у тех, кто подписан на меня вконтакте (добавили в друзья) я попадаю в этот блок. Подозреваю, связано с общим числом друзей — когда оно переваливает за определённое число, личная страница трансформируется и где-то в недрах базы получает некий статус «интересности». Но это лишь моя теория.
И при создании группы можно сразу определить — она будет создана именно как группа или просто Публичной страницей. Во втором случае она так же попадает в блок «Интересные страницы».
Ну и у второго и третьего профиля даже блок групп не скрыт. А вот «интересные страницы» не скрываются вовсе (если это пункт «кого видно из моих друзей и подписок» в настройках приватности, то мало кто будет так заморачиваться для скрытия публичной группы). По третьему профилю вообще очень легко всё деанонимизируется.
sshk
23.06.2016 20:35А The Вышка — это не группа, а паблик. Поэтому ее и можно увидеть в интересных страницах.
impwx
23.06.2016 15:31+1Скачать три списка групп через готовую библиотеку, найти пересечения, два полученных результата проверить руками… Как-то не тянет на сакральное знание, которым нужно было поделиться с сообществом.
Oxoron
23.06.2016 15:41-2Вы абсолютно правы, статья не самая серьезная. Я честно постарался это выразить катом, первым абзацем и тэгами.
ParadoxFilm
23.06.2016 16:59Привет! Как было указано в комментах к моей статьи, ссылки на группу не было по причине того, что это запрещено правилами хабра. Конечно, узнать коей она является — труда не составит (ибо цель скрыть её никто не преследовал).
По вашей статье: не понятно, зачем авторизация (методы получения списка групп пользователя доступны без этого). Также неясно, зачем использовать библиотеку (ведь есть API ВКонтакте).
P.S. Лестно, что статья написана относительно моей. Спасибо, это было интересно!
P.P.S. Группа, естественно, найдена верно.
lizarge
23.06.2016 17:06+2Это хабрахабр или переписка студентов
неудачникованалитиков тут? Если к первой статье можно было хоть что то разумное предьявить то тут уже нечего и сказать.
Вау у вконтакте есть API а VS2015 с Dark Theme это конечно показатель глубокого профессионализма, если поставите Dark Green Theme то все девчата с соседнего ПТУ ваши конечно. Группы еще какие то в ВК, детский сад.
aquamakc
23.06.2016 17:59int[] UserIds — тип Int32 передаётся в GetUserGroups(long userId) — тип Int64,
Thread.Sleep(1000); — зачем?
Да и вообще для хабра как-то слабовато.Oxoron
23.06.2016 20:54-11. В моем случае массив состоит из констант. Константы в пределах Int32, Int32 конвертится в Int64, потери времени не критичны.
2. Thread.Sleep(1000); — у API есть ограничение по запросам в секунду. Точного значения не помнил, поэтому взял с запасом. Опять-таки, потеря 3 секунд — не проблема.
riot26
А зачем в коде логин/пароль? Можно ведь было обойтись более безопасным auth token`ом с правами только на нужные штуки.
Oxoron
Несомненно, oauth безопаснее. Другое дело, что мою одноразовую страницу не жалко, а авторизация логин-пароль-applicationId делается быстрее.