Web Push-Protokoll

Matt Gaunt

Sie haben gesehen, wie Push-Nachrichten mit einer Bibliothek ausgelöst werden. Aber was machen diese Bibliotheken genau?

Nun, sie stellen Netzwerkanfragen und achten dabei darauf, dass diese Anfragen das richtige Format haben. Die Spezifikation, die diese Netzwerkanfrage definiert, ist das Web Push Protocol.

Diagramm zum Senden einer Push-Nachricht von Ihrem Server an einen Push-Dienst

In diesem Abschnitt wird beschrieben, wie sich der Server mit Anwendungsserverschlüsseln identifizieren kann und wie die verschlüsselte Nutzlast und die zugehörigen Daten gesendet werden.

Das ist keine schöne Seite des Web-Push-Effekts und ich bin keine Experte für Verschlüsselung. Sehen wir uns die einzelnen Teile an, da es hilfreich ist, zu wissen, was diese Bibliotheken im Hintergrund machen.

Anwendungsserverschlüssel

Wenn wir einen Nutzer abonnieren, übergeben wir ein applicationServerKey. Dieser Schlüssel wird an den Push-Dienst übergeben und verwendet, um zu prüfen, ob die Anwendung, die den Nutzer abonniert hat, auch die Anwendung ist, die Push-Nachrichten auslöst.

Wenn wir eine Push-Nachricht auslösen, senden wir eine Reihe von Headern, mit denen der Push-Dienst die Anwendung authentifizieren kann. (Dies ist durch die VAPID-Spezifikation definiert.)

Was bedeutet das alles genau und was passiert genau? Nun, das sind die Schritte für die Anwendungsserver-Authentifizierung:

  1. Der Anwendungsserver signiert einige JSON-Informationen mit dem privaten Anwendungsschlüssel.
  2. Diese signierten Informationen werden als Header in einer POST-Anfrage an den Push-Dienst gesendet.
  3. Der Push-Dienst verwendet den gespeicherten öffentlichen Schlüssel, den er von pushManager.subscribe() erhalten hat, um zu prüfen, ob die empfangenen Informationen mit dem privaten Schlüssel in Verbindung mit dem öffentlichen Schlüssel signiert sind. Wichtig: Der öffentliche Schlüssel ist der applicationServerKey, der an den Aboaufruf übergeben wird.
  4. Wenn die signierten Informationen gültig sind, sendet der Push-Dienst die Push-Nachricht an den Nutzer.

Ein Beispiel für diesen Informationsfluss ist unten aufgeführt. (In der Legende unten links sind öffentliche und private Schlüssel angegeben.)

Darstellung der Verwendung des privaten Anwendungsserverschlüssels beim Senden einer Nachricht

Die „signierten Informationen“, die einem Header in der Anfrage hinzugefügt werden, sind ein JSON Web Token.

JSON-Webtoken

Mit einem JSON-Webtoken (kurz: JWT) kann eine Nachricht an Dritte gesendet werden, damit der Empfänger überprüfen kann, wer sie gesendet hat.

Wenn ein Drittanbieter eine Nachricht erhält, muss er den öffentlichen Schlüssel des Absenders abrufen und damit die Signatur des JWT validieren. Wenn die Signatur gültig ist, muss das JWT mit dem entsprechenden privaten Schlüssel signiert worden sein und somit vom erwarteten Absender stammen.

Auf https://jwt.io/ gibt es eine Reihe von Bibliotheken, die das Signieren für Sie vornehmen können. Ich empfehle Ihnen, das nach Möglichkeit zu tun. Sehen wir uns der Vollständigkeit halber an, wie ein signiertes JWT manuell erstellt wird.

Web-Push und signierte JWTs

Ein signiertes JWT ist nur ein String. Sie können sich jedoch als drei Strings vorstellen, die durch Punkte verbunden sind.

Abbildung der Strings in einem JSON Web Token

Der erste und der zweite String (die JWT-Informationen und JWT-Daten) sind JSON-Inhalte, die base64-codiert sind, was bedeutet, dass sie öffentlich lesbar sind.

Der erste String enthält Informationen zum JWT selbst und gibt an, welcher Algorithmus zum Erstellen der Signatur verwendet wurde.

Die JWT-Informationen für Web-Push müssen die folgenden Informationen enthalten:

{
  "typ": "JWT",
  "alg": "ES256"
}

Der zweite String sind die JWT-Daten. Dadurch werden Informationen zum Absender des JWT bereitgestellt, für wen es bestimmt ist und wie lange es gültig ist.

Bei Web-Push hätten die Daten folgendes Format:

{
  "aud": "https://some-push-service.org",
  "exp": "1469618703",
  "sub": "mailto:example@web-push-book.org"
}

Der Wert aud ist die Zielgruppe, also die Zielgruppe, für die das JWT bestimmt ist. Bei Web-Push ist die Zielgruppe der Push-Dienst, daher legen wir für ihn den Ursprung des Push-Dienstes fest.

Der Wert exp ist der Ablauf des JWT. Er verhindert, dass Snoopers ein JWT wiederverwenden, wenn sie es abfangen. Der Ablauf ist ein Zeitstempel in Sekunden und darf nicht länger 24 Stunden sein.

In Node.js wird der Ablauf festgelegt mit:

Math.floor(Date.now() / 1000) + 12 * 60 * 60;

Es sind 12 statt 24 Stunden, um Probleme mit abweichenden Uhrzeiten zwischen der sendenden Anwendung und dem Push-Dienst zu vermeiden.

Schließlich muss der Wert sub entweder eine URL oder eine mailto-E-Mail-Adresse sein. So kann ein Push-Dienst Kontaktinformationen aus dem JWT finden, wenn er sich an den Absender wenden muss. Aus diesem Grund benötigte die Web-Push-Bibliothek eine E-Mail-Adresse.

Genau wie die JWT-Informationen sind die JWT-Daten als URL-sicherer Base64-String codiert.

Der dritte String, die Signatur, ist das Ergebnis, aus dem die ersten beiden Strings (JWT-Informationen und JWT-Daten) mit einem Punktzeichen verbunden werden, das wir „unsigniertes Token“ nennen, und signiert es.

Für den Signaturvorgang muss das „nicht signierte Token“ mit ES256 verschlüsselt werden. Gemäß der JWT-Spezifikation steht ES256 für „ECDSA unter Verwendung der P-256-Kurve und SHA-256-Hash-Algorithmus“. Mit Web-Crypto können Sie die Signatur so erstellen:

// Utility function for UTF-8 encoding a string to an ArrayBuffer.
const utf8Encoder = new TextEncoder('utf-8');

// The unsigned token is the concatenation of the URL-safe base64 encoded
// header and body.
const unsignedToken = .....;

// Sign the |unsignedToken| using ES256 (SHA-256 over ECDSA).
const key = {
  kty: 'EC',
  crv: 'P-256',
  x: window.uint8ArrayToBase64Url(
    applicationServerKeys.publicKey.subarray(1, 33)),
  y: window.uint8ArrayToBase64Url(
    applicationServerKeys.publicKey.subarray(33, 65)),
  d: window.uint8ArrayToBase64Url(applicationServerKeys.privateKey),
};

// Sign the |unsignedToken| with the server's private key to generate
// the signature.
return crypto.subtle.importKey('jwk', key, {
  name: 'ECDSA', namedCurve: 'P-256',
}, true, ['sign'])
.then((key) => {
  return crypto.subtle.sign({
    name: 'ECDSA',
    hash: {
      name: 'SHA-256',
    },
  }, key, utf8Encoder.encode(unsignedToken));
})
.then((signature) => {
  console.log('Signature: ', signature);
});

Ein Push-Dienst kann ein JWT mithilfe des öffentlichen Anwendungsserverschlüssels validieren, um die Signatur zu entschlüsseln. Dabei wird sichergestellt, dass der entschlüsselte String mit dem „unsignierten Token“ übereinstimmt (d. h. den ersten beiden Strings im JWT).

Das signierte JWT (d. h. alle drei durch Punkte verbundenen Strings) wird als Authorization-Header mit vorangestelltem WebPush an den Web-Push-Dienst gesendet. Beispiel:

Authorization: 'WebPush [JWT Info].[JWT Data].[Signature]';

Das Web Push-Protokoll gibt außerdem an, dass der öffentliche Anwendungsserverschlüssel im Crypto-Key-Header als URL-sicherer Base64-codierter String mit vorangestelltem p256ecdsa= gesendet werden muss.

Crypto-Key: p256ecdsa=[URL Safe Base64 Public Application Server Key]

Nutzlastverschlüsselung

Sehen wir uns als Nächstes an, wie wir eine Nutzlast mit einer Push-Nachricht senden können, damit unsere Webanwendung, wenn sie eine Push-Nachricht empfängt, auf die empfangenen Daten zugreifen kann.

Eine häufig gestellte Frage von Nutzern, die andere Push-Dienste verwendet haben, lautet: Warum muss die Web-Push-Nutzlast verschlüsselt werden? Bei systemeigenen Apps können Push-Nachrichten Daten als Nur-Text senden.

Ein Vorteil von Web-Push besteht darin, dass, da alle Push-Dienste dieselbe API (Web-Push-Protokoll) verwenden, Entwickler nicht darauf achten müssen, wer der Push-Dienst ist. Wir können eine Anfrage im richtigen Format stellen und erwarten, dass eine Push-Nachricht gesendet wird. Der Nachteil ist, dass Entwickler Nachrichten an einen nicht vertrauenswürdigen Push-Dienst senden könnten. Durch die Verschlüsselung der Nutzlast kann ein Push-Dienst die gesendeten Daten nicht lesen. Nur der Browser kann die Informationen entschlüsseln. Dies schützt die Daten der Nutzenden.

Die Verschlüsselung der Nutzlast wird in der Spezifikation zur Nachrichtenverschlüsselung definiert.

Bevor wir uns die spezifischen Schritte zum Verschlüsseln von Nutzlasten von Push-Nachrichten ansehen, sollten wir uns mit einigen Techniken befassen, die während des Verschlüsselungsvorgangs verwendet werden. (Massive hat Tip an Mat Scales für seinen ausgezeichneten Artikel zur Push-Verschlüsselung.)

ECDH und HKDF

Sowohl ECDH als auch HKDF werden während des gesamten Verschlüsselungsvorgangs verwendet und bieten Vorteile für die Verschlüsselung von Informationen.

ECDH: Diffie-Hellman-Schlüsselaustausch Elliptic Curve

Stellen Sie sich vor, Sie haben zwei Personen, die Informationen austauschen möchten, Alice und Bob. Sowohl Alice als auch Bob haben ihre eigenen öffentlichen und privaten Schlüssel. Alice und Bob teilen ihre öffentlichen Schlüssel.

Die nützliche Eigenschaft von mit ECDH generierten Schlüsseln ist, dass Alice ihren privaten Schlüssel und Bobs öffentlichen Schlüssel verwenden kann, um den geheimen Wert „X“ zu erstellen. Bob kann dasselbe tun und dabei seinen privaten Schlüssel und den öffentlichen Schlüssel von Alice verwenden, um unabhängig voneinander denselben Wert "X" zu erstellen. Dadurch ist X ein gemeinsames Geheimnis und Alice und Bob mussten nur ihren öffentlichen Schlüssel teilen. Jetzt können Bob und Alice die Nachrichten mit X ver- und entschlüsseln.

ECDH definiert, soweit ich weiß, die Eigenschaften von Kurven, die diese "Funktion" ermöglichen, ein gemeinsames geheimes "X" zu erstellen.

Dies ist eine allgemeine Erläuterung zu ECDH. Weitere Informationen finden Sie in diesem Video.

Was den Code angeht: Die meisten Sprachen / Plattformen enthalten Bibliotheken, um das Generieren dieser Schlüssel zu vereinfachen.

In Node würden wir Folgendes tun:

const keyCurve = crypto.createECDH('prime256v1');
keyCurve.generateKeys();

const publicKey = keyCurve.getPublicKey();
const privateKey = keyCurve.getPrivateKey();

HKDF: HMAC-basierte Schlüsselableitungsfunktion

Wikipedia hat eine knappe Beschreibung von HKDF:

HKDF ist eine HMAC-basierte Schlüsselableitungsfunktion, die jedes schwache Schlüsselmaterial in kryptografisch starkes Schlüsselmaterial umwandelt. Es kann beispielsweise verwendet werden, um von Diffie Hellman ausgetauschte gemeinsame Secrets in Schlüsselmaterial zu konvertieren, das für Verschlüsselung, Integritätsprüfung oder Authentifizierung geeignet ist.

Im Wesentlichen nimmt HKDF nicht besonders sichere Eingaben an und macht diese sicherer.

Die Spezifikation, mit der diese Verschlüsselung definiert wird, erfordert die Verwendung von SHA-256 als Hash-Algorithmus. Die resultierenden Schlüssel für HKDF im Web-Push sollten nicht länger als 256 Bit (32 Byte) sein.

In Node könnte dies so implementiert werden:

// Simplified HKDF, returning keys up to 32 bytes long
function hkdf(salt, ikm, info, length) {
  // Extract
  const keyHmac = crypto.createHmac('sha256', salt);
  keyHmac.update(ikm);
  const key = keyHmac.digest();

  // Expand
  const infoHmac = crypto.createHmac('sha256', key);
  infoHmac.update(info);

  // A one byte long buffer containing only 0x01
  const ONE_BUFFER = new Buffer(1).fill(1);
  infoHmac.update(ONE_BUFFER);

  return infoHmac.digest().slice(0, length);
}

Tipp: Im Artikel zu diesem Beispielcode

Hier werden ECDH und HKDF lose behandelt.

ECDH ist eine sichere Möglichkeit, öffentliche Schlüssel freizugeben und ein gemeinsames Secret zu generieren. Mit HKDF werden unsichere Materialien sicher gemacht.

Diese wird während der Verschlüsselung unserer Nutzlast verwendet. Als Nächstes sehen wir uns an, was wir als Eingabe verstehen und wie diese verschlüsselt werden.

Eingaben

Wenn wir eine Push-Nachricht mit einer Nutzlast an einen Nutzer senden möchten, benötigen wir drei Eingaben:

  1. Die Nutzlast selbst.
  2. Das auth-Secret aus dem PushSubscription.
  3. Den p256dh-Schlüssel aus PushSubscription.

Wir haben gesehen, wie die Werte auth und p256dh aus einer PushSubscription abgerufen wurden. Zur Erinnerung: Für ein Abo benötigen wir diese Werte:

subscription.toJSON().keys.auth;
subscription.toJSON().keys.p256dh;

subscription.getKey('auth');
subscription.getKey('p256dh');

Der Wert auth sollte als Secret behandelt und nicht außerhalb Ihrer Anwendung freigegeben werden.

Der p256dh-Schlüssel ist ein öffentlicher Schlüssel, der manchmal als öffentlicher Schlüssel des Clients bezeichnet wird. Hier bezeichnen wir p256dh als öffentlichen Aboschlüssel. Der öffentliche Schlüssel des Abos wird vom Browser generiert. Der Browser hält den privaten Schlüssel geheim und entschlüsselt damit die Nutzlast.

Diese drei Werte, auth, p256dh und payload, werden als Eingaben benötigt. Das Ergebnis des Verschlüsselungsvorgangs ist die verschlüsselte Nutzlast, ein Salt-Wert und ein öffentlicher Schlüssel, die nur zum Verschlüsseln der Daten verwendet werden.

Salz

Der Salt muss 16 Byte zufälliger Daten umfassen. In NodeJS erstellen wir einen Salt wie folgt:

const salt = crypto.randomBytes(16);

Öffentliche / private Schlüssel

Die öffentlichen und privaten Schlüssel sollten mit einer elliptischen P-256-Kurve generiert werden, was in Node.de so gemacht würde:

const localKeysCurve = crypto.createECDH('prime256v1');
localKeysCurve.generateKeys();

const localPublicKey = localKeysCurve.getPublicKey();
const localPrivateKey = localKeysCurve.getPrivateKey();

Diese Schlüssel werden im Folgenden als „lokale Schlüssel“ bezeichnet. Sie werden nur für die Verschlüsselung verwendet und haben nichts mit Anwendungsserverschlüsseln zu tun.

Mit der Nutzlast, dem Authentifizierungs-Secret und dem öffentlichen Aboschlüssel als Eingaben und mit einem neu generierten Salt und einem Satz lokaler Schlüssel können wir die Verschlüsselung durchführen.

Gemeinsames Secret

Der erste Schritt besteht darin, ein gemeinsames Secret mit dem öffentlichen Aboschlüssel und unserem neuen privaten Schlüssel zu erstellen. Erinnern Sie sich an die ECDH-Erklärung mit Alice und Bob? So einfach ist das.)

const sharedSecret = localKeysCurve.computeSecret(
  subscription.keys.p256dh,
  'base64',
);

Damit wird im nächsten Schritt der Pseudozufallsschlüssel (PRK) berechnet.

Pseudozufälliger Schlüssel

Der Pseudo Random Key (PRK) ist die Kombination aus dem Authentifizierungs-Secret des Push-Abos und dem gemeinsamen Secret, das wir gerade erstellt haben.

const authEncBuff = new Buffer('Content-Encoding: auth\0', 'utf8');
const prk = hkdf(subscription.keys.auth, sharedSecret, authEncBuff, 32);

Sie fragen sich vielleicht, wofür der String Content-Encoding: auth\0 dient. Kurz gesagt, hat sie keinen eindeutigen Zweck, obwohl Browser eine eingehende Nachricht entschlüsseln und nach der erwarteten Inhaltscodierung suchen könnten. \0 fügt am Ende des Zwischenspeichers ein Byte mit dem Wert 0 hinzu. Dies wird von Browsern erwartet, die die Nachricht entschlüsseln und so viele Byte für die Inhaltscodierung erwarten, gefolgt von einem Byte mit dem Wert 0, gefolgt von den verschlüsselten Daten.

Unser Pseudozufallsschlüssel führt einfach die Authentifizierung, das gemeinsame Secret und eine Codierungsinformationen über HKDF aus (d.h., es wird kryptografisch stärker).

Kontext

Der „Kontext“ ist ein Satz von Byte, mit dem später zwei Werte im Verschlüsselungsbrowser berechnet werden. Es ist im Wesentlichen ein Bytearray, das den öffentlichen Aboschlüssel und den lokalen öffentlichen Schlüssel enthält.

const keyLabel = new Buffer('P-256\0', 'utf8');

// Convert subscription public key into a buffer.
const subscriptionPubKey = new Buffer(subscription.keys.p256dh, 'base64');

const subscriptionPubKeyLength = new Uint8Array(2);
subscriptionPubKeyLength[0] = 0;
subscriptionPubKeyLength[1] = subscriptionPubKey.length;

const localPublicKeyLength = new Uint8Array(2);
subscriptionPubKeyLength[0] = 0;
subscriptionPubKeyLength[1] = localPublicKey.length;

const contextBuffer = Buffer.concat([
  keyLabel,
  subscriptionPubKeyLength.buffer,
  subscriptionPubKey,
  localPublicKeyLength.buffer,
  localPublicKey,
]);

Der abschließende Kontextpuffer ist ein Label: die Anzahl der Byte im öffentlichen Aboschlüssel, gefolgt vom Schlüssel selbst, der Anzahl der Byte im lokalen öffentlichen Schlüssel und dem Schlüssel selbst.

Mit diesem Kontextwert können wir ihn zum Erstellen einer Nonce und eines Inhaltsverschlüsselungsschlüssels (Content Encryption Key, CEK) verwenden.

Schlüssel und Nonce für Contentverschlüsselung

Eine Nonce ist ein Wert, der Wiederholungsangriffe verhindert, da er nur einmal verwendet werden sollte.

Der Inhaltsverschlüsselungsschlüssel (Content Encryption Key, CEK) ist der Schlüssel, der letztendlich zum Verschlüsseln unserer Nutzlast verwendet wird.

Zuerst müssen wir die Datenbyte für die Nonce und den CEK erstellen. Dabei handelt es sich einfach um einen inhaltscodierten String, gefolgt vom Kontextpuffer, den wir gerade berechnet haben:

const nonceEncBuffer = new Buffer('Content-Encoding: nonce\0', 'utf8');
const nonceInfo = Buffer.concat([nonceEncBuffer, contextBuffer]);

const cekEncBuffer = new Buffer('Content-Encoding: aesgcm\0');
const cekInfo = Buffer.concat([cekEncBuffer, contextBuffer]);

Diese Informationen werden über HKDF ausgeführt und kombiniert Salt und PRK mit nonceInfo und cekInfo:

// The nonce should be 12 bytes long
const nonce = hkdf(salt, prk, nonceInfo, 12);

// The CEK should be 16 bytes long
const contentEncryptionKey = hkdf(salt, prk, cekInfo, 16);

Dadurch erhalten wir unseren Nonce- und Content-Verschlüsselungsschlüssel.

Verschlüsselung ausführen

Da wir nun den Verschlüsselungsschlüssel für Inhalte haben, können wir die Nutzlast verschlüsseln.

Wir erstellen eine AES128-Chiffre, indem wir den Inhaltsverschlüsselungsschlüssel als Schlüssel verwenden und die Nonce ein Initialisierungsvektor ist.

In Node funktioniert das so:

const cipher = crypto.createCipheriv(
  'id-aes128-GCM',
  contentEncryptionKey,
  nonce,
);

Bevor wir die Nutzlast verschlüsseln, müssen wir definieren, wie viel Auffüllung wir am Anfang der Nutzlast hinzufügen möchten. Mit einem Padding wird das Risiko verhindert, dass Mitleser Nachrichtentypen anhand der Größe der Nutzlast ermitteln können.

Sie müssen zwei Bytes hinzufügen, um die Länge eines eventuellen zusätzlichen Abstands anzugeben.

Wenn Sie beispielsweise kein Auffüllung hinzugefügt haben, hätten Sie zwei Byte mit dem Wert 0, d.h. es ist kein Auffüllung vorhanden, sodass Sie nach diesen beiden Bytes die Nutzlast lesen. Wenn Sie 5 Byte Auffüllung hinzugefügt haben, haben die ersten beiden Byte den Wert 5, sodass der Verbraucher weitere fünf Byte lesen und dann mit dem Lesen der Nutzlast beginnt.

const padding = new Buffer(2 + paddingLength);
// The buffer must be only zeros, except the length
padding.fill(0);
padding.writeUInt16BE(paddingLength, 0);

Dann führen wir das Padding und die Nutzlast über diese Chiffre aus.

const result = cipher.update(Buffer.concat(padding, payload));
cipher.final();

// Append the auth tag to the result -
// https://nodejs.org/api/crypto.html#crypto_cipher_getauthtag
const encryptedPayload = Buffer.concat([result, cipher.getAuthTag()]);

Wir haben jetzt unsere verschlüsselte Nutzlast. Super!

Es muss nur noch festgelegt werden, wie diese Nutzlast an den Push-Dienst gesendet wird.

Verschlüsselte Nutzlast-Header und -Text

Damit diese verschlüsselte Nutzlast an den Push-Dienst gesendet werden kann, müssen in der POST-Anfrage verschiedene Header definiert werden.

Verschlüsselungsheader

Der „Verschlüsselung“-Header muss den Salt enthalten, der für die Verschlüsselung der Nutzlast verwendet wird.

Der 16-Byte-Salt sollte wie folgt für die Base64-URL sicher codiert und dem Verschlüsselungs-Header hinzugefügt werden:

Encryption: salt=[URL Safe Base64 Encoded Salt]

Crypto-Schlüssel-Header

Wir haben festgestellt, dass der Header Crypto-Key im Abschnitt „Application Server Keys“ (Anwendungsserverschlüssel) verwendet wird, um den öffentlichen Anwendungsserverschlüssel zu enthalten.

Dieser Header wird auch verwendet, um den lokalen öffentlichen Schlüssel zum Verschlüsseln der Nutzlast freizugeben.

Der resultierende Header sieht so aus:

Crypto-Key: dh=[URL Safe Base64 Encoded Local Public Key String]; p256ecdsa=[URL Safe Base64 Encoded Public Application Server Key]

Inhaltstyp, Länge und Codierungs-Header

Der Header Content-Length ist die Anzahl der Byte in der verschlüsselten Nutzlast. Die Header „Content-Type“ und „Content-Encoding“ sind feste Werte. Dies wird unten dargestellt.

Content-Length: [Number of Bytes in Encrypted Payload]
Content-Type: 'application/octet-stream'
Content-Encoding: 'aesgcm'

Wenn diese Header eingerichtet sind, müssen wir die verschlüsselte Nutzlast als Text unserer Anfrage senden. Wie Sie sehen, ist Content-Type auf application/octet-stream gesetzt. Dies liegt daran, dass die verschlüsselte Nutzlast als Bytestream gesendet werden muss.

In NodeJS würden wir das so machen:

const pushRequest = https.request(httpsOptions, function(pushResponse) {
pushRequest.write(encryptedPayload);
pushRequest.end();

Weitere Überschriften?

Wir haben die für JWT-/Anwendungsserverschlüssel verwendeten Header behandelt (d.h. wie die Anwendung mit dem Push-Dienst identifiziert wird) und die Header zum Senden einer verschlüsselten Nutzlast.

Es gibt zusätzliche Header, mit denen Push-Dienste das Verhalten gesendeter Nachrichten ändern. Einige dieser Header sind erforderlich, andere sind optional.

TTL-Header

Erforderlich

TTL (oder Gültigkeitsdauer) ist eine Ganzzahl, die die Anzahl der Sekunden angibt, die Ihre Push-Nachricht vor ihrer Zustellung im Push-Dienst verfügbar sein soll. Wenn die TTL abläuft, wird die Nachricht aus der Push-Dienstwarteschlange entfernt und nicht zugestellt.

TTL: [Time to live in seconds]

Wenn Sie für TTL den Wert null festlegen, versucht der Push-Dienst, die Nachricht sofort zu senden. Wenn das Gerät jedoch nicht erreichbar ist, wird die Nachricht sofort aus der Push-Dienstwarteschlange gelöscht.

Technisch gesehen kann ein Push-Dienst den TTL einer Push-Nachricht bei Bedarf reduzieren. Sie können feststellen, ob dies der Fall ist, indem Sie den TTL-Header in der Antwort eines Push-Dienstes prüfen.

Thema

Optional

Themen sind Strings, mit denen ausstehende Nachrichten durch eine neue Nachricht ersetzt werden können, wenn die Themennamen übereinstimmen.

Das ist nützlich, wenn mehrere Nachrichten gesendet werden, während ein Gerät offline ist, und Sie möchten, dass der Nutzer die neueste Nachricht nur sieht, wenn das Gerät eingeschaltet ist.

Dringlichkeit

Optional

Die Dringlichkeit gibt für den Push-Dienst an, wie wichtig eine Nachricht für den Nutzer ist. Dies kann vom Push-Dienst verwendet werden, um die Akkulaufzeit eines Nutzergeräts zu schonen, da nur bei einem niedrigen Akkustand bei wichtigen Nachrichten geweckt wird.

Der Headerwert ist wie unten dargestellt definiert. Der Standardwert ist normal

Urgency: [very-low | low | normal | high]

Alles an einem Ort

Wenn Sie weitere Fragen dazu haben, können Sie jederzeit sehen, wie Bibliotheken Push-Nachrichten in der Organisation web-push-libs auslösen.

Wenn Sie eine verschlüsselte Nutzlast und die obigen Header haben, müssen Sie nur eine POST-Anfrage an endpoint in einem PushSubscription senden.

Was machen wir also mit der Antwort auf diese POST-Anfrage?

Antwort vom Push-Dienst

Nachdem Sie eine Anfrage an einen Push-Dienst gesendet haben, müssen Sie den Statuscode der Antwort überprüfen, da dieser Aufschluss darüber gibt, ob die Anfrage erfolgreich war oder nicht.

Statuscode Beschreibung
201 Erstellt Die Anfrage zum Senden einer Push-Nachricht wurde empfangen und akzeptiert.
429 Zu viele Anfragen: Das bedeutet, dass Ihr Anwendungsserver ein Ratenlimit mit einem Push-Dienst erreicht hat. Der Push-Dienst sollte einen „Repeat-After“-Header enthalten, der angibt, wie lange es dauert, bis eine weitere Anfrage gestellt werden kann.
400 Ungültige Anfrage. Das bedeutet im Allgemeinen, dass einer Ihrer Header ungültig oder nicht ordnungsgemäß formatiert ist.
404 Nicht gefunden Dies bedeutet, dass das Abo abgelaufen ist und nicht verwendet werden kann. Löschen Sie in diesem Fall „PushSubscription“ und warten Sie, bis der Client den Nutzer wieder abonniert.
410 Verschwunden. Das Abo ist nicht mehr gültig und sollte vom Anwendungsserver entfernt werden. Dies kann durch Aufrufen von „unsubscribe()“ für „PushSubscription“ reproduziert werden.
413 Die Nutzlast ist zu groß. Die Mindestnutzlast, die ein Push-Dienst unterstützen muss, beträgt 4.096 Byte (oder 4 KB).

Weitere Informationen

Code-Labs