commit 7f3efcc6563cab0c86447b9405548ddaaee2f294
parent 0ca707cca577868fc2e8a20384300937dad9581d
Author: Tom Ritter <tom@mozilla.com>
Date: Mon, 8 Dec 2025 16:31:03 +0000
Bug 1873716: Add logging for Font Fingerprinting r=timhuang
Differential Revision: https://phabricator.services.mozilla.com/D275348
Diffstat:
5 files changed, 51 insertions(+), 14 deletions(-)
diff --git a/dom/canvas/OffscreenCanvas.cpp b/dom/canvas/OffscreenCanvas.cpp
@@ -16,6 +16,7 @@
#include "WebGLChild.h"
#include "mozilla/Atomics.h"
#include "mozilla/CheckedInt.h"
+#include "mozilla/Logging.h"
#include "mozilla/dom/BlobImpl.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/OffscreenCanvasBinding.h"
@@ -33,6 +34,8 @@
namespace mozilla::dom {
+static mozilla::LazyLogModule gFingerprinterDetection("FingerprinterDetection");
+
OffscreenCanvasCloneData::OffscreenCanvasCloneData(
OffscreenCanvasDisplayHelper* aDisplay, uint32_t aWidth, uint32_t aHeight,
layers::LayersBackend aCompositorBackend, bool aNeutered, bool aIsWriteOnly,
@@ -638,6 +641,7 @@ FontVisibility OffscreenCanvas::GetFontVisibility() const {
}
void OffscreenCanvas::ReportBlockedFontFamily(const nsCString& aMsg) const {
+ MOZ_LOG(gFingerprinterDetection, mozilla::LogLevel::Info, ("%s", aMsg.get()));
if (Maybe<uint64_t> windowID = GetWindowID()) {
nsContentUtils::ReportToConsoleByWindowID(NS_ConvertUTF8toUTF16(aMsg),
nsIScriptError::warningFlag,
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
@@ -137,6 +137,7 @@
static mozilla::LazyLogModule sWorkerPrivateLog("WorkerPrivate");
static mozilla::LazyLogModule sWorkerTimeoutsLog("WorkerTimeouts");
+static mozilla::LazyLogModule gFingerprinterDetection("FingerprinterDetection");
mozilla::LogModule* WorkerLog() { return sWorkerPrivateLog; }
@@ -6773,6 +6774,7 @@ FontVisibility WorkerPrivate::GetFontVisibility() const {
}
void WorkerPrivate::ReportBlockedFontFamily(const nsCString& aMsg) const {
+ MOZ_LOG(gFingerprinterDetection, mozilla::LogLevel::Info, ("%s", aMsg.get()));
nsContentUtils::ReportToConsoleNonLocalized(NS_ConvertUTF8toUTF16(aMsg),
nsIScriptError::warningFlag,
"Security"_ns, GetDocument());
diff --git a/gfx/src/nsFontCache.cpp b/gfx/src/nsFontCache.cpp
@@ -17,6 +17,8 @@ using mozilla::services::GetObserverService;
NS_IMPL_ISUPPORTS(nsFontCache, nsIObserver)
+static mozilla::LazyLogModule gFingerprinterDetection("FingerprinterDetection");
+
// The Init and Destroy methods are necessary because it's not
// safe to call AddObserver from a constructor or RemoveObserver
// from a destructor. That should be fixed.
@@ -117,7 +119,14 @@ void nsFontCache::DetectFontFingerprinting(const nsFont& aFont) {
// number of cache misses in a short amount of time, which indicates the
// usage of an unreasonable amount of different fonts by the web page.
- if (mReportedProbableFingerprinting || aFont.family.families.list.IsEmpty()) {
+ if (aFont.family.families.list.IsEmpty()) {
+ return;
+ }
+
+ if (!MOZ_LOG_TEST(gFingerprinterDetection, mozilla::LogLevel::Info) &&
+ mReportedProbableFingerprinting) {
+ // We've already reported fingerprinting for this document, and logging
+ // isn't enabled, so skip the rest of the detection logic.
return;
}
@@ -143,20 +152,39 @@ void nsFontCache::DetectFontFingerprinting(const nsFont& aFont) {
uint16_t fontsMissedRecently = 0;
bool clearMissedFonts = false;
- for (auto iter = missedFonts->Iter(); !iter.Done(); iter.Next()) {
- if (now - kFingerprintingLastNSec <= iter.Data()) {
- if (++fontsMissedRecently > kFingerprintingCacheMissThreshold) {
- mContext->Document()->RecordFontFingerprinting();
- mReportedProbableFingerprinting = true;
- clearMissedFonts = true;
- break;
+ if (!mReportedProbableFingerprinting) {
+ for (auto iter = missedFonts->Iter(); !iter.Done(); iter.Next()) {
+ if (now - kFingerprintingLastNSec <= iter.Data()) {
+ if (++fontsMissedRecently > kFingerprintingCacheMissThreshold) {
+ mContext->Document()->RecordFontFingerprinting();
+ mReportedProbableFingerprinting = true;
+ clearMissedFonts = true;
+ break;
+ }
+ } else {
+ // Remove the old entries from missed cache list.
+ iter.Remove();
+ }
+ }
+ if (mReportedProbableFingerprinting) {
+ // We detected a font fingerprinter, so print out all the fonts they
+ // queries and missed
+ for (auto iter = missedFonts->Iter(); !iter.Done(); iter.Next()) {
+ MOZ_LOG(
+ gFingerprinterDetection, mozilla::LogLevel::Info,
+ ("Font Fingerprinting Tripped | Document %p | Font Family | %s",
+ mContext->Document(), NS_ConvertUTF16toUTF8(iter.Key()).get()));
}
- } else {
- // Remove the old entries from missed cache list.
- iter.Remove();
}
+ } else {
+ // I've already reported the font fingerprinting, but I want to report each
+ // additional font
+ MOZ_LOG(gFingerprinterDetection, mozilla::LogLevel::Info,
+ ("Font Fingerprinting Tripped | Document %p | Font Family | %s",
+ mContext->Document(), NS_ConvertUTF16toUTF8(key).get()));
}
- if (clearMissedFonts) {
+ if (!MOZ_LOG_TEST(gFingerprinterDetection, mozilla::LogLevel::Info) &&
+ clearMissedFonts) {
missedFonts->Clear();
}
}
diff --git a/gfx/src/nsFontCache.h b/gfx/src/nsFontCache.h
@@ -54,11 +54,11 @@ class nsFontCache final : public nsIObserver {
// Number of cache misses before we assume that a font fingerprinting attempt
// is being made.
- static constexpr int32_t kFingerprintingCacheMissThreshold = 20;
+ static constexpr int32_t kFingerprintingCacheMissThreshold = 10;
// We assume that fingerprinters will lookup a large number of fonts in a
// short amount of time.
static constexpr PRTime kFingerprintingLastNSec =
- PRTime(PR_USEC_PER_SEC) * 3; // 3 seconds
+ PRTime(PR_USEC_PER_SEC) * 6; // 6 seconds
static_assert(kFingerprintingCacheMissThreshold < kMaxCacheEntries);
diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp
@@ -113,6 +113,8 @@ using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace mozilla::layers;
+static LazyLogModule gFingerprinterDetection("FingerprinterDetection");
+
/**
* Layer UserData for ContainerLayers that want to be notified
* of local invalidations of them and their descendant layers.
@@ -3081,6 +3083,7 @@ bool nsPresContext::ShouldResistFingerprinting(RFPTarget aTarget) const {
}
void nsPresContext::ReportBlockedFontFamily(const nsCString& aMsg) const {
+ MOZ_LOG(gFingerprinterDetection, LogLevel::Info, ("%s", aMsg.get()));
nsContentUtils::ReportToConsoleNonLocalized(NS_ConvertUTF8toUTF16(aMsg),
nsIScriptError::warningFlag,
"Security"_ns, Document());