Start · Sprachen · JavaScript · Referenz · RTCCertificateStats.base64Certificate

RTCCertificateStats.base64Certificate

Eigenschaft

String mit der Base64-Darstellung des DER-codierten Zertifikats, das in einer WebRTC-Verbindung für DTLS verwendet wird.

seit JavaScript Baseline 2023: Chrome, Edge, Firefox, Safari (WebR Kategorie: webapi

Signatur

RTCCertificateStats.base64Certificate

Beschreibung

Die Eigenschaft base64Certificate des Wörterbuchs RTCCertificateStats enthält das vollständige X.509-Zertifikat als Base64-codierten String im DER-Format. Das entspricht dem Inhalt einer PEM-Datei ohne die Zeilen -----BEGIN CERTIFICATE----- und -----END CERTIFICATE----- und ohne Zeilenumbrüche.

Solche Statistikobjekte mit type === "certificate" erhält man über RTCPeerConnection.getStats(). Pro Verbindung gibt es in der Regel zwei davon: eines für das lokale und eines für das entfernte DTLS-Zertifikat. Welches welches ist, erkennt man über RTCTransportStats.localCertificateId und remoteCertificateId.

Nützlich ist die Eigenschaft beim Debuggen und Protokollieren, etwa um das Zertifikat mit Werkzeugen wie OpenSSL zu untersuchen. Außerdem kann man damit prüfen, ob der Fingerabdruck (fingerprint) wirklich zum ausgehandelten Zertifikat passt. Ist die Zertifikatskette länger, verweist issuerCertificateId auf das Statistikobjekt des ausstellenden Zertifikats.

Rückgabewert

Typ
string
Beschreibung
Base64-codierte DER-Darstellung des Zertifikats, ohne PEM-Kopf- und Fußzeile und ohne Zeilenumbrüche.

Beispiele

Alle Zertifikate einer Verbindung auslesen

const logCertificates = async (pc) => {
  const stats = await pc.getStats();
  stats.forEach((report) => {
    if (report.type === "certificate") {
      console.log(report.id, report.fingerprintAlgorithm, report.fingerprint);
      console.log("Länge (Base64):", report.base64Certificate.length);
    }
  });
};

// Aufruf, sobald die DTLS-Verbindung steht
pc.addEventListener("connectionstatechange", () => {
  if (pc.connectionState === "connected") logCertificates(pc);
});
RTCCertificate_AB:CD:... sha-256 AB:CD:EF:... Länge (Base64): 540

Lokales und entferntes Zertifikat über den Transport zuordnen

const getDtlsCertificates = async (pc) => {
  const stats = await pc.getStats();
  const transport = [...stats.values()].find((r) => r.type === "transport");
  if (!transport) return null;
  return {
    local: stats.get(transport.localCertificateId)?.base64Certificate,
    remote: stats.get(transport.remoteCertificateId)?.base64Certificate
  };
};

const certs = await getDtlsCertificates(pc);
console.log(certs?.remote?.slice(0, 20));
MIIBFjCBvaADAgECAgkA

Zertifikat als PEM-Datei exportieren

const toPem = (base64) => {
  const lines = base64.match(/.{1,64}/g).join("\n");
  return `-----BEGIN CERTIFICATE-----\n${lines}\n-----END CERTIFICATE-----\n`;
};

const downloadPem = (base64, filename = "remote.pem") => {
  const blob = new Blob([toPem(base64)], { type: "application/x-pem-file" });
  const a = document.createElement("a");
  a.href = URL.createObjectURL(blob);
  a.download = filename;
  a.click();
  URL.revokeObjectURL(a.href);
};

const { remote } = await getDtlsCertificates(pc);
if (remote) downloadPem(remote);

SHA-256-Fingerabdruck selbst berechnen und vergleichen

const fingerprintOf = async (base64) => {
  const der = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
  const hash = await crypto.subtle.digest("SHA-256", der);
  return [...new Uint8Array(hash)]
    .map((b) => b.toString(16).padStart(2, "0").toUpperCase())
    .join(":");
};

const stats = await pc.getStats();
for (const r of stats.values()) {
  if (r.type === "certificate" && r.fingerprintAlgorithm === "sha-256") {
    const ok = (await fingerprintOf(r.base64Certificate)) === r.fingerprint.toUpperCase();
    console.log(r.id, ok ? "Fingerabdruck stimmt" : "Abweichung!");
  }
}
RTCCertificate_... Fingerabdruck stimmt

// Wichtig · Fallstricke

  • Nur nach dem DTLS-Handshake verfügbar: Vor dem Verbindungsaufbau enthält getStats() keine Einträge vom Typ "certificate". Frage die Werte deshalb erst ab, wenn connectionState === "connected" ist.
  • Kein PEM: Der String hat keine Kopf- und Fußzeile und keine Zeilenumbrüche. Für OpenSSL & Co. musst du ihn selbst in 64-Zeichen-Zeilen umbrechen und die PEM-Kopf- und Fußzeile ergänzen.
  • Selbstsignierte Zertifikate: WebRTC-Zertifikate sind meist kurzlebig und selbst ausgestellt. Die Sicherheit beruht auf dem Fingerabdruck, der über die Signalisierung (SDP) übertragen wird, nicht auf einer Zertifizierungsstelle.
  • Datenschutz: Wenn du Zertifikate mit RTCPeerConnection.generateCertificate() erzeugst und dauerhaft speicherst, lässt sich ein Nutzer darüber wiedererkennen. Überlege genau, ob du die Werte an einen Server protokollierst.
  • Kompatibilität: Wird in allen aktuellen Browsern mit WebRTC-Statistik-API unterstützt. Ältere Chrome-Versionen haben einen anderen, veralteten Statistik-Stil mit Rückruffunktion verwendet. Nutze immer die Promise-Variante von getStats().