Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Посещал ли пользователь сайт?

Атака не работает — в браузерах давно реализована защита, у меня идея «сработала» в силу того, что я не выполнил все необходимые проверки.

В прошлом было достаточно много методов определить ходил ли пользовать на какой-то сайт или нет. В основном, идея была проста: у себя на сайте через CSS каким-то способом выделяем посещённые (:visited) ссылки — например, делаем таким ссылкам шрифт больше, а потом через ДжаваСкрипт смотрим у каких ссылок ширина стала больше расчётной.

Это считалось проблемой, поэтому свойство изменили так, чтобы никакой утечки информации о посещении в ДжаваСкрипт не происходило. Все современные браузеры уже много лет от этого защищены.

Но недавно меня осенило, что есть способ обойти эту защиту!

Ведь если пользователь посещал целевой сайт, то скорее всего какие-то его ресурсы легли в кеш. Если найти какой-то ресурс этого сайта большого размера, загрузить его и попытаться определить за какое время это произошло, то по этой разнице можно понять — был он в кеше или нет.

Я попробовал сделать это с «Гитхабом». Самый большой файл, который загружается там с первой страницей — vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_primer_octicons-react_di-b40d97-9b98c5140e22.js. Занимает он 136 килобайт, вполне подходящий размер.

Как же определить момент когда он загрузится? Если посмотреть внутрь, видно, что он после скачивания создаёт свойство webpackChunk в объекте globalThis. Если перехватить обращение к этому свойству, можно понять, что файл загружен:

const t = new Date();
Object.defineProperty(globalThis, 'webpackChunk', {
  set: function() {
    console.log(new Date() - t);
  }
});

Ниже этого кода подключаем загрузку указанного файла прямо с «Гитхаба» через тег <script> и дело в шляпе.

Я проверил, если очистить кеш браузера, то файл у меня загружается примерно за 100—400 миллисекунд, если берётся из кеша — это 0—12. Легко отличить одно от другого.

2 комментария
MiRacLe 2 мес

Chrome обещал бороться и с таким методом: https://developer.chrome.com/blog/http-cache-partitioning?hl=ru

Евгений Степанищев 2 мес

Судя по этой ссылке, работать не должно. Но, блин, работает! Может они только для медиа-ресурсов это сделали?

Добавлено: не, не работает. Сам себя обманул.

Роман Парпалак 2 мес

Кстати да, этот способ не должен работать из-за «разделенного кеша». По этой же причине использование шрифтов напрямую с серверов Google Fonts не имеет преимуществ по сравнению со шрифтами на своем сервере, об этом писали на хабре: https://habr.com/ru/companies/vdsina/articles/533208/

Евгений Степанищев 2 мес

Тем не менее, у меня работает. Правда, я проверял в своей «Опере», но вряд ли там по-другому всё устроено, движок тот же, но потестирую потом в «настоящем» «Хроме».

Добавлено: Может они только для медиа-ресурсов это сделали? Проверил в «Хроме» тоже работает. Разница в загрузке — на один-два порядка.

Добавлено: не, не работает. Сам себя обманул.