Font Enumeration Fingerprinting
Background
Font enumeration fingerprinting is a basic fingerprint technique that started to appear in 2007. Early on this was done by not only JavaScript but Flash as well. With the decline of Flash the market has shifted towards JavaScript enumeration only.
How It Works
The installed fonts on a system vary over time based on software that has been installed in the system. The idea behind the JavaScript code is very simple. It creates a span element with a known font family, measure its width, set the target font family, and measure the width again. If there is a difference in the width, you will know that the font has rendered and is thus available. It then comes down to creating a list of fonts to check. The list provided balances comprehensiveness against speed, as checking each font takes time.
Entropy Estimate: 13.9 bits
Code
The JavaScript function below enumerates all forms and form fields.
Source Code
function fingerprint_fonts() {
"use strict";
var strOnError, style, fonts, count, template, fragment, divs, i, font, div, body, result, e;
strOnError = "Error";
style = null;
fonts = null;
font = null;
count = 0;
template = null;
divs = null;
e = null;
div = null;
body = null;
i = 0;
try {
style = "position: absolute; visibility: hidden; display: block !important";
fonts = ["Abadi MT Condensed Light", "Adobe Fangsong Std", "Adobe Hebrew", "Adobe Ming Std", "Agency FB", "Aharoni", "Andalus", "Angsana New", "AngsanaUPC", "Aparajita", "Arab", "Arabic Transparent", "Arabic Typesetting", "Arial Baltic", "Arial Black", "Arial CE", "Arial CYR", "Arial Greek", "Arial TUR", "Arial", "Batang", "BatangChe", "Bauhaus 93", "Bell MT", "Bitstream Vera Serif", "Bodoni MT", "Bookman Old Style", "Braggadocio", "Broadway", "Browallia New", "BrowalliaUPC", "Calibri Light", "Calibri", "Californian FB", "Cambria Math", "Cambria", "Candara", "Castellar", "Casual", "Centaur", "Century Gothic", "Chalkduster", "Colonna MT", "Comic Sans MS", "Consolas", "Constantia", "Copperplate Gothic Light", "Corbel", "Cordia New", "CordiaUPC", "Courier New Baltic", "Courier New CE", "Courier New CYR", "Courier New Greek", "Courier New TUR", "Courier New", "DFKai-SB", "DaunPenh", "David", "DejaVu LGC Sans Mono", "Desdemona", "DilleniaUPC", "DokChampa", "Dotum", "DotumChe", "Ebrima", "Engravers MT", "Eras Bold ITC", "Estrangelo Edessa", "EucrosiaUPC", "Euphemia", "Eurostile", "FangSong", "Forte", "FrankRuehl", "Franklin Gothic Heavy", "Franklin Gothic Medium", "FreesiaUPC", "French Script MT", "Gabriola", "Gautami", "Georgia", "Gigi", "Gisha", "Goudy Old Style", "Gulim", "GulimChe", "GungSeo", "Gungsuh", "GungsuhChe", "Haettenschweiler", "Harrington", "Hei S", "HeiT", "Heisei Kaku Gothic", "Hiragino Sans GB", "Impact", "Informal Roman", "IrisUPC", "Iskoola Pota", "JasmineUPC", "KacstOne", "KaiTi", "Kalinga", "Kartika", "Khmer UI", "Kino MT", "KodchiangUPC", "Kokila", "Kozuka Gothic Pr6N", "Lao UI", "Latha", "Leelawadee", "Levenim MT", "LilyUPC", "Lohit Gujarati", "Loma", "Lucida Bright", "Lucida Console", "Lucida Fax", "Lucida Sans Unicode", "MS Gothic", "MS Mincho", "MS PGothic", "MS PMincho", "MS Reference Sans Serif", "MS UI Gothic", "MV Boli", "Magneto", "Malgun Gothic", "Mangal", "Marlett", "Matura MT Script Capitals", "Meiryo UI", "Meiryo", "Menlo", "Microsoft Himalaya", "Microsoft JhengHei", "Microsoft New Tai Lue", "Microsoft PhagsPa", "Microsoft Sans Serif", "Microsoft Tai Le", "Microsoft Uighur", "Microsoft YaHei", "Microsoft Yi Baiti", "MingLiU", "MingLiU-ExtB", "MingLiU_HKSCS", "MingLiU_HKSCS-ExtB", "Miriam Fixed", "Miriam", "Mongolian Baiti", "MoolBoran", "NSimSun", "Narkisim", "News Gothic MT", "Niagara Solid", "Nyala", "PMingLiU", "PMingLiU-ExtB", "Palace Script MT", "Palatino Linotype", "Papyrus", "Perpetua", "Plantagenet Cherokee", "Playbill", "Prelude Bold", "Prelude Condensed Bold", "Prelude Condensed Medium", "Prelude Medium", "PreludeCompressedWGL Black", "PreludeCompressedWGL Bold", "PreludeCompressedWGL Light", "PreludeCompressedWGL Medium", "PreludeCondensedWGL Black", "PreludeCondensedWGL Bold", "PreludeCondensedWGL Light", "PreludeCondensedWGL Medium", "PreludeWGL Black", "PreludeWGL Bold", "PreludeWGL Light", "PreludeWGL Medium", "Raavi", "Rachana", "Rockwell", "Rod", "Sakkal Majalla", "Sawasdee", "Script MT Bold", "Segoe Print", "Segoe Script", "Segoe UI Light", "Segoe UI Semibold", "Segoe UI Symbol", "Segoe UI", "Shonar Bangla", "Showcard Gothic", "Shruti", "SimHei", "SimSun", "SimSun-ExtB", "Simplified Arabic Fixed", "Simplified Arabic", "Snap ITC", "Sylfaen", "Symbol", "Tahoma", "Times New Roman Baltic", "Times New Roman CE", "Times New Roman CYR", "Times New Roman Greek", "Times New Roman TUR", "Times New Roman", "TlwgMono", "Traditional Arabic", "Trebuchet MS", "Tunga", "Tw Cen MT Condensed Extra Bold", "Ubuntu", "Umpush", "Univers", "Utopia", "Utsaah", "Vani", "Verdana", "Vijaya", "Vladimir Script", "Vrinda", "Webdings", "Wide Latin", "Wingdings"];
count = fonts.length;
template = '<b style="display:inline !important; width:auto !important; font:normal 10px/1 \'X\',sans-serif !important">wwmmllii</b>' + '<b style="display:inline !important; width:auto !important; font:normal 10px/1 \'X\',monospace !important">wwmmllii</b>';
fragment = document.createDocumentFragment();
divs = [];
for (i = 0; i < count; i = i + 1) {
font = fonts[i];
div = document.createElement('div');
font = font.replace(/['"<>]/g, '');
div.innerHTML = template.replace(/X/g, font);
div.style.cssText = style;
fragment.appendChild(div);
divs.push(div);
}
body = document.body;
body.insertBefore(fragment, body.firstChild);
result = [];
for (i = 0; i < count; i = i + 1) {
e = divs[i].getElementsByTagName('b');
if (e[0].offsetWidth === e[1].offsetWidth) {
result.push(fonts[i]);
}
}
// do not combine these two loops, remove child will cause reflow
// and induce severe performance hit
for (i = 0; i < count; i = i + 1) {
body.removeChild(divs[i]);
}
return result.join('|');
} catch (err) {
return strOnError;
}
}
Validation
Unlike other code on the Internet we do everything possible to verify our code for you. In order to minimize problems and maximize compatibility this code has been verified with JSLint and has been extensively tested with over 1100 OS/Browser combinations using BrowserStack.
Reference
Listing all fonts on a user's computer (Apr 08, 2005). In TEK-TIPS.com. Retrieved September 09, 2017, from http://www.tek-tips.com/faqs.cfm?fid=5799
JavaScript/CSS Font Detector (Mar 15, 2007). In lalit.lab. Retrieved September 09, 2017, from http://www.lalit.org/lab/javascript-css-font-detect/
Detecting System Fonts without Flash (Jul 30, 2015). In BramStein.com. Retrieved September 09, 2017, from https://www.bramstein.com/writing/detecting-system-fonts-without-flash.html