Web Push: Что такое и с чем едят
Введение
Web Push — это технология, позволяющая веб-приложениям получать сообщения от сервера даже тогда, когда страница не загружена в браузере или находится в фоновом режиме. В отличие от классических HTTP-запросов, которые инициируются клиентом, push-уведомления инициируются сервером и доставляются через инфраструктуру браузера, что делает их идеальным инструментом для оповещений, обновлений и re-engagement'а пользователей.
Push API является стандартизированным W3C-спецификацией и с марта 2023 года широко доступен во всех основных браузерах. Однако за кажущейся простотой отправки уведомления скрывается сложная экосистема из протоколов, механизмов шифрования, сервис-воркеров и push-сервисов. Мы разберём Web Push до уровня протоколов, рассмотрим архитектуру, безопасность, новые стандарты и практические нюансы реализации.
Архитектура Web Push: три ключевых компонента
Web Push строится на взаимодействии трёх основных сущностей:
- Браузер (User Agent) — клиентская среда, в которой работает веб-приложение.
- Push-сервис (Push Service) — внешний сервис, предоставляемый поставщиком браузера (например, FCM от Google для Chrome, APNs от Apple для Safari), который принимает push-сообщения от сервера приложений и доставляет их на устройства пользователей.
- Сервер приложений (Application Server) — ваш бэкенд, который инициирует отправку push-сообщений.
Ключевая особенность: сервер приложений никогда не взаимодействует с браузером напрямую. Все сообщения проходят через push-сервис, который выполняет роль посредника, обеспечивая доставку даже тогда, когда браузер закрыт или устройство офлайн.
Service Worker — невидимый обработчик
Для получения push-сообщений веб-приложение должно зарегистрировать service worker. Service worker — это JavaScript-скрипт, который работает в фоновом режиме, независимо от открытой страницы. Именно он:
- Подписывается на push-уведомления через PushManager.subscribe()
- Принимает входящие push-события через обработчик onpush
- Отображает уведомления через ServiceWorkerRegistration.showNotification()
// Регистрация service worker
navigator.serviceWorker.register('/sw.js');
// В service worker (sw.js)
self.addEventListener('push', (event) => {
const data = event.data.json();
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body,
icon: '/icon.png'
})
);
});
Каждая подписка уникальна для конкретного service worker, а её endpoint (URL, на который сервер отправляет сообщения) является capability URL — знание этого URL достаточно для отправки сообщения. Именно поэтому endpoint необходимо хранить в секрете.
Протокол Web Push: как сервер отправляет сообщение
Протокол, определяющий формат HTTP-запроса от сервера приложений к push-сервису, описан в RFC 8030. Этот запрос — не просто POST с телом сообщения, он включает сложную систему аутентификации и шифрования.
VAPID — аутентификация сервера приложений
VAPID (Voluntary Application Server Identification) — это механизм, позволяющий push-сервису удостовериться, что сообщение отправлено именно тем сервером приложений, который создал подписку. Это предотвращает ситуацию, когда злоумышленник, получивший endpoint, может отправлять сообщения от имени вашего приложения.
Процесс аутентификации выглядит так:
- Сервер приложений генерирует пару ключей VAPID (публичный и приватный) на основе кривой P-256.
- Публичный ключ передаётся в браузер при вызове
PushManager.subscribe(). - При отправке push-сообщения сервер создаёт JSON Web Token (JWT) с полями:
aud (audience) — URL push-сервиса
exp (expiration) — timestamp истечения срока действия токена
sub (subject) — контактный email разработчика
- JWT подписывается приватным ключом VAPID с использованием алгоритма ES256.
- Подписанный JWT передаётся в заголовке
Authorizationзапроса. - Push-сервис проверяет подпись, используя сохранённый публичный ключ.
POST https://fcm.googleapis.com/... HTTP/1.1
Authorization: vapid t=eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9..., k=...
Content-Type: application/octet-stream
Content-Encoding: aes128gcm
Шифрование полезной нагрузки
Сообщения, передаваемые через push-сервис, обязательно шифруются. Это гарантирует, что даже push-сервис (который может принадлежать третьей стороне, например Google) не сможет прочитать содержимое уведомления.
Долгое время стандартом шифрования был RFC 8291, использующий ECDH (эллиптическую криптографию) в сочетании с AES-128-GCM.
Переход на HPKE
В июле 2026 года опубликован новый Internet-Draft «WebPush Encryption using HPKE» (Hybrid Public Key Encryption), который заменяет RFC 8291.
Причина перехода — подготовка к пост-квантовой эпохе: текущая эллиптическая криптография уязвима перед квантовыми компьютерами. HPKE использует гибридную схему шифрования, сочетающую механизм инкапсуляции ключей (KEM) и предварительно разделённый ключ (PSK) с аутентифицированным шифрованием с дополнительными данными (AEAD).
Важно: на сентябрь 2026 года HPKE-документ остаётся Internet-Draft (рабочим черновиком) со сроком действия до 25 января 2027 года. Он ещё не является утверждённым RFC, но является официальным направлением развития стандарта.
Параллельно разрабатывается альтернативный подход — «WebPush Encryption using Symmetric Ciphers», определяющий использование чисто симметричной криптографии с Web Push.
Жизненный цикл push-подписки
Создание подписки
// В основном потоке
async function subscribeUser() {
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(publicVapidKey)
});
// Отправляем subscription на сервер
await fetch('/api/subscribe', {
method: 'POST',
body: JSON.stringify(subscription),
headers: { 'Content-Type': 'application/json' }
});
}
Объект PushSubscription содержит:
- endpoint — URL для отправки сообщений
- keys — объект с публичными ключами (p256dh — ключ для шифрования, auth — секрет для аутентификации)
Важно: userVisibleOnly: true означает, что каждое push-сообщение должно сопровождаться видимым уведомлением — браузеры не разрешают «тихие» push-сообщения без отображения нотификации.
Хранение подписки на сервере
Подписку необходимо сохранять на сервере, привязав к конкретному пользователю. Без этого вы не сможете отправить сообщение — endpoint является единственным способом достичь браузера пользователя.
// Пример хранения в базе данных
const subscription = {
endpoint: 'https://fcm.googleapis.com/...',
expirationTime: null,
keys: {
p256dh: 'BP...',
auth: 'C...'
}
};
Отправка сообщения
На сервере отправка выглядит так (пример с библиотекой web-push для Node.js):
const webpush = require('web-push');
webpush.setVapidDetails(
'mailto:example@yourdomain.com',
publicVapidKey,
privateVapidKey
);
await webpush.sendNotification(
subscription, // сохранённая подписка
JSON.stringify({ title: 'Hello!', body: 'World' })
);
Альтернативные реализации доступны для различных экосистем: Go (go-webpush), PHP, .NET, Deno и другие.
Declarative Web Push — новый стандарт
Традиционный Web Push требует, чтобы service worker выполнял JavaScript при каждом получении сообщения. Это создаёт несколько проблем:
- Каждое push-событие требует запуска JS-кода
- Каждое «тихое» push-сообщение расходует бюджет браузера
- Доставка зависит от исправности service worker
Declarative Web Push решает эти проблемы. Вместо выполнения кода сервер отправляет небольшой JSON-документ с описанием уведомления, и браузер рендерит его напрямую.
Статус стандарта
Declarative Web Push перешёл из статуса Safari-эксперимента в W3C Working Draft. W3C Push API Working Draft был опубликован 1 декабря 2025 года. Стандарт получил поддержку нескольких вендоров (multi-vendor editorship).
Формат полезной нагрузки:
{
"web_push": 8030,
"notification": {
"title": "Your order has shipped",
"body": "Tracking number AT-48201 is on the way.",
"navigate": "https://example.com/orders/48201",
"icon": "https://example.com/icon.png",
"app_badge": 3
}
}
Ключ "web_push": 8030 (ссылка на RFC 8030) сигнализирует браузеру, что это декларативное уведомление. Поле navigate определяет URL, который откроется при клике — без необходимости писать notificationclick-обработчик. Поле app_badge обновляет бейдж на иконке приложения на домашнем экране.
Поддержка браузеров:
| Платформа | Версия | Дата | Детали |
|---|---|---|---|
| iOS / iPadOS | 18.4 | Март 2025 | Первый публичный релиз для Home Screen web apps |
| macOS / Safari | 18.5 | Май 2025 | Поддержка на Mac для установленных и обычных сайтов |
| Safari | 26.0 – 26.4 | Сентябрь 2025 – Март 2026 | Улучшение developer ergonomics, автоматическая пауза service worker в Web Inspector |
| iOS 26 | — | 2026 | Все сайты, добавленные на Home Screen, по умолчанию открываются как web app |
Apple выступила лидером внедрения. Mozilla заняла позитивную позицию в отношении стандарта. К 2026 году декларативный формат стал предпочтительным для iOS и macOS веб-пушей.
Ограничения и квоты
Chrome Push API rate limits
С января 2026 года Chrome начал внедрять ограничения скорости для Push API на основе вовлечения пользователей. Это часть долгосрочной стратегии Google по борьбе со спам-уведомлениями.
Как работает:
Ежедневно рассчитываются три ключевых фактора:
1. Количество push-сообщений на единицу времени, проведённого на сайте
2. Количество показанных запросов разрешения на единицу времени
3. Уровень вовлечения пользователя с сайтом (на основе engagement score и времени в фокусе)
Когда сайт признаётся нарушающим (disruptive) — отправляет большое количество уведомлений при очень низком вовлечении — его способность отправлять сообщения ограничивается до не менее 1000 сообщений в минуту.
Дополнительные меры Chrome:
- Автоматическое удаление разрешений на уведомления для сайтов, с которыми пользователь не взаимодействовал недавно
- Автоматический отзыв разрешений для сайтов, помеченных Google Safe Browsing как злоупотребляющие
- On-device машинное обучение для выявления спам-уведомлений на Android
Надёжность доставки
Push-доставка никогда не гарантируется на 100%. Причины:
- Браузер не запущен на устройстве
- Устройство офлайн
- Подписка истекла (токены могут «протухать» без предупреждения)
- Пользователь отозвал разрешение
Важное ограничение: Firefox не может отправлять уведомления на неактивные сайты, что ограничивает охват по сравнению с Chrome и Edge.
Рекомендуется реализовать:
- Retry-механизмы с экспоненциальной задержкой
- Мониторинг истечения подписок (поле expirationTime в PushSubscription)
- Обработку ошибок 410 (Gone) — сигнал, что подписка более не действительна
6. Поддержка браузеров
| Браузер | Windows | macOS | Android | iOS |
|---|---|---|---|---|
| Chrome | ✅ | ✅ | ✅ | ✅ |
| Firefox | ✅ | ✅ | ✅ | ✅ |
| Safari | ❌ | ✅ (macOS 13+) | ❌ | ✅ (iOS 16.4+) |
| Edge | ✅ | ✅ | ✅ | ✅ |
| Opera | ✅ | — | ✅ | — |
Ключевые требования:
- HTTPS — обязателен для всех браузеров
- Явное согласие пользователя — запрос разрешения должен инициироваться действием пользователя
Особенности Safari:
- Использует Apple Push Notification Service (APNS)
- iOS 17.4: пользователи в Евросоюзе больше не могут устанавливать PWA на Home Screen, что блокирует уведомления Safari для этого региона
Безопасность и конфиденциальность
Разрешения пользователя
Браузеры НЕ ДОЛЖНЫ предоставлять доступ к Push API без явного согласия пользователя. Это означает, что:
- Запрос разрешения должен инициироваться действием пользователя (клик, тап)
- Пользователь может в любой момент отозвать разрешение в настройках браузера
Конфиденциальность endpoint'ов
Push-эндпоинты НЕ ДОЛЖНЫ раскрывать информацию о пользователе — устройство, идентичность или местоположение. Push-сервис не должен позволять коррелировать разные подписки одного пользователя.
Метаданные vs содержимое
Хотя содержимое сообщения зашифровано, push-сервис всё равно видит метаданные: факт отправки, время, размер сообщения, частоту. Это неизбежный компромисс: push-сервис должен знать, кому и когда доставлять сообщение.
CORS
В сообществе обсуждается необходимость явной поддержки CORS для push-серверов, чтобы упростить одноранговые (P2P) сценарии.
Практические рекомендации
UX получения разрешения
Никогда не запрашивайте разрешение на push-уведомления сразу при загрузке страницы. Пользователь должен понимать, зачем ему это нужно. Рекомендуется:
- Показать поясняющий UI («Хотите получать уведомления о новых сообщениях?»)
- Запросить разрешение только после явного согласия пользователя
- Обработать отказ — не блокировать функциональность
Управление подписками на сервере
Храните для каждого пользователя:
- Объект
PushSubscription - Дату создания подписки
- Признак активности (если пришла ошибка 410 — удаляйте)
Реализуйте эндпоинты:
POST /api/push/subscribe— сохранение подпискиDELETE /api/push/unsubscribe— удаление при отписке
Оптимизация полезной нагрузки
- Ограничьте размер сообщения — стандартный лимит: до 70 символов для заголовка, 250 для тела
- Используйте сжатие (Content-Encoding: aes128gcm уже включает сжатие)
- Для сложных данных используйте ID ссылки вместо полного объекта
Мониторинг и отладка
- В Chrome DevTools → Application → Service Workers можно симулировать push-события
- Safari 26 добавил автоматическую паузу service worker в Web Inspector для отладки push-событий
- Логируйте ошибки отправки на сервере для выявления проблемных подписок
Генерация VAPID-ключей
# Пример генерации с использованием web-push CLI
npx web-push generate-vapid-keys
Или программно:
keys, err := webpush.GenerateVAPIDKeys()
pem, err := keys.ExportVAPIDPrivateKeyPEM()
Web Push vs нативные push-уведомления
| Характеристика | Web Push | Нативные Push |
|---|---|---|
| Требования | HTTPS, Service Worker | SDK, сертификаты |
| Доставка | Зависит от браузера | Управляется ОС |
| Срок жизни токена | Может истечь без предупреждения | Стабильнее |
| Кастомизация | Ограничена API браузера | Полный контроль |
| Стоимость | Бесплатно | Требует аккаунтов разработчика |
Web Push идеально подходит для:
- PWA и веб-приложений
- Быстрого прототипирования
- Сценариев, где нативное приложение нецелесообразно
Будущее Web Push
Экосистема Web Push активно развивается. Ключевые тренды на 2026 год:
- HPKE вместо RFC 8291 — Internet-Draft от июля 2026 года, переход на пост-квантово-устойчивое шифрование
- Declarative Web Push — стандартизация в W3C, расширение поддержки в браузерах
- Ужесточение политик — Chrome вводит лимиты на частоту отправки для сайтов с низким вовлечением
- Унификация платформ — iOS 16.4+ добавил поддержку Web Push, существенно расширив охват
- Более широкий PWA-охват — iOS 26: все сайты на Home Screen по умолчанию открываются как web app
Заключение
Web Push — это мощный, но сложный механизм, требующий понимания нескольких уровней абстракции: от service worker'ов в браузере до криптографических протоколов на сервере. Мы разобрали архитектуру, протоколы VAPID и шифрования (включая переход на HPKE), процесс подписки и отправки, а также новые стандарты, такие как Declarative Web Push.
Ключевые выводы:
- Service worker — обязательный компонент для приёма сообщений (кроме Declarative Web Push)
- VAPID — аутентификация сервера приложений (RFC 8292)
- Шифрование — обязательное условие (переход с RFC 8291 на HPKE)
- Endpoint'ы — чувствительные данные, требуют безопасного хранения
- Declarative Web Push — будущее стандарта (W3C Working Draft), упрощающее реализацию
- Rate limits — Chrome внедряет ограничения на основе вовлечения пользователей с 2026 года
При правильной реализации Web Push становится надёжным каналом коммуникации с пользователями, повышая вовлечённость и ценность веб-приложений.