Кратко

  • Если ключ меняется после чтения Session, но до создания подписки, проверочное push-сообщение может быть отклонено. Сервер не должен повторять такую проверку; клиент обязан проверить возвращённый sessionState.
  • Техническое сообщение об ошибке 9055 предлагает удалить необязательный механизм последнего уведомления из RFC 9749. На момент проверки оно имело статус Reported, а не Verified: это ещё не утверждённая поправка.

Ожидание удобно тем, что не требует нового решения. Запрос уже принят, удалённый сервис что-то делает, остаётся дождаться следующего сообщения. Но иногда следующее сообщение не задерживается: отправитель прямо не должен повторять отвергнутую попытку.

Такой случай описан в RFC 9749, опубликованном в марте 2025 года. Документ вводит аутентификацию VAPID для JMAP Web Push и рассматривает смену ключа приложения во время создания подписки. В результате клиент может получить ответ на запрос создания, но не завершить проверку канала. Выход из этого состояния требует обнаружить, что сведения о ключе уже устарели.

Речь не идёт об установленной аварии конкретного поставщика. Из рассмотренных источников нельзя вывести долю затронутых устройств, число пропущенных уведомлений или объём потерянной почты. Это разбор предусмотренной протоколом ситуации и критерия, по которому стоит принимать изменение в эксплуатацию.

Между чтением и действием проходит время

Клиент узнаёт открытый ключ сервера приложения из объекта Session. Затем использует связанную с ним push-точку при регистрации подписки в JMAP. Чтение Session и PushSubscription/set не образуют единую неделимую операцию.

Если сервер заменит ключ между ними, подтверждение может быть аутентифицировано новым ключом, тогда как push-точка ограничена старым. Описанный в RFC ответ 403 в таком случае отражает несовпадение двух состояний во времени. Повторное вычисление подписи само по себе не устраняет различие.

Ограничение имеет смысл. Согласно RFC 8292, отправитель в ограниченную подписку должен доказать владение закрытым ключом, соответствующим открытому ключу, указанному при её создании. Если отправителю позволить самостоятельно заменить это условие любым текущим ключом, защита исчезнет. Новый открытый ключ требует новой подписки.

Впрочем, 403 не является однозначным диагнозом гонки при ротации. Недействительная подпись, неправильная аудитория токена и нарушения срока его действия тоже могут привести к отказу аутентификации. Для вывода о смене ключа нужны согласованные сведения о времени создания, поколении ключа и состоянии Session. Массовое пересоздание после любого 403 способно увеличить нагрузку, не затронув настоящую причину.

Нужно различать и сами ключи. Подпись VAPID удостоверяет сервер приложения, а шифрование полезной нагрузки отвечает за конфиденциальность. Для подписи и обмена ключами шифрования должен использоваться разный закрытый ключевой материал. Успешная аутентификация не доказывает доставку, прочтение уведомления или действие пользователя.

Ответ API ещё не означает работающий канал

В RFC 8620 начальная проверка нужна, чтобы клиент подтвердил доступ к данным, отправленным по указанному адресу. Пока он не вернул правильный проверочный код, сервер не должен отправлять последующие запросы. Принятое создание и завершённая проверка — разные этапы.

Особенно важно, где искать признаки изменившихся условий. У PushSubscription/set нет условия ifInState, а в результате нет oldState и newState. Нельзя автоматически перенести сюда контроль конкурентного обновления обычной коллекции. Нужный sessionState находится во внешнем ответе API и относится к объекту Session.

RFC 9749 требует, чтобы клиент проверял эти сведения относительно ожидаемого applicationServerKey. При несовпадении клиент может снова попытаться создать подписку и может удалить предыдущую неудачную попытку. Это восстановление на основе актуальной информации, а не бесконечное повторение запроса с прежней предпосылкой.

Запрет для сервера также нужно читать точно. Он касается отклонённой PushVerification в рассматриваемой ситуации, а не всех повторных отправок любых push-сообщений. Пересоздать правильно связанную подписку на стороне клиента — не то же самое, что заставить сервер снова проверять уже отвергнутую связь в тех же условиях.

Операционная метрика «подписка активна» поэтому требует расшифровки. Был ли принят запрос? Вернулся ли код? Проверена ли связь и к какому поколению ключа она относится? Пользовательский интерфейс может не показывать все промежуточные шаги, но эксплуатационные данные должны позволять их различить.

Иначе отсутствие уведомлений выглядит одинаково при двух разных обстоятельствах: новых изменений действительно нет либо канал ещё не прошёл проверку. Счётчик принятых запросов не отличает нормальное молчание от незаконченного подключения.

Инструкция переустановить приложение иногда меняет локальное состояние, но не доказывает работоспособность штатного восстановления. В качестве управленческой проверки полезно спросить, не перекладывает ли такой универсальный совет реконструкцию на пользователя. Это возможный сценарий для оценки, а не обвинение конкретного сервиса.

У последнего сигнала есть нерешённая проблема

RFC 9749 допускает переходный период, когда старые подписки ещё обслуживаются соответствующим старым ключом. По окончании периода, либо сразу при его отсутствии, сервер обязан уничтожить подписки предыдущего ключа. Общая обязательная продолжительность такого сосуществования не установлена.

Исходный текст также предлагает необязательный последний StateChange для определённых старых подписок. Предполагается, что он вызовет PushSubscription/changes и поможет обнаружить новое состояние Session. Именно эта цепочка стала предметом технического замечания.

Запись 9055 в перечне ошибок RFC Editor, поданная Neil Jenkins 31 июля 2026 года, предлагает удалить абзац. В ней отмечено, что PushSubscription не связан с учётной записью, необходимой для описанной структуры StateChange, а метода PushSubscription/changes в RFC 8620 вообще нет.

При проверке 7 сентября 2026 года запись всё ещё имела статус Reported, не Verified. Следовательно, нельзя представлять предложение как уже вступившую в силу нормативную поправку. Однако обе особенности интерфейса можно независимо проверить по RFC 8620. Практический вывод ограничен: спорную последовательность нельзя выдавать за подтверждённый механизм совместимости и надёжное последнее предупреждение.

Это не доказательство неисправности всех реализаций. Состояние текста стандарта, статус замечания и поведение конкретного продукта — три разных предмета проверки. Их смешение делает материал громче, но лишает эксплуатационную рекомендацию точности.

Даже технически корректное предупреждение не гарантировало бы пробуждение неактивного клиента. RFC 8030 ограничивает время хранения push-сообщений и позволяет сервису его сокращать. Сообщение с нулевым временем жизни не ждёт недоступное устройство. Слово «последнее» выражает намерение отправителя, а не факт получения.

Поэтому нужен тест возвращения: способен ли клиент после периода бездействия обнаружить смену и создать подтверждённую замену, если никакого предупреждения не видел? Реестр возможностей JMAP у IANA фиксирует согласованный идентификатор расширения. Он не удостоверяет распространённость реализации или успешное восстановление установленных версий.

Сохранять ход событий, а не жизнь старых секретов

Для расследования полезны поколение ключа, момент принятия попытки, завершение проверки и вывод подписки из эксплуатации. Полный push-адрес и секреты шифрования не обязательно сохранять ради такого следа.

RFC 8620 требует безопасно удалять эти значения при уничтожении подписки. PushSubscription/get не должен возвращать URL и ключи даже по прямому запросу. Несекретные идентификаторы поколений и временные отметки с ограниченным сроком хранения позволяют наблюдать переход, не создавая постоянную копию отозванного материала в диагностических журналах.

Срок жизни подписки связан и с данными доступа к API, которыми она была создана. Их истечение или отзыв нельзя свести к очередному сбою транспорта. Кроме того, клиенту не следует изменять подписки с deviceClientId, который он не распознаёт как собственный.

Восстановление одного устройства ценой удаления связей остальных расширяет область вмешательства. Локальный успех в этом случае оплачивается чужими разрывами. Соблюдение границ входит в качество восстановления не меньше, чем появление нового уведомления.