Signatur
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
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);
});
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));
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!");
}
}
// 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, wennconnectionState === "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().