Внимание! Сайт не обновлялся более 3х лет!
Перейти в портфолио компании

Авторизация Вконтакте C++Builder

17 марта 2012

Сколько же статей на эту тему в рунете.. Но хоть один из способов работает?

Пробуйте хоть все, - ни один!

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

Но сейчас способ все таки нашелся. С одной стороны ничего особенного в нем нет, просто нужно учитывать несколько факторов. 

Все что нам понадобится, это TIdHTTP, снифер, барузер, ну и немного смышленности.

Для начала зайдем на vk.com, если вы авторизированы - произведите выход.

Вот наш объект:

Исследуем исходный код страницы авторизации и проследим последовательность событий

<a href="javascript: quick_login()">Вход</a>

Находим функцию quick_login()

 

function quick_login() {
  var options = {onSuccess: try_to_login};
  hide('message_text');
  Ajax.postWithCaptcha('/login.php', 
{'op': 'a_login_attempt', 'login': ge('email').value}, options);
}

Необязательно осмысливать каждую строку, в этой функции ключевой момент try_to_login
 

var vklogin = false;
function try_to_login(obj, text) {
  if (text.substr(0, 4) == 'good') {
    var to = 'YWxfZmVlZC5waHA-';
    if (location.hash.toString().length) {
      to += location.hash;
    }
    if (to.length) {
      window.location.href = '/' + to;
    } else {
      window.location.href = '/id' + text.substr(4);
    }
  } else if (text.substr(0, 10) == 'not_active') {
    window.location.href = '/login.php?r=1';
  } else if (text.substr(0, 6) == 'invite') {
    window.location.href = '/help.php?page=welcome&hash=' + text.substr(6);
  } else if (text.substr(0, 9) == 'reginvite') {
    window.location.href = '/register.php?hash=' + text.substr(9);
  } else if (text.substr(0, 7) == 'vklogin') {
    vklogin = true;
    ge('login').submit();
  } else {
    show('message_text');
    ge('message_text').innerHTML = "<div id="error" style="font-size: 11px">
Указан неверный логин или пароль.</div>";
  }
}

Ключевой момент:ge('login').submit(); - если вы создали хоть одну html форму, то сразу почувствуете, вот она, отправка запроса!
И вот на какую формочку мы наткнулись:

<form method="post" name="login" id="login" action="https://login.vk.com/" onsubmit="if (vklogin) {return true} 
else { quick_login();return false;}">
 <input type="hidden" name="act" id="act" value="login">
 <input type="hidden" name="success_url" id="success_url" value="">
 <input type="hidden" name="fail_url" id="fail_url" value="">
 <input type="hidden" name="try_to_login" id="try_to_login" value="1">
 <input type="hidden" name="to" id="to" value="YWxfZmVlZC5waHA-">
 <input type="hidden" name="vk" id="vk" value="1">
 <input type="hidden" name="al_test" value="3">
 <input type="hidden" name="from_host" value="vk.com">
 <input type="hidden" name="from_protocol" value="http">
 <input type="hidden" name="ip_h" value="3d2c01fb0ff2d54c22">
 ...
 <input class="inputText" type="text" name="email" value="" id="email">
 ...
 <input class="inputText" type="password" name="pass" value="" id="pass">
 </form>

Самые простые параметры, в нашем запросе будем использовать лишь те, которые имеют значение. Разве что кроме полей to, al_test> и ip_h - хешированный IP уж нам точно не понадобится..

Как кажется на первый взгляд - это победа! Сформировать POST-запрос и все готово... нуну...

 

Включим снифер, посмотрим что отправляет браузер

 

Host: vk.com
Proxy-Connection: keep-alive
Content-Length: 46
Origin: http://vk.com
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.79 Safari/535.11
Content-Type: application/x-www-form-urlencoded
Accept: */*
Referer: http://vk.com/login.php?m=1&email=fuckall_666%40mail.ru
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.3
Cookie: remixlang=0; remixdt=7200; audio_vol=100; remixseenads=1; remixflash=11.1.102; remixchk=5
 
op=a_login_attempt&login=***мой эмейл***­fdOGј
 
После этого запроса сразу же следуют редиректы с GET-запросами!
 
GET http://www.tns-counter.ru/V13a***R%3Ehttp://vk.com/login.php?m=1&email=**мой эмейл**vkontakte_ru/ru/UTF-8/tmsec=vk_total/899708346 HTTP/1.1
Host: www.tns-counter.ru
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.79 Safari/535.11
Accept: */*
Referer: http://vk.com/feed
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.3
Cookie: guid=49D10B044F5328ECX1330850028
 
Чего там только не летит! ООоопа!!! А вот это уже интересно!
Вот вам секретный агент, который знает о вас все!
Это своеобразный "счётчик" который владеет информацией о просмотре страниц с вашего IP, какие сообщения читали, какие сообщения отправляли, и много всего прочего!
Может кто не знает, но слежка происходит не только с сайта vk.com. А так же и с вашего любимого компьютера! Подобного рода счетчики "натыканы" повсюду! Но об этом как-нибудь в другой статье)
 
 
Пора приступать к написанию нашей функции авторизации!
Разумеется все моменты объяснять нет смысла, т.к. статья будет содержать избыточную информацию.
Лишь основные, важные моменты буду комментировать.
 
Алгоритм:
1) Подготавливаем авторизационные данные
2) Выключаем редирект
3) Формируем POST-запрос авторизации в нужной кодировке
4) Посылаем сформированный запрос
5) Получаем адрес редиректа
6) Роемся в хедерах на предмет cookies
7) Устанавливаем найденные cookies + те что выдал снифер
8) Включаем редирект (да, пусть отправляет инфу о том, что мы зашли, пусть нас контролируют хД)
9) Получаем страницу по адресу на который были перенаправлены
10) Проверяем результат
 
Поехали:
1)
Объявляем следующие переменные:

TStringList *LoginInfo = new TStringList; // Авторизационные данные
TStringStream *Response = new TStringStream;  // Поток ответа от сервера
String Location,  // Адрес перенаправления
html,  //html-странчка
cookie;  // куки

2) 

IdHTTP1->HandleRedirects = false;
// Был у меня плачевный опыт, когда так не делал
IdHTTP1->Request->CustomHeaders->Clear(); 

3)

     
LoginInfo->Add("act=login");
LoginInfo->Add("expire=");
LoginInfo->Add("captcha_sid=");
LoginInfo->Add("captcha_key=");
LoginInfo->Add("from_host=vk.com");

 
Не видел ни одного примера в рунете, где так делают..
А ведь без этого кириллица у вас не пройдет)))
 

LoginInfo->Add("email="+IdHTTP1->URL->ParamsEncode(login, TEncoding::UTF8 ));
LoginInfo->Add("pass="+IdHTTP1->URL->ParamsEncode(pass, TEncoding::UTF8));
IdHTTP1->ProxyParams->ProxyPort = 3128;
IdHTTP1->ProxyParams->ProxyServer = "proxy.uisi.ru";
IdHTTP1->Request->UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) 
AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.79 Safari/535.11";
IdHTTP1->Request->Host = "login.vk.com";
IdHTTP1->Request->Accept = "*/*";
IdHTTP1->Request->AcceptLanguage = "ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4";
IdHTTP1->Request->Referer = "http://vk.com/login.php?m=1&email=**мой мейл***";
IdHTTP1->Request->AcceptCharSet = "windows-1251,utf-8;q=0.7,*;q=0.3";

 
4)

try {
    IdHTTP1->Post("http://login.vk.com/?act=login",LoginInfo,Response);
}catch(...){}

5)

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

Location = IdHTTP1->Response->Location;
html = IdHTTP1->Get(Location);
ShowMessage(html);
Хм.. А вот и функция установки vk кук)))
<script type="text/javascript">
var _ua = navigator.userAgent;
var locDomain = 'vk.com'.match(/[a-zA-Z]+\.[a-zA-Z]+\.?$/)[0];
if (/opera/i.test(_ua) || !/msie 6/i.test(_ua) || document.domain != locDomain) {
  document.domain = locDomain;
}
function setCookieEx(n, v, s) {
  var d = new Date();
  d.setTime(d.getTime() + 1000 * 60 * 60 * 24 * 365);
  var e = s ? ('; expires=' + d.toGMTString()) : '';
  document.cookie = 'remix' + n + '=' + escape(v) 
+ e + '; path=/; domain=.' + locDomain;
}
setCookieEx('sid', '85c119f1b1d240dda38a0a383ca8e4a25e2a07b2a137f35b7228c3600255', 1); setCookieEx('reg_sid', '', 1);setCookieEx('rec_sid', '', 1);
parent.onLoginDone('/id116443786');
</script>

6)
 

for (int i = 0; i < IdHTTP1->Response->RawHeaders->Count-1; ++i) {
    if (IdHTTP1->Response->RawHeaders->Names[i] == "Set-Cookie")
        cookie = IdHTTP1->Response->RawHeaders->ValueFromIndex[i];
}

7)

IdHTTP1->Request->CustomHeaders->Add(
"Cookie: remixchk=5;audio_vol=70;remixmid=;remixsid="+
cookie.SubString(1,cookie.Length()-abs(cookie.Pos(";")-cookie.Length()))+
"remixgid=; remixemail=; remixpass=");

8)

IdHTTP1->HandleRedirects = true;

9)

html = IdHTTP1->Get("http://vk.com/audio");
LoginInfo->Text = html;
Response->Free();

10)
Проверяем результат. Как? 
Заходим на vk.com, смотрим что там есть такого, чего не может быть в случае безуспешного входа
Можно сначала обратиться к начальному исследованию страницы входа в vk.com
А именно, там было скрытое поле со значением login
Вот оно:

<input type="hidden" name="act" id="act" value="login">

Руководствуясь логикой, функция отключения должна называться logout
Так ли это? Снова исследуем исходный код страницы vk.com
 
И правда, вот оно:

<input type="hidden" name="act" value="logout">

Это и будет являться определяющим фактором успешной авторизации:
 
Проверяем:

if (LoginInfo->Text.Pos("logout")) return true;
else return false;

И что получаем в итоге? Думали все наконец-то закончилось и можно парсить странички на предмет музыки/видео/сообщений?
А вот не так то просто оказывается с vk.com
Возможно кого-то уже могло смутить сообщение о редиректе подобное следующему:

 

"Project Project1.exe raised exception class EIdHTTPProtocolException with message 'HTTP/1.0 302 Moved Temporarily'."

 

Но это не должно вас смущать, это совершенно нормально, отладчик предупреждает вас о перенаправлении!
С этим можно жить, но как жить с тем, что все исследование коту под хвост?
 
Ок, разочаровываемся, отчаиваемся и ради успокоения проходим авторизацию vkontakte посредством браузера.
Нууу ладно.. посмотрим чуток исходник страницы..
Нуу почемууу... что же еще ему отправить, чтоб заработало...
Хм... а что он отправляет чтоб не работало? Точнее чтоб отключиться?
 
А вот такая штука:

<input type="hidden" name="act" value="logout">
<input type="hidden" name="al_frame" value="1">
<input type="hidden" name="from_host" value="vk.com">
<input type="hidden" name="from_protocol" value="http">
<input type="hidden" name="hash" value="f441fdb1d9c92cda80">

Все тоже самое.. но что это за ткое al_frame?
Скажу честно когда я увидел это, я даже предположить не мог, что это за чудо такое..
10 минут поиска в Google не дали практически ничего.. кроме ссылок авторизации следующего вида:
 
https://login.vk.com/?al_frame=1&from_host=vk.com
 
Хмм..м.м.мм... ну попробуем отправить и мы ему этот al_frame, чем бы он не являлся!
 
Добавляем в пункт 3:

LoginInfo->Add("al_frame=1");

ПРОБУЕМ! Ииии! Получилось!!!!
Вот так дорогие друзья! Нельзя отчаиваться, когда, руководствуясь логикой, и опытом, вы приходите к негативному результату!
Есть смысл еще позаниматься магией! :D
 
 
Честно говоря я так и не понял что это за al_frame такой... почему он не палится ни снифером, ни в формах запроса авторизации...
можно лишь предположить что это тип выравнивания - alignment: frame
← назад