Hier erfahren Sie, wie Sie mit der Local Font Access API auf die lokal installierten Schriftarten des Nutzers zugreifen und detaillierte Informationen dazu abrufen können.
Websichere Schriftarten
Wenn Sie schon länger Webentwickler sind, erinnern Sie sich vielleicht noch an die sogenannten websicheren Schriftarten.
Diese Schriftarten sind auf fast allen Instanzen der am häufigsten verwendeten Betriebssysteme (Windows, macOS, die gängigsten Linux-Distributionen, Android und iOS) verfügbar. Anfang der 2000er Jahre startete Microsoft sogar eine Initiative namens TrueType Core Fonts for the Web, die diese Schriftarten kostenlos zum Download anbot, damit „Websites, die diese Schriftarten verwenden, genau so angezeigt werden, wie es der Webdesigner vorgesehen hat“. Ja, das gilt auch für Websites, auf denen Comic Sans MS verwendet wird. Ein klassischer websicherer Schriftarten-Stack (mit dem ultimativen Fallback auf die Schriftart sans-serif
) könnte so aussehen:
body {
font-family: Helvetica, Arial, sans-serif;
}
Web fonts
Die Zeiten, in denen websichere Schriftarten wirklich wichtig waren, sind längst vorbei. Heute haben wir Webfonts, von denen einige sogar variable Schriftarten sind, die wir durch Ändern der Werte für die verschiedenen verfügbaren Achsen weiter anpassen können. Sie können Webfonts verwenden, indem Sie am Anfang des CSS einen @font-face
-Block deklarieren, in dem die herunterzuladenden Schriftartdateien angegeben werden:
@font-face {
font-family: 'FlamboyantSansSerif';
src: url('flamboyant.woff2');
}
Anschließend können Sie die benutzerdefinierte Web-Schriftart wie gewohnt mit font-family
verwenden:
body {
font-family: 'FlamboyantSansSerif';
}
Lokale Schriftarten als Fingerprint-Vektor
Die meisten Webfonts stammen aus dem Web. Interessant ist jedoch, dass die Property src
in der @font-face
-Deklaration neben der Funktion url()
auch die Funktion local()
akzeptiert. So können benutzerdefinierte Schriftarten lokal geladen werden. Wenn der Nutzer FlamboyantSansSerif auf seinem Betriebssystem installiert hat, wird die lokale Kopie verwendet, anstatt die Schriftart herunterzuladen:
@font-face {
font-family: 'FlamboyantSansSerif';
src: local('FlamboyantSansSerif'), url('flamboyant.woff2');
}
Dieser Ansatz bietet einen guten Fallback-Mechanismus, der möglicherweise Bandbreite spart. Im Internet können wir leider nicht immer freundlich zueinander sein. Das Problem mit der local()
-Funktion besteht darin, dass sie für Browser-Fingerprinting missbraucht werden kann. Die Liste der vom Nutzer installierten Schriftarten kann ziemlich aufschlussreich sein. Viele Unternehmen haben eigene Unternehmensschriftarten, die auf den Laptops der Mitarbeiter installiert sind. Google hat beispielsweise eine Unternehmensschriftart namens Google Sans.
Ein Angreifer kann versuchen, herauszufinden, für welches Unternehmen jemand arbeitet, indem er die Existenz einer großen Anzahl bekannter Unternehmensschriftarten wie Google Sans testet. Der Angreifer würde versuchen, Text, der in diesen Schriftarten festgelegt ist, auf einem Canvas zu rendern und die Glyphen zu messen. Wenn die Glyphen der bekannten Form der Unternehmensschrift entsprechen, hat der Angreifer einen Treffer. Wenn die Glyphen nicht übereinstimmen, weiß der Angreifer, dass eine Standardersatzschriftart verwendet wurde, da die Unternehmensschriftart nicht installiert war. Ausführliche Informationen zu dieser und anderen Browser-Fingerprinting-Angriffen finden Sie im Übersichtsartikel von Laperdix et al.
Abgesehen von Unternehmensschriftarten kann schon die Liste der installierten Schriftarten identifizierbar sein. Die Situation mit diesem Angriffsvektor hat sich so verschlechtert, dass das WebKit-Team vor Kurzem beschlossen hat, „nur Webfonts und Fonts, die mit dem Betriebssystem geliefert werden, aber keine lokal vom Nutzer installierten Fonts in die Liste der verfügbaren Fonts aufzunehmen“. (Und hier bin ich mit einem Artikel zum Gewähren des Zugriffs auf lokal gespeicherte Schriftarten.)
Local Font Access API
Der Anfang dieses Artikels hat Sie vielleicht in eine negative Stimmung versetzt. Können wir wirklich keine schönen Dinge haben? Kein Grund zur Sorge. Wir glauben, dass wir das schaffen können, und vielleicht ist noch nicht alles verloren. Zuerst möchte ich aber eine Frage beantworten, die Sie sich vielleicht stellen.
Warum benötigen wir die Local Font Access API, wenn es Webfonts gibt?
Professionelle Design- und Grafiktools waren im Web bisher schwer zu realisieren. Ein Problem war bisher, dass Designer nicht auf die gesamte Vielfalt professionell erstellter und mit Hinweisen versehener Schriftarten zugreifen und diese verwenden konnten, die sie lokal installiert haben. Webfonts ermöglichen einige Publishing-Anwendungsfälle, aber keinen programmatischen Zugriff auf die Vektorglyphenformen und Schriftarttabellen, die von Rasterizern zum Rendern der Glyphenkonturen verwendet werden. Es gibt auch keine Möglichkeit, auf die Binärdaten einer Web-Schriftart zuzugreifen.
- Designtools benötigen Zugriff auf Schriftart-Bytes, um ihre eigene OpenType-Layoutimplementierung durchzuführen und Designtools auf niedrigeren Ebenen einzubinden, z. B. für Aktionen wie das Anwenden von Vektorfiltern oder Transformationen auf die Glyphenformen.
- Entwickler haben möglicherweise ältere Schrift-Stacks für ihre Anwendungen, die sie ins Web bringen. Für die Verwendung dieser Stacks ist in der Regel direkter Zugriff auf Schriftartdaten erforderlich, was bei Webfonts nicht möglich ist.
- Einige Schriftarten sind möglicherweise nicht für die Bereitstellung über das Web lizenziert. Linotype hat beispielsweise eine Lizenz für einige Schriftarten, die nur die Desktop-Nutzung umfasst.
Die Local Font Access API soll diese Herausforderungen lösen. Sie besteht aus zwei Teilen:
- Eine API zur Schriftartaufzählung, mit der Nutzer Zugriff auf alle verfügbaren Systemschriftarten gewähren können.
- Aus jedem Enumerierungsergebnis kann der Zugriff auf den SFNT-Container auf niedriger Ebene (byteorientiert) angefordert werden, der die vollständigen Schriftartdaten enthält.
Unterstützte Browser
Local Font Access API verwenden
Funktionserkennung
So prüfen Sie, ob die Local Font Access API unterstützt wird:
if ('queryLocalFonts' in window) {
// The Local Font Access API is supported
}
Lokale Schriftarten auflisten
Wenn Sie eine Liste der lokal installierten Schriftarten abrufen möchten, müssen Sie window.queryLocalFonts()
aufrufen. Beim ersten Mal wird eine Berechtigungsaufforderung ausgelöst, die der Nutzer genehmigen oder ablehnen kann. Wenn der Nutzer die Abfrage seiner lokalen Schriftarten genehmigt, gibt der Browser ein Array mit Schriftartdaten zurück, das Sie durchlaufen können. Jede Schriftart wird als FontData
-Objekt mit den Attributen family
(z. B. "Comic Sans MS"
), fullName
(z. B. "Comic Sans MS"
), postscriptName
(z. B. "ComicSansMS"
) und style
(z. B. "Regular"
) dargestellt.
// Query for all available fonts and log metadata.
try {
const availableFonts = await window.queryLocalFonts();
for (const fontData of availableFonts) {
console.log(fontData.postscriptName);
console.log(fontData.fullName);
console.log(fontData.family);
console.log(fontData.style);
}
} catch (err) {
console.error(err.name, err.message);
}
Wenn Sie nur an einer Teilmenge von Schriftarten interessiert sind, können Sie sie auch anhand der PostScript-Namen filtern, indem Sie einen postscriptNames
-Parameter hinzufügen.
const availableFonts = await window.queryLocalFonts({
postscriptNames: ['Verdana', 'Verdana-Bold', 'Verdana-Italic'],
});
Auf SFNT-Daten zugreifen
Der vollständige SFNT-Zugriff ist über die Methode blob()
des FontData
-Objekts verfügbar. SFNT ist ein Schriftartdateiformat, das andere Schriftarten wie PostScript, TrueType, OpenType, Web Open Font Format (WOFF) und andere enthalten kann.
try {
const availableFonts = await window.queryLocalFonts({
postscriptNames: ['ComicSansMS'],
});
for (const fontData of availableFonts) {
// `blob()` returns a Blob containing valid and complete
// SFNT-wrapped font data.
const sfnt = await fontData.blob();
// Slice out only the bytes we need: the first 4 bytes are the SFNT
// version info.
// Spec: https://docs.microsoft.com/en-us/typography/opentype/spec/otff#organization-of-an-opentype-font
const sfntVersion = await sfnt.slice(0, 4).text();
let outlineFormat = 'UNKNOWN';
switch (sfntVersion) {
case '\x00\x01\x00\x00':
case 'true':
case 'typ1':
outlineFormat = 'truetype';
break;
case 'OTTO':
outlineFormat = 'cff';
break;
}
console.log('Outline format:', outlineFormat);
}
} catch (err) {
console.error(err.name, err.message);
}
Demo
In der Demo unten können Sie die Local Font Access API in Aktion sehen. Sehen Sie sich auch den Quellcode an. In der Demo wird ein benutzerdefiniertes Element namens <font-select>
gezeigt, das eine lokale Schriftartauswahl implementiert.
Datenschutz
Die Berechtigung "local-fonts"
scheint eine Oberfläche zu bieten, die sich sehr gut für Fingerprinting eignet. Browser können jedoch beliebige Werte zurückgeben. Anonymitätsorientierte Browser bieten beispielsweise möglicherweise nur eine Reihe von Standard-Schriftarten an, die im Browser integriert sind. Ebenso müssen Browser Tabellendaten nicht genau so bereitstellen, wie sie auf der Festplatte gespeichert sind.
Die Local Font Access API ist so konzipiert, dass sie nur die Informationen offenlegt, die für die genannten Anwendungsfälle erforderlich sind. System-APIs können eine Liste der installierten Schriftarten in der Reihenfolge der Schriftartinstallation zurückgeben, nicht in zufälliger oder sortierter Reihenfolge. Wenn genau die Liste der installierten Schriftarten zurückgegeben wird, die von einer solchen System-API bereitgestellt wird, können zusätzliche Daten offengelegt werden, die für das Fingerprinting verwendet werden können. Die Beibehaltung dieser Reihenfolge unterstützt nicht die Anwendungsfälle, die wir ermöglichen möchten. Daher muss diese API die zurückgegebenen Daten sortieren, bevor sie zurückgegeben werden.
Sicherheit und Berechtigungen
Das Chrome-Team hat die Local Font Access API unter Berücksichtigung der in Controlling Access to Powerful Web Platform Features definierten Grundsätze entwickelt und implementiert, darunter Nutzerkontrolle, Transparenz und Ergonomie.
Kontrolle durch Nutzer
Der Zugriff auf die Schriftarten eines Nutzers liegt vollständig in seiner Hand und ist nur zulässig, wenn die Berechtigung "local-fonts"
, wie in der Berechtigungsregistrierung aufgeführt, gewährt wird.
Transparenz
Ob einer Website Zugriff auf die lokalen Schriftarten des Nutzers gewährt wurde, ist im Informationsblatt zur Website zu sehen.
Beibehalten von Berechtigungen
Die Berechtigung "local-fonts"
bleibt auch nach dem Neuladen der Seite erhalten. Sie kann über das Tab Websiteinformationen widerrufen werden.
Feedback
Das Chrome-Team möchte mehr über Ihre Erfahrungen mit der Local Font Access API erfahren.
Informationen zum API-Design
Gibt es etwas an der API, das nicht wie erwartet funktioniert? Oder fehlen Methoden oder Eigenschaften, die Sie für die Umsetzung Ihrer Idee benötigen? Haben Sie Fragen oder Anmerkungen zum Sicherheitsmodell? Melden Sie ein Spezifikationsproblem im entsprechenden GitHub-Repository oder fügen Sie Ihre Gedanken zu einem bestehenden Problem hinzu.
Problem mit der Implementierung melden
Haben Sie einen Fehler in der Chrome-Implementierung gefunden? Oder weicht die Implementierung von der Spezifikation ab?
Melden Sie einen Fehler unter new.crbug.com. Geben Sie dabei so viele Details wie möglich an, fügen Sie eine einfache Anleitung zur Reproduktion hinzu und geben Sie Blink>Storage>FontAccess
in das Feld Components (Komponenten) ein.
API-Support zeigen
Planen Sie, die Local Font Access API zu verwenden? Ihre öffentliche Unterstützung hilft dem Chrome-Team, Funktionen zu priorisieren, und zeigt anderen Browseranbietern, wie wichtig es ist, sie zu unterstützen.
Senden Sie einen Tweet an @ChromiumDev mit dem Hashtag #LocalFontAccess
und teilen Sie uns mit, wo und wie Sie die Funktion verwenden.
Nützliche Links
- Erläuterung
- Spezifikationsentwurf
- Chromium-Fehler für die Schriftartaufzählung
- Chromium-Fehler für den Zugriff auf Schriftarttabellen
- ChromeStatus-Eintrag
- GitHub-Repository
- TAG-Überprüfung
- Mozilla-Standards
Danksagungen
Die API-Spezifikation für den Zugriff auf lokal gespeicherte Schriftarten wurde von Emil A. bearbeitet. Eklund, Alex Russell, Joshua Bell und Olivier Yiptong. Dieser Artikel wurde von Joe Medley, Dominik Röttsches und Olivier Yiptong überprüft. Hero-Image von Brett Jordan auf Unsplash.