Dowiedz się, jak interfejs Local Font Access API umożliwia dostęp do lokalnie zainstalowanych czcionek użytkownika i uzyskiwanie szczegółowych informacji o nich
Bezpieczne czcionki internetowe
Jeśli zajmujesz się już od jakiegoś czasu tworzeniem stron internetowych, być może pamiętasz tak zwane bezpieczne czcionki internetowe.
Te czcionki są dostępne w prawie wszystkich instancjach najczęściej używanych systemów operacyjnych (Windows, macOS, najczęściej używanych dystrybucjach Linuksa, Android i iOS). Na początku XXI w. firma Microsoft była nawet inicjatorem inicjatywy TrueType Core Fonts for the Web, która umożliwiała bezpłatne pobieranie tych czcionek. Jej celem było to, aby zawsze, gdy użytkownik odwiedza witrynę, która je określa, widział strony dokładnie tak, jak zamierzył to projektant witryny. Tak, dotyczy to witryn z ustawionymi ustawieniami Comic Sans MS. Oto klasyczny zestaw czcionek internetowych (z ostatecznym substytutem dowolnej sans-serif
czcionki) może wyglądać tak:
body {
font-family: Helvetica, Arial, sans-serif;
}
czcionki internetowe,
Czasy, w których znaczenie miały czcionki bezpieczne w internecie, dawno minęły. Obecnie dostępne są czcionki internetowe. Niektóre z nich są nawet czcionkami zmiennymi, które możemy ulepszać, zmieniając wartości dla różnych wyświetlanych osi. Aby używać czcionek internetowych, na początku kodu CSS zadeklaruj blok @font-face
, który określa pliki czcionek do pobrania:
@font-face {
font-family: 'FlamboyantSansSerif';
src: url('flamboyant.woff2');
}
Następnie możesz używać niestandardowej czcionki internetowej, podając font-family
:
body {
font-family: 'FlamboyantSansSerif';
}
Czcionki lokalne jako wektor odcisku palca
Większość czcionek internetowych pochodzi z internetu. Ciekawostką jest to, że w deklaracji funkcji @font-face
występująca w niej właściwość src
oprócz funkcji url()
obsługuje też funkcję local()
. Dzięki temu czcionki niestandardowe są wczytywane (niespodzianka!) lokalnie. Jeśli zdarzy się, że użytkownik ma w swoim systemie operacyjnym zainstalowaną wersję FlamboyantSansSerif, zamiast pobierania zostanie użyta kopia lokalna:
@font-face {
font-family: 'FlamboyantSansSerif';
src: local('FlamboyantSansSerif'), url('flamboyant.woff2');
}
To podejście zapewnia przydatny mechanizm zastępczy, który może oszczędzać przepustowość. W internecie niestety nie ma rzeczy idealnych. Problem z funkcją local()
polega na tym, że może ona być nadużywana przy pobieraniu odcisków cyfrowych w przeglądarce. Okazuje się, że lista czcionek zainstalowanych przez użytkownika może być dość charakterystyczna. Wiele firm ma własne czcionki firmowe zainstalowane na laptopach pracowników. Na przykład firma Google ma font firmowy o nazwie Google Sans.
Atakujący może próbować określić, w jakiej firmie pracuje dana osoba, testując obecność dużej liczby znanych czcionek korporacyjnych, takich jak Google Sans. Osoba atakująca może spróbować renderować tekst zapisany w tych czcionkach na płótnie i zmierzyć glif. Jeśli glify pasują do znanego kształtu czcionki firmowej, atakujący trafia w dziesiątkę. Jeśli znaki nie pasują, atakujący wie, że użyto domyślnego czcionki zastępczej, ponieważ czcionka firmowa nie była zainstalowana. Szczegółowe informacje o tym i innych atakach polegających na tworzeniu odcisków palców przeglądarki znajdziesz w raporcie zespołu Laperdix et al.
Czcionki należące do firmy, można zidentyfikować nawet listę zainstalowanych czcionek. Sytuacja z tym wektorem ataku stała się tak zła, że zespół WebKit postanowił uwzględniać [na liście dostępnych czcionek] tylko czcionki internetowe i czcionki dołączone do systemu operacyjnego, a nie czcionki instalowane lokalnie przez użytkownika. (A tutaj jestem, z artykułem o przyznawaniu dostępu do czcionek lokalnych).
Interfejs Local Fonts Access API
Początek tego artykułu może wywołać u Ciebie negatywne emocje. Czy naprawdę nie możemy mieć ładnych rzeczy? Bez litości. Myślę, że możemy to zrobić i nie wszystko jest stracone. Najpierw jednak odpowiem na pytanie, które być może zadajesz sobie.
Dlaczego potrzebujemy interfejsu Local Font Access API, skoro istnieją czcionki internetowe?
W przeszłości trudno było znaleźć w internecie narzędzia do tworzenia grafik i projektów o profesjonalnej jakości. Jednym z problemów było to, że projektanci nie mogli korzystać z pełnej gamy profesjonalnie skonstruowanych i zaimplementowanych czcionek zainstalowanych lokalnie. Czcionki internetowe umożliwiają niektóre przypadki użycia dotyczące publikowania, ale nie umożliwiają dostępu programowego do kształtów wektorowych znaków i tablic czcionek używanych przez rastrowanie do renderowania kontur znaków. Nie ma też możliwości uzyskania dostępu do danych binarnych czcionki internetowej.
- Narzędzia do projektowania potrzebują dostępu do bajtów czcionek, aby móc stosować własne implementacje układu OpenType i umożliwiać narzędziom do projektowania łączenie się z poziomami niższego poziomu w celu wykonywania takich działań jak stosowanie filtrów wektorowych czy przekształcanie kształtów glifu.
- Deweloperzy mogą mieć starsze stosy czcionek do swoich aplikacji, które udostępniają w internecie. Aby korzystać z tych pakietów, zwykle trzeba mieć bezpośredni dostęp do danych czcionek, czego czcionki internetowe nie zapewniają.
- Niektóre czcionki mogą nie mieć licencji na dostarczanie przez Internet. Na przykład Linotype ma licencję na niektóre czcionki, która obejmuje tylko użytkowanie na komputerze.
Interfejs API Local Font Access to próba rozwiązania tych problemów. Składa się z 2 części:
- Interfejs font enumeration API umożliwiający użytkownikom przyznawanie dostępu do pełnego zestawu dostępnych czcionek systemowych.
- W ramach każdego wyniku zliczania możliwość żądania dostępu do kontenera SFNT niskiego poziomu (orientowanego na bajty), który zawiera pełne dane czcionki.
Obsługa przeglądarek
Jak korzystać z interfejsu Local Font Access API
Wykrywanie cech
Aby sprawdzić, czy interfejs Local Font Access API jest obsługiwany, wpisz:
if ('queryLocalFonts' in window) {
// The Local Font Access API is supported
}
Wyliczanie czcionek lokalnych
Aby uzyskać listę zainstalowanych lokalnie czcionek, musisz wywołać funkcję window.queryLocalFonts()
. Za pierwszym razem wywoła to prośbę o przyznanie uprawnień, którą użytkownik może zatwierdzić lub odrzucić. Jeśli użytkownik zatwierdzi zapytanie dotyczące czcionek lokalnych, przeglądarka zwróci tablicę z danymi czcionek, które możesz przetwarzać w pętli. Każda czcionka jest reprezentowana jako obiekt FontData
z właściwościami family
(np. "Comic Sans MS"
), fullName
(np. "Comic Sans MS"
), postscriptName
(np. "ComicSansMS"
) i style
(np. "Regular"
).
// 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);
}
Jeśli interesują Cię tylko niektóre czcionki, możesz je też przefiltrować na podstawie nazw PostScriptu, dodając parametr postscriptNames
.
const availableFonts = await window.queryLocalFonts({
postscriptNames: ['Verdana', 'Verdana-Bold', 'Verdana-Italic'],
});
Dostęp do danych SFNT
Pełny dostęp do SFNT jest dostępny za pomocą metody blob()
obiektu FontData
. SFNT to format pliku czcionki, który może zawierać inne czcionki, takie jak PostScript, TrueType, OpenType, czcionki w formacie Web Open Font Format (WOFF) i inne.
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);
}
Prezentacja
Interfejs Local Font Access API możesz zobaczyć w działaniu w poniżej przedstawionym demo. Koniecznie zapoznaj się też
z kodem źródłowym. Demonstracja przedstawia element niestandardowy o nazwie <font-select>
, który implementuje lokalny selektor czcionek.
Kwestie dotyczące prywatności
Zezwolenie "local-fonts"
umożliwia dostęp do powierzchni, która może być łatwo zidentyfikowana. Przeglądarki mogą jednak zwracać dowolne treści. Na przykład przeglądarki skoncentrowane na zapewnieniu anonimowości mogą udostępniać tylko zestaw domyślnych czcionek wbudowanych w przeglądarkę. Podobnie przeglądarki nie muszą podawać danych tabeli dokładnie w takiej postaci, w jakiej są widoczne na dysku.
W miarę możliwości interfejs Local Font Access API udostępnia tylko te informacje, które są niezbędne do obsługi wymienionych przypadków użycia. Interfejsy API systemu mogą wyświetlać listę zainstalowanych czcionek nie w kolejności losowej ani posortowanej, ale według kolejności instalacji. Zwracanie dokładnie takiej samej listy zainstalowanych czcionek, jaką podaje systemowy interfejs API, może ujawniać dodatkowe dane, które mogą być używane do tworzenia odcisków palców. Zachowanie tej kolejności nie pomaga w przypadku przypadków użycia, które chcemy umożliwić. W związku z tym ten interfejs API wymaga, aby zwracane dane były przed zwróceniem posortowane.
Zabezpieczenia i uprawnienia
Zespół Chrome zaprojektował i wdrżał interfejs API Local Font Access, korzystając z podstawowych zasad określonych w artykule Kontrolowanie dostępu do zaawansowanych funkcji platformy internetowej, w tym kontroli użytkownika, przejrzystości i ergonomiki.
Kontrola użytkownika
Dostęp do czcionek użytkownika jest całkowicie pod jego kontrolą i nie będzie dozwolony, chyba że użytkownik przyzna uprawnienia "local-fonts"
wymienione w rejestrze uprawnień.
Przejrzystość
Informacje o tym, czy witrynie przyznano dostęp do czcionek lokalnych użytkownika, będą widoczne w arkuszu informacji o witrynie.
Trwałość uprawnień
Uprawnienie "local-fonts"
będzie zachowane między wczytaniami strony. Możesz go anulować, korzystając z arkusza informacji o witrynie.
Prześlij opinię
Zespół Chrome chce poznać Twoje wrażenia z korzystania z interfejsu API dostępu do czcionek lokalnych.
Prześlij informacje o projektowaniu interfejsu API
Czy coś w interfejsie API nie działa zgodnie z oczekiwaniami? A może brakuje metod lub właściwości, których potrzebujesz do wdrożenia swojego pomysłu? Masz pytania lub uwagi dotyczące modelu bezpieczeństwa? Zgłoś problem ze specyfikacją w odpowiednim repozytorium GitHub lub dodaj swoje uwagi do istniejącego problemu.
Zgłaszanie problemów z implementacją
Czy znalazłeś/znalazłaś błąd w implementacji Chrome? A może implementacja różni się od specyfikacji?
Zgłoś błąd na stronie new.crbug.com. Podaj jak najwięcej szczegółów,
proste instrukcje odtwarzania i wpisz Blink>Storage>FontAccess
w polu Komponenty.
Glitch to świetne narzędzie do szybkiego i łatwego udostępniania informacji o powtarzających się problemach.
Pokaż informacje o pomocy dotyczącej interfejsu API
Czy planujesz korzystać z interfejsu Local Font Access API? Twoja publiczna pomoc pomaga zespołowi Chrome ustalać priorytety funkcji i pokazuje innym dostawcom przeglądarek, jak ważne jest wspieranie tych funkcji.
Wyślij tweeta na adres @ChromiumDev, używając hashtagu #LocalFontAccess
, i poinformuj nas, gdzie i jak go używasz.
Przydatne linki
- Wyjaśnienie
- Specyfikacja w wersji roboczej
- Błąd w Chromium dotyczący wyliczania czcionek
- Błąd Chromium dotyczący dostępu do tabeli czcionek
- Wpis w ChromeStatus
- repozytorium GitHub,
- Sprawdzanie tagów
- Poglądy Mozilla na temat standardów
Podziękowania
Specyfikację interfejsu Local Font Access API edytował Emil A. Eklund, Alex Russell, Joshua Bell i Olivier Yiptong. Ten artykuł został sprawdzony przez Joe Medley, Dominik Röttsches i Olivier Yiptong. Baner powitalny autorstwa Bretta Jordana na Unsplash.