Start · Sprachen · JavaScript · Referenz · WebTransport.exportKeyingMaterial()

WebTransport.exportKeyingMaterial()

Methode

Leitet über den TLS-Exporter der zugrunde liegenden QUIC/HTTP/3-Verbindung Schlüsselmaterial ab und liefert es als <code>Promise&lt;ArrayBuffer&gt;</code>.

seit JavaScript Experimentell: eingeschränkte Browser-Unterstützun Kategorie: webapi

Signatur

WebTransport.prototype.exportKeyingMaterial(label, context)

Beschreibung

Mit exportKeyingMaterial() kann eine Anwendung aus der TLS-Sitzung einer bestehenden WebTransport-Verbindung eigenes Schlüsselmaterial ableiten. Die Methode nutzt den TLS Keying Material Exporter nach RFC 5705 bzw. RFC 8446 (Abschnitt 7.5). Client und Server bekommen bei gleichem label und gleichem context identische Bytes. Ein Dritter, der nicht Endpunkt derselben TLS-Sitzung ist, kann diese Bytes nicht berechnen.

Typische Einsatzgebiete:

  • Channel Binding: Ein Authentifizierungs-Token oder eine Signatur wird an genau diese Verbindung gebunden. So lässt sich ein abgefangenes Token nicht über eine andere Verbindung wiederverwenden.
  • Ende-zu-Ende-Schlüssel ableiten: Das Material dient als Eingabe für HKDF oder crypto.subtle.importKey(), etwa für zusätzliche Verschlüsselung auf Anwendungsebene.
  • Sitzungsabgleich: Client und Server vergleichen einen Fingerabdruck und erkennen so einen Man-in-the-Middle, der die TLS-Verbindung terminiert.

Die Methode ist nur sinnvoll, nachdem die Verbindung aufgebaut ist, also nach await transport.ready. Das label sollte anwendungsspezifisch und eindeutig sein, damit sich verschiedene Verwendungszwecke nicht in die Quere kommen. Über context lässt sich optional weitere Information einmischen, zum Beispiel eine Benutzer-ID oder eine Nonce.

Parameter

Name Typ Default Beschreibung
$label Pflicht BufferSource (ArrayBuffer | TypedArray | DataView) Anwendungsspezifisches Label für den TLS-Exporter, höchstens 255 Byte. Meist ein per TextEncoder kodierter String wie "EXPORTER-my-app-binding".
$context BufferSource leerer Kontext Optionaler Kontextwert (höchstens 255 Byte), der in die Ableitung einfließt. Unterschiedliche Kontexte ergeben unterschiedliches Schlüsselmaterial.

Rückgabewert

Typ
Promise<ArrayBuffer>
Beschreibung
Ein Promise, das mit einem ArrayBuffer voller abgeleiteter Bytes erfüllt wird. Das Promise wird abgelehnt, wenn der Transport geschlossen oder fehlgeschlagen ist, wenn label oder context zu lang sind oder wenn der Export nicht unterstützt wird.

Beispiele

Schlüsselmaterial exportieren und als Hex ausgeben

const transport = new WebTransport('https://example.com:4433/wt');
await transport.ready;

const label = new TextEncoder().encode('EXPORTER-demo');
const material = await transport.exportKeyingMaterial(label);

const hex = [...new Uint8Array(material)]
  .map((b) => b.toString(16).padStart(2, '0'))
  .join('');
console.log(material.byteLength, hex);
32 "9f1c…" (Länge und Inhalt hängen von der Sitzung ab)

Channel Binding: Token an die Verbindung binden

const connectAuthenticated = async (url, token) => {
  const transport = new WebTransport(url);
  await transport.ready;

  const enc = new TextEncoder();
  const binding = await transport.exportKeyingMaterial(
    enc.encode('EXPORTER-my-app-auth'),
    enc.encode(token)
  );

  // Binding-Wert zusammen mit dem Token an den Server senden
  const stream = await transport.createBidirectionalStream();
  const writer = stream.writable.getWriter();
  const payload = JSON.stringify({
    token,
    binding: btoa(String.fromCharCode(...new Uint8Array(binding)))
  });
  await writer.write(enc.encode(payload));
  await writer.close();
  return transport;
};

const transport = await connectAuthenticated('https://example.com:4433/wt', 'abc123');

AES-Schlüssel für Ende-zu-Ende-Verschlüsselung ableiten

const transport = new WebTransport('https://example.com:4433/wt');
await transport.ready;

const ikm = await transport.exportKeyingMaterial(
  new TextEncoder().encode('EXPORTER-my-app-e2e')
);

const baseKey = await crypto.subtle.importKey('raw', ikm, 'HKDF', false, ['deriveKey']);
const aesKey = await crypto.subtle.deriveKey(
  { name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(16), info: new TextEncoder().encode('chat-v1') },
  baseKey,
  { name: 'AES-GCM', length: 256 },
  false,
  ['encrypt', 'decrypt']
);
console.log(aesKey.algorithm);
{ name: "AES-GCM", length: 256 }

// Wichtig · Fallstricke

  • Experimentell: Die Methode steht noch nicht in allen Browsern zur Verfügung, Safari unterstützt WebTransport je nach Version gar nicht. Deshalb vorher prüfen, etwa mit typeof WebTransport !== 'undefined' && 'exportKeyingMaterial' in WebTransport.prototype, und eine Ausweichlösung vorsehen.
  • Nur in sicheren Kontexten (HTTPS) verfügbar, außerdem in Web Workers.
  • Aufruf erst nach await transport.ready. Bei geschlossenem oder fehlgeschlagenem Transport wird das Promise abgelehnt.
  • label und context dürfen jeweils höchstens 255 Byte lang sein, sonst wird das Promise abgelehnt.
  • Sicherheit: Das exportierte Material ist geheim. Es darf nicht protokolliert, nicht im Klartext an Dritte weitergegeben und nicht unverändert als Schlüssel für mehrere Zwecke verwendet werden. Für jeden Zweck ein eigenes Label wählen und den Wert per HKDF weiterverarbeiten.
  • Beim Verbindungsaufbau mit serverCertificateHashes (selbst signierte Zertifikate) belegt Channel Binding nur, dass Client und Server dieselbe Sitzung teilen, nicht aber die Identität des Servers.
  • Pro Sitzung ergibt sich ein anderes Material. Nach einem Neuaufbau der Verbindung muss es neu abgeleitet werden.