09
Собственно, по поводу evercookies пишут многое: у кого-то работает у кого-то нет. Лично у меня всё нормально работает и информация в куках хранится и не сбрасывается. А значит почему не использовать?
Правда тут появляется ряд трудностей:
- исходники нужных серверных страниц (png и etag’и) на php
- необходимость ввести ряд правок в evercookie.js (например, разрешить загружать evercookie.swf с другого домен, на тот случай если есть CDN; отключить CSS History Knocker – 190 запросов к гуглу слишком много: сначала страница зависла, потом firefox вылетел); подправить пару функций для использования asp.net-страниц или хендлера
Во-первых, использовать две отдельные страницы как-то не резонно, тем более, что обе они предназначены для одного, поэтому я решил сделать хендлер (можно и страницу), которому в качестве параметров передавать имя куки и режим (png или etag). В итоге вместо evercookie_etag и evercookie_png стало EvercookieHandler.ashx?name=&emode=. Менее красиво, но не страшно: всегда можно прикрутить роутинг.
Ниже код метода ProcessRequest хендлера:
{
string mode = "";
HttpCookie cookie = context.Request.Cookies[context.Request["name"]];
if ((mode = context.Request["emode"]) != null)
switch (mode)
{
case "png":
if (cookie == null)
{
context.Response.StatusCode = 304;
}
else
{
int x = 0;
using (Bitmap img = new Bitmap(200, 1))
{
for (int i = 0; i < cookie.Value.Length; i += 3)
{
byte[] b = new byte[3];
for (byte j = 0; j < 3; j++)
if (i + j < cookie.Value.Length)
b[j] = (byte)cookie.Value[i + j];
Color c = Color.FromArgb(b[0], b[1], b[2]);
img.SetPixel(x++, 0, c);
}
context.Response.AppendHeader("Content-Type", "image/png");
context.Response.AppendHeader("Last-Modified", DateTime.Now.ToString("R"));
context.Response.AppendHeader("Expires", DateTime.Now.AddYears(20).ToString("R"));
context.Response.AppendHeader("Cache-Control", "private, max-age=" + 24 * 365 * 60 * 60 * 20);
using (MemoryStream ms = new MemoryStream())
{
img.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ms.WriteTo(context.Response.OutputStream);
}
}
}
break;
case "etag":
if (cookie != null)
{
context.Response.AppendHeader("ETag", cookie.Value);
context.Response.Write(cookie.Value);
}
else
if (context.Request.Headers["If-None-Match"] != null)
context.Response.Write(context.Request.Headers["If-None-Match"]);
break;
}
}
Замечу, что на вебдеве etag не «взлетит» – видимо сервер не поддерживает данный заголовок, зато на IIS’е всё в норме.
Следующий пункт – модификация evercookie.js.
Прежде всего избавим от мучений гугл и избавим заодно от подвисания страницу. Делается это легко – в комментариях в самом файле прописано как это сделать:
0 – выключаем данный функционал, 1 – включаем.
Далее находим определение функции evercookie_lso и немного модифицируем его:
params.swliveconnect = "true";
params.allowScriptAccess = "always"; // вот добавляемая строка
var attributes = {};
Теперь флешку можно подгружать и с других доменов.
Теперь осталось модифицировать evercookie_etag и evercookie_png
if (typeof (value) != "undefined") {
// make sure we have evercookie session defined first
document.cookie = name + '_etag=' + value;
// evercookie_etag.php handles etagging
var img = new Image();
img.style.visibility = 'hidden';
img.style.position = 'absolute';
img.src = ajaxHandler + '?name=' + name + '_etag&emode=etag';
}
else {
// interestingly enough, we want to erase our evercookie
// http cookie so the php will force a cached response
var origvalue = this.getFromStr(name + "_etag", document.cookie);
self._ec.etagData = undefined;
document.cookie = name + '_etag=; expires=Mon, 20 Sep 2010 00:00:00 UTC; path=/';
$.ajax({
url: ajaxHandler + '?name=' + name + '_etag&emode=etag',
success: function (data) {
// put our cookie back
document.cookie = name + '_etag=' + origvalue + '; expires=Tue, 31 Dec 2030 00:00:00 UTC; path=/';
self._ec.etagData = data;
}
});
}
}
this.evercookie_png = function (name, value) {
if (document.createElement('canvas').getContext) {
if (typeof (value) != "undefined") {
// make sure we have evercookie session defined first
document.cookie = name + '_png=' + value;
// evercookie_png.php handles the hard part of generating the image
// based off of the http cookie and returning it cached
var img = new Image();
img.style.visibility = 'hidden';
img.style.position = 'absolute';
img.src = ajaxHandler + '?name=' + name + '_png&emode=png';
}
else {
var context = document.createElement('canvas');
context.style.visibility = 'hidden';
context.style.position = 'absolute';
context.width = 200;
context.height = 1;
var ctx = context.getContext('2d');
// interestingly enough, we want to erase our evercookie
// http cookie so the php will force a cached response
var origvalue = this.getFromStr(name + "_png", document.cookie);
self._ec.pngData = undefined;
document.cookie = name + '_png=; expires=Mon, 20 Sep 2010 00:00:00 UTC; path=/';
var img = new Image();
img.style.visibility = 'hidden';
img.style.position = 'absolute';
img.src = ajaxHandler + '?name=' + name + '_png&emode=png';
img.onload = function () {
// put our cookie back
document.cookie = name + '_png=' + origvalue + '; expires=Tue, 31 Dec 2030 00:00:00 UTC; path=/';
self._ec.pngData = '';
ctx.drawImage(img, 0, 0);
// get CanvasPixelArray from given coordinates and dimensions
var imgd = ctx.getImageData(0, 0, 200, 1);
var pix = imgd.data;
// loop over each pixel to get the "RGB" values (ignore alpha)
for (var i = 0, n = pix.length; i < n; i += 4) {
if (pix[i] == 0) break;
self._ec.pngData += String.fromCharCode(pix[i]);
if (pix[i + 1] == 0) break;
self._ec.pngData += String.fromCharCode(pix[i + 1]);
if (pix[i + 2] == 0) break;
self._ec.pngData += String.fromCharCode(pix[i + 2]);
}
}
}
}
}
Собственно, внесённые в эти методы изменения вызваны созданием хендлера вместо php-страниц.






