696 lines
29 KiB
Diff
696 lines
29 KiB
Diff
From: csagan5 <32685696+csagan5@users.noreply.github.com>
|
|
Date: Fri, 30 Mar 2018 10:09:03 +0200
|
|
Subject: Multiple fingerprinting mitigations
|
|
|
|
1. getClientRects, getBoundingClientRect, measureText: add fingerprinting mitigation
|
|
|
|
Scale the result of Range::getClientRects, Element::getBoundingClientRect and
|
|
Canvas::measureText by a random +/-3/1000000th of the original value for each
|
|
float in the returned Rect/Quad.
|
|
|
|
It contains improvements from ungoogled-chromium which add two flags:
|
|
1. --fingerprinting-client-rects-noise to enable fingerprinting deception for Range::getClientRects and Element::getBoundingClientRect
|
|
2. --fingerprinting-canvas-measuretext-noise to enable fingerprinting deception for Canvas::measureText
|
|
|
|
2. Canvas: fingerprinting mitigations for image data and webGL
|
|
|
|
Disable webGL renderer info and modify the color data returned by ToBlob,
|
|
ToDataURL and getImageData so that it will contain randomly manipulated
|
|
pixels (maximum 20) that slightly change the color of the R,G,B components
|
|
without a visible effect.
|
|
|
|
Credits to Slaviro (https://github.com/Slaviro) for coming up with a better
|
|
approach to change color components.
|
|
|
|
Added flag --fingerprinting-canvas-image-data-noise to disable Canvas image data fingerprinting deception
|
|
---
|
|
chrome/browser/BUILD.gn | 1 +
|
|
chrome/browser/about_flags.cc | 13 ++
|
|
content/browser/BUILD.gn | 1 +
|
|
.../renderer_host/render_process_host_impl.cc | 4 +
|
|
content/child/BUILD.gn | 1 +
|
|
content/child/runtime_features.cc | 9 +
|
|
.../public/platform/web_runtime_features.h | 3 +
|
|
.../blink/renderer/core/dom/document.cc | 18 ++
|
|
.../blink/renderer/core/dom/document.h | 7 +
|
|
.../blink/renderer/core/dom/element.cc | 8 +
|
|
third_party/blink/renderer/core/dom/range.cc | 12 +-
|
|
.../renderer/core/html/canvas/text_metrics.cc | 18 ++
|
|
.../renderer/core/html/canvas/text_metrics.h | 2 +
|
|
.../canvas2d/canvas_rendering_context_2d.cc | 8 +-
|
|
third_party/blink/renderer/platform/BUILD.gn | 5 +-
|
|
.../platform/exported/web_runtime_features.cc | 12 ++
|
|
.../platform/graphics/image_data_buffer.cc | 7 +
|
|
.../platform/graphics/static_bitmap_image.cc | 160 ++++++++++++++++++
|
|
.../platform/graphics/static_bitmap_image.h | 2 +
|
|
.../platform/runtime_enabled_features.json5 | 9 +
|
|
third_party/ungoogled/BUILD.gn | 10 ++
|
|
third_party/ungoogled/ungoogled_switches.cc | 18 ++
|
|
third_party/ungoogled/ungoogled_switches.h | 18 ++
|
|
23 files changed, 343 insertions(+), 3 deletions(-)
|
|
create mode 100644 third_party/ungoogled/BUILD.gn
|
|
create mode 100644 third_party/ungoogled/ungoogled_switches.cc
|
|
create mode 100644 third_party/ungoogled/ungoogled_switches.h
|
|
|
|
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
|
|
--- a/chrome/browser/BUILD.gn
|
|
+++ b/chrome/browser/BUILD.gn
|
|
@@ -2244,6 +2244,7 @@ static_library("browser") {
|
|
"//services/device/public/cpp:device_features",
|
|
"//services/device/public/cpp/serial:switches",
|
|
"//services/device/public/cpp/usb",
|
|
+ "//third_party/ungoogled:switches",
|
|
"//services/device/public/mojom",
|
|
"//services/device/public/mojom:usb",
|
|
"//services/image_annotation:service",
|
|
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
|
|
--- a/chrome/browser/about_flags.cc
|
|
+++ b/chrome/browser/about_flags.cc
|
|
@@ -168,6 +168,7 @@
|
|
#include "services/media_session/public/cpp/features.h"
|
|
#include "services/network/public/cpp/features.h"
|
|
#include "services/network/public/cpp/network_switches.h"
|
|
+#include "third_party/ungoogled/ungoogled_switches.h"
|
|
#include "storage/browser/quota/quota_features.h"
|
|
#include "third_party/blink/public/common/experiments/memory_ablation_experiment.h"
|
|
#include "third_party/blink/public/common/features.h"
|
|
@@ -2516,6 +2517,18 @@ const FeatureEntry kFeatureEntries[] = {
|
|
{"enable-webrtc-srtp-aes-gcm", flag_descriptions::kWebrtcSrtpAesGcmName,
|
|
flag_descriptions::kWebrtcSrtpAesGcmDescription, kOsAll,
|
|
SINGLE_VALUE_TYPE(switches::kEnableWebRtcSrtpAesGcm)},
|
|
+ {"fingerprinting-canvas-image-data-noise",
|
|
+ "Disable Canvas image data fingerprint deception",
|
|
+ "Slightly modifies at most 20 pixels in Canvas image data extracted via JS APIs",
|
|
+ kOsAll, SINGLE_DISABLE_VALUE_TYPE(switches::kFingerprintingCanvasImageDataNoise)},
|
|
+ {"fingerprinting-client-rects-noise",
|
|
+ "Disable get*ClientRects() fingerprint deception",
|
|
+ "Scale the output values of Range::getClientRects() and Element::getBoundingClientRect() with a randomly selected factor in the range -0.0003% to 0.0003%, which are recomputed on every document initialization.",
|
|
+ kOsAll, SINGLE_DISABLE_VALUE_TYPE(switches::kFingerprintingClientRectsNoise)},
|
|
+ {"fingerprinting-canvas-measuretext-noise",
|
|
+ "Disable Canvas::measureText() fingerprint deception",
|
|
+ "Scale the output values of Canvas::measureText() with a randomly selected factor in the range -0.0003% to 0.0003%, which are recomputed on every document initialization.",
|
|
+ kOsAll, SINGLE_DISABLE_VALUE_TYPE(switches::kFingerprintingCanvasMeasureTextNoise)},
|
|
{"enable-webrtc-stun-origin", flag_descriptions::kWebrtcStunOriginName,
|
|
flag_descriptions::kWebrtcStunOriginDescription, kOsAll,
|
|
SINGLE_VALUE_TYPE(switches::kEnableWebRtcStunOrigin)},
|
|
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
|
|
--- a/content/browser/BUILD.gn
|
|
+++ b/content/browser/BUILD.gn
|
|
@@ -217,6 +217,7 @@ source_set("browser") {
|
|
"//third_party/libyuv",
|
|
"//third_party/re2",
|
|
"//third_party/sqlite",
|
|
+ "//third_party/ungoogled:switches",
|
|
"//third_party/webrtc_overrides:webrtc_component",
|
|
"//third_party/wtl",
|
|
"//third_party/zlib",
|
|
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
|
|
--- a/content/browser/renderer_host/render_process_host_impl.cc
|
|
+++ b/content/browser/renderer_host/render_process_host_impl.cc
|
|
@@ -219,6 +219,7 @@
|
|
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
|
|
#include "third_party/blink/public/mojom/disk_allocator.mojom.h"
|
|
#include "third_party/blink/public/public_buildflags.h"
|
|
+#include "third_party/ungoogled/ungoogled_switches.h"
|
|
#include "third_party/skia/include/core/SkBitmap.h"
|
|
#include "ui/accessibility/accessibility_switches.h"
|
|
#include "ui/base/ui_base_switches.h"
|
|
@@ -3280,6 +3281,9 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
|
|
switches::kDisableBreakpad,
|
|
switches::kDisableDatabases,
|
|
switches::kDisableFileSystem,
|
|
+ switches::kFingerprintingClientRectsNoise,
|
|
+ switches::kFingerprintingCanvasMeasureTextNoise,
|
|
+ switches::kFingerprintingCanvasImageDataNoise,
|
|
switches::kDisableFrameRateLimit,
|
|
switches::kDisableGpuMemoryBufferVideoFrames,
|
|
switches::kDisableHistogramCustomizer,
|
|
diff --git a/content/child/BUILD.gn b/content/child/BUILD.gn
|
|
--- a/content/child/BUILD.gn
|
|
+++ b/content/child/BUILD.gn
|
|
@@ -103,6 +103,7 @@ target(link_target_type, "child") {
|
|
"//third_party/blink/public/common",
|
|
"//third_party/blink/public/strings",
|
|
"//third_party/ced",
|
|
+ "//third_party/ungoogled:switches",
|
|
"//third_party/zlib/google:compression_utils",
|
|
"//ui/base",
|
|
"//ui/events/blink",
|
|
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
|
|
--- a/content/child/runtime_features.cc
|
|
+++ b/content/child/runtime_features.cc
|
|
@@ -37,6 +37,8 @@
|
|
#include "ui/gl/gl_switches.h"
|
|
#include "ui/native_theme/native_theme_features.h"
|
|
|
|
+#include "third_party/ungoogled/ungoogled_switches.h"
|
|
+
|
|
#if defined(OS_ANDROID)
|
|
#include "base/android/build_info.h"
|
|
#endif
|
|
@@ -530,6 +532,13 @@ void SetCustomizedRuntimeFeaturesFromCombinedArgs(
|
|
// They're moved here to distinguish them from actual base checks
|
|
WebRuntimeFeatures::EnableOverlayScrollbars(ui::IsOverlayScrollbarEnabled());
|
|
|
|
+ WebRuntimeFeatures::EnableFingerprintingClientRectsNoise(
|
|
+ !command_line.HasSwitch(switches::kFingerprintingClientRectsNoise));
|
|
+ WebRuntimeFeatures::EnableFingerprintingCanvasMeasureTextNoise(
|
|
+ !command_line.HasSwitch(switches::kFingerprintingCanvasMeasureTextNoise));
|
|
+ WebRuntimeFeatures::EnableFingerprintingCanvasImageDataNoise(
|
|
+ !command_line.HasSwitch(switches::kFingerprintingCanvasImageDataNoise));
|
|
+
|
|
if (base::FeatureList::IsEnabled(blink::features::kFileHandlingAPI)) {
|
|
WebRuntimeFeatures::EnableFeatureFromString("FileHandling", true);
|
|
}
|
|
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
|
|
--- a/third_party/blink/public/platform/web_runtime_features.h
|
|
+++ b/third_party/blink/public/platform/web_runtime_features.h
|
|
@@ -200,6 +200,9 @@ class WebRuntimeFeatures {
|
|
BLINK_PLATFORM_EXPORT static void EnableGetDisplayMedia(bool);
|
|
BLINK_PLATFORM_EXPORT static void EnableGetCurrentBrowsingContextMedia(bool);
|
|
BLINK_PLATFORM_EXPORT static void EnableAllowSyncXHRInPageDismissal(bool);
|
|
+ BLINK_PLATFORM_EXPORT static void EnableFingerprintingClientRectsNoise(bool);
|
|
+ BLINK_PLATFORM_EXPORT static void EnableFingerprintingCanvasMeasureTextNoise(bool);
|
|
+ BLINK_PLATFORM_EXPORT static void EnableFingerprintingCanvasImageDataNoise(bool);
|
|
BLINK_PLATFORM_EXPORT static void EnableShadowDOMV0(bool);
|
|
BLINK_PLATFORM_EXPORT static void EnableCustomElementsV0(bool);
|
|
BLINK_PLATFORM_EXPORT static void EnableHTMLImports(bool);
|
|
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
|
|
--- a/third_party/blink/renderer/core/dom/document.cc
|
|
+++ b/third_party/blink/renderer/core/dom/document.cc
|
|
@@ -42,6 +42,7 @@
|
|
#include "base/macros.h"
|
|
#include "base/metrics/histogram_functions.h"
|
|
#include "base/optional.h"
|
|
+#include "base/rand_util.h"
|
|
#include "base/time/time.h"
|
|
#include "cc/input/overscroll_behavior.h"
|
|
#include "cc/input/scroll_snap_data.h"
|
|
@@ -2513,6 +2514,23 @@ void Document::UpdateStyleAndLayoutTree() {
|
|
#if DCHECK_IS_ON()
|
|
AssertLayoutTreeUpdated(*this);
|
|
#endif
|
|
+
|
|
+ if (RuntimeEnabledFeatures::FingerprintingClientRectsNoiseEnabled()) {
|
|
+ // Precompute -0.0003% to 0.0003% noise factor for get*ClientRect*() fingerprinting
|
|
+ noise_factor_x_ = 1 + (base::RandDouble() - 0.5) * 0.000003;
|
|
+ noise_factor_y_ = 1 + (base::RandDouble() - 0.5) * 0.000003;
|
|
+ } else {
|
|
+ noise_factor_x_ = 1;
|
|
+ noise_factor_y_ = 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+double Document::GetNoiseFactorX() {
|
|
+ return noise_factor_x_;
|
|
+}
|
|
+
|
|
+double Document::GetNoiseFactorY() {
|
|
+ return noise_factor_y_;
|
|
}
|
|
|
|
void Document::InvalidateStyleAndLayoutForFontUpdates() {
|
|
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
|
|
--- a/third_party/blink/renderer/core/dom/document.h
|
|
+++ b/third_party/blink/renderer/core/dom/document.h
|
|
@@ -448,6 +448,10 @@ class CORE_EXPORT Document : public ContainerNode,
|
|
has_xml_declaration_ = has_xml_declaration ? 1 : 0;
|
|
}
|
|
|
|
+ // Values for get*ClientRect fingerprint deception
|
|
+ double GetNoiseFactorX();
|
|
+ double GetNoiseFactorY();
|
|
+
|
|
AtomicString visibilityState() const;
|
|
bool IsPageVisible() const;
|
|
bool hidden() const;
|
|
@@ -1984,6 +1988,9 @@ class CORE_EXPORT Document : public ContainerNode,
|
|
|
|
base::ElapsedTimer start_time_;
|
|
|
|
+ double noise_factor_x_;
|
|
+ double noise_factor_y_;
|
|
+
|
|
Member<ScriptRunner> script_runner_;
|
|
|
|
HeapVector<Member<ScriptElementBase>> current_script_stack_;
|
|
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
|
|
--- a/third_party/blink/renderer/core/dom/element.cc
|
|
+++ b/third_party/blink/renderer/core/dom/element.cc
|
|
@@ -2062,6 +2062,11 @@ DOMRectList* Element::getClientRects() {
|
|
DCHECK(element_layout_object);
|
|
GetDocument().AdjustFloatQuadsForScrollAndAbsoluteZoom(
|
|
quads, *element_layout_object);
|
|
+ if (RuntimeEnabledFeatures::FingerprintingClientRectsNoiseEnabled()) {
|
|
+ for (FloatQuad& quad : quads) {
|
|
+ quad.Scale(GetDocument().GetNoiseFactorX(), GetDocument().GetNoiseFactorY());
|
|
+ }
|
|
+ }
|
|
return MakeGarbageCollected<DOMRectList>(quads);
|
|
}
|
|
|
|
@@ -2079,6 +2084,9 @@ DOMRect* Element::getBoundingClientRect() {
|
|
DCHECK(element_layout_object);
|
|
GetDocument().AdjustFloatRectForScrollAndAbsoluteZoom(result,
|
|
*element_layout_object);
|
|
+ if (RuntimeEnabledFeatures::FingerprintingClientRectsNoiseEnabled()) {
|
|
+ result.Scale(GetDocument().GetNoiseFactorX(), GetDocument().GetNoiseFactorY());
|
|
+ }
|
|
return DOMRect::FromFloatRect(result);
|
|
}
|
|
|
|
diff --git a/third_party/blink/renderer/core/dom/range.cc b/third_party/blink/renderer/core/dom/range.cc
|
|
--- a/third_party/blink/renderer/core/dom/range.cc
|
|
+++ b/third_party/blink/renderer/core/dom/range.cc
|
|
@@ -1615,6 +1615,12 @@ DOMRectList* Range::getClientRects() const {
|
|
Vector<FloatQuad> quads;
|
|
GetBorderAndTextQuads(quads);
|
|
|
|
+ if (RuntimeEnabledFeatures::FingerprintingClientRectsNoiseEnabled()) {
|
|
+ for (FloatQuad& quad : quads) {
|
|
+ quad.Scale(owner_document_->GetNoiseFactorX(), owner_document_->GetNoiseFactorY());
|
|
+ }
|
|
+ }
|
|
+
|
|
return MakeGarbageCollected<DOMRectList>(quads);
|
|
}
|
|
|
|
@@ -1741,7 +1747,11 @@ FloatRect Range::BoundingRect() const {
|
|
|
|
// If all rects are empty, return the first rect.
|
|
if (result.IsEmpty() && !quads.IsEmpty())
|
|
- return quads.front().BoundingBox();
|
|
+ result = quads.front().BoundingBox();
|
|
+
|
|
+ if (!result.IsEmpty() && RuntimeEnabledFeatures::FingerprintingClientRectsNoiseEnabled()) {
|
|
+ result.Scale(owner_document_->GetNoiseFactorX(), owner_document_->GetNoiseFactorY());
|
|
+ }
|
|
|
|
return result;
|
|
}
|
|
diff --git a/third_party/blink/renderer/core/html/canvas/text_metrics.cc b/third_party/blink/renderer/core/html/canvas/text_metrics.cc
|
|
--- a/third_party/blink/renderer/core/html/canvas/text_metrics.cc
|
|
+++ b/third_party/blink/renderer/core/html/canvas/text_metrics.cc
|
|
@@ -55,6 +55,24 @@ TextMetrics::TextMetrics(const Font& font,
|
|
Update(font, direction, baseline, align, text);
|
|
}
|
|
|
|
+void TextMetrics::Shuffle(const double factor) {
|
|
+ // x-direction
|
|
+ width_ *= factor;
|
|
+ actual_bounding_box_left_ *= factor;
|
|
+ actual_bounding_box_right_ *= factor;
|
|
+
|
|
+ // y-direction
|
|
+ font_bounding_box_ascent_ *= factor;
|
|
+ font_bounding_box_descent_ *= factor;
|
|
+ actual_bounding_box_ascent_ *= factor;
|
|
+ actual_bounding_box_descent_ *= factor;
|
|
+ em_height_ascent_ *= factor;
|
|
+ em_height_descent_ *= factor;
|
|
+ baselines_->setAlphabetic(baselines_->alphabetic() * factor);
|
|
+ baselines_->setHanging(baselines_->hanging() * factor);
|
|
+ baselines_->setIdeographic(baselines_->ideographic() * factor);
|
|
+}
|
|
+
|
|
void TextMetrics::Update(const Font& font,
|
|
const TextDirection& direction,
|
|
const TextBaseline& baseline,
|
|
diff --git a/third_party/blink/renderer/core/html/canvas/text_metrics.h b/third_party/blink/renderer/core/html/canvas/text_metrics.h
|
|
--- a/third_party/blink/renderer/core/html/canvas/text_metrics.h
|
|
+++ b/third_party/blink/renderer/core/html/canvas/text_metrics.h
|
|
@@ -64,6 +64,8 @@ class CORE_EXPORT TextMetrics final : public ScriptWrappable {
|
|
|
|
void Trace(Visitor*) const override;
|
|
|
|
+ void Shuffle(const double factor);
|
|
+
|
|
private:
|
|
void Update(const Font&,
|
|
const TextDirection&,
|
|
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
|
|
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
|
|
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
|
|
@@ -947,9 +947,15 @@ TextMetrics* CanvasRenderingContext2D::measureText(const String& text) {
|
|
else
|
|
direction = ToTextDirection(GetState().GetDirection(), canvas());
|
|
|
|
- return MakeGarbageCollected<TextMetrics>(font, direction,
|
|
+ TextMetrics* text_metrics = MakeGarbageCollected<TextMetrics>(font, direction,
|
|
GetState().GetTextBaseline(),
|
|
GetState().GetTextAlign(), text);
|
|
+
|
|
+ // Scale text metrics if enabled
|
|
+ if (RuntimeEnabledFeatures::FingerprintingCanvasMeasureTextNoiseEnabled()) {
|
|
+ text_metrics->Shuffle(canvas()->GetDocument().GetNoiseFactorX());
|
|
+ }
|
|
+ return text_metrics;
|
|
}
|
|
|
|
void CanvasRenderingContext2D::DrawTextInternal(
|
|
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
|
|
--- a/third_party/blink/renderer/platform/BUILD.gn
|
|
+++ b/third_party/blink/renderer/platform/BUILD.gn
|
|
@@ -1584,7 +1584,9 @@ component("platform") {
|
|
"//third_party/blink/renderer:non_test_config",
|
|
]
|
|
|
|
- include_dirs = []
|
|
+ include_dirs = [
|
|
+ "//third_party/skia/include/private", # For shuffler in graphics/static_bitmap_image.cc
|
|
+ ]
|
|
|
|
allow_circular_includes_from = [
|
|
"//third_party/blink/renderer/platform/blob",
|
|
@@ -1647,6 +1649,7 @@ component("platform") {
|
|
"//third_party/blink/public/strings",
|
|
"//third_party/blink/renderer/platform/wtf",
|
|
"//third_party/ced",
|
|
+ "//third_party/ungoogled:switches",
|
|
"//third_party/emoji-segmenter",
|
|
"//third_party/harfbuzz-ng:hb_scoped_util",
|
|
"//third_party/icu",
|
|
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
|
|
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
|
|
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
|
|
@@ -647,4 +647,16 @@ void WebRuntimeFeatures::EnableTargetBlankImpliesNoOpener(bool enable) {
|
|
RuntimeEnabledFeatures::SetTargetBlankImpliesNoOpenerEnabled(enable);
|
|
}
|
|
|
|
+void WebRuntimeFeatures::EnableFingerprintingClientRectsNoise(bool enable) {
|
|
+ RuntimeEnabledFeatures::SetFingerprintingClientRectsNoiseEnabled(enable);
|
|
+}
|
|
+
|
|
+void WebRuntimeFeatures::EnableFingerprintingCanvasMeasureTextNoise(bool enable) {
|
|
+ RuntimeEnabledFeatures::SetFingerprintingCanvasMeasureTextNoiseEnabled(enable);
|
|
+}
|
|
+
|
|
+void WebRuntimeFeatures::EnableFingerprintingCanvasImageDataNoise(bool enable) {
|
|
+ RuntimeEnabledFeatures::SetFingerprintingCanvasImageDataNoiseEnabled(enable);
|
|
+}
|
|
+
|
|
} // namespace blink
|
|
diff --git a/third_party/blink/renderer/platform/graphics/image_data_buffer.cc b/third_party/blink/renderer/platform/graphics/image_data_buffer.cc
|
|
--- a/third_party/blink/renderer/platform/graphics/image_data_buffer.cc
|
|
+++ b/third_party/blink/renderer/platform/graphics/image_data_buffer.cc
|
|
@@ -36,6 +36,8 @@
|
|
|
|
#include "base/compiler_specific.h"
|
|
#include "base/memory/ptr_util.h"
|
|
+#include "base/rand_util.h"
|
|
+#include "base/logging.h"
|
|
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
|
|
#include "third_party/blink/renderer/platform/image-encoders/image_encoder.h"
|
|
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
|
|
@@ -145,6 +147,11 @@ bool ImageDataBuffer::EncodeImageInternal(const ImageEncodingMimeType mime_type,
|
|
const SkPixmap& pixmap) const {
|
|
DCHECK(is_valid_);
|
|
|
|
+ if (RuntimeEnabledFeatures::FingerprintingCanvasImageDataNoiseEnabled()) {
|
|
+ // shuffle subchannel color data within the pixmap
|
|
+ StaticBitmapImage::ShuffleSubchannelColorData(pixmap_.writable_addr(), pixmap_.info(), 0, 0);
|
|
+ }
|
|
+
|
|
if (mime_type == kMimeTypeJpeg) {
|
|
SkJpegEncoder::Options options;
|
|
options.fQuality = ImageEncoder::ComputeJpegQuality(quality);
|
|
diff --git a/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc b/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
|
|
--- a/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
|
|
+++ b/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
|
|
@@ -4,6 +4,8 @@
|
|
|
|
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
|
|
|
|
+#include "base/rand_util.h"
|
|
+#include "base/logging.h"
|
|
#include "base/numerics/checked_math.h"
|
|
#include "gpu/command_buffer/client/gles2_interface.h"
|
|
#include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
|
|
@@ -17,6 +19,9 @@
|
|
#include "third_party/skia/include/core/SkSurface.h"
|
|
#include "v8/include/v8.h"
|
|
|
|
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
|
|
+#include "third_party/skia/include/private/SkColorData.h"
|
|
+
|
|
namespace blink {
|
|
|
|
scoped_refptr<StaticBitmapImage> StaticBitmapImage::Create(
|
|
@@ -128,7 +133,162 @@ bool StaticBitmapImage::CopyToByteArray(
|
|
.bounds()
|
|
.intersect(SkIRect::MakeXYWH(rect.X(), rect.Y(), info.width(),
|
|
info.height())));
|
|
+
|
|
+ if (read_pixels_successful && RuntimeEnabledFeatures::FingerprintingCanvasImageDataNoiseEnabled()) {
|
|
+ ShuffleSubchannelColorData(dst.data(), info, rect.X(), rect.Y());
|
|
+ }
|
|
+
|
|
return true;
|
|
}
|
|
|
|
+// set the component to maximum-delta if it is >= maximum, or add to existing color component (color + delta)
|
|
+#define shuffleComponent(color, max, delta) ( (color) >= (max) ? ((max)-(delta)) : ((color)+(delta)) )
|
|
+
|
|
+#define writable_addr(T, p, stride, x, y) (T*)((const char *)p + y * stride + x * sizeof(T))
|
|
+
|
|
+void StaticBitmapImage::ShuffleSubchannelColorData(const void *addr, const SkImageInfo& info, int srcX, int srcY) {
|
|
+ auto w = info.width() - srcX, h = info.height() - srcY;
|
|
+
|
|
+ // skip tiny images; info.width()/height() can also be 0
|
|
+ if ((w < 8) || (h < 8)) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // generate the first random number here
|
|
+ double shuffleX = base::RandDouble();
|
|
+
|
|
+ // cap maximum pixels to change
|
|
+ auto pixels = (w + h) / 128;
|
|
+ if (pixels > 20) {
|
|
+ pixels = 20;
|
|
+ } else if (pixels < 2) {
|
|
+ pixels = 2;
|
|
+ }
|
|
+
|
|
+ auto colorType = info.colorType();
|
|
+ auto fRowBytes = info.minRowBytes(); // stride
|
|
+
|
|
+ DLOG(INFO) << "BRM: ShuffleSubchannelColorData() w=" << w << " h=" << h << " colorType=" << colorType << " fRowBytes=" << fRowBytes;
|
|
+
|
|
+ // second random number (for y/height)
|
|
+ double shuffleY = base::RandDouble();
|
|
+
|
|
+ // calculate random coordinates using bisection
|
|
+ auto currentW = w, currentH = h;
|
|
+ for(;pixels >= 0; pixels--) {
|
|
+ int x = currentW * shuffleX, y = currentH * shuffleY;
|
|
+
|
|
+ // calculate randomisation amounts for each RGB component
|
|
+ uint8_t shuffleR = base::RandInt(0, 4);
|
|
+ uint8_t shuffleG = (shuffleR + x) % 4;
|
|
+ uint8_t shuffleB = (shuffleG + y) % 4;
|
|
+
|
|
+ // manipulate pixel data to slightly change the R, G, B components
|
|
+ switch (colorType) {
|
|
+ case kAlpha_8_SkColorType:
|
|
+ {
|
|
+ auto *pixel = writable_addr(uint8_t, addr, fRowBytes, x, y);
|
|
+ auto r = SkColorGetR(*pixel), g = SkColorGetG(*pixel), b = SkColorGetB(*pixel), a = SkColorGetA(*pixel);
|
|
+
|
|
+ r = shuffleComponent(r, UINT8_MAX-1, shuffleR);
|
|
+ g = shuffleComponent(g, UINT8_MAX-1, shuffleG);
|
|
+ b = shuffleComponent(b, UINT8_MAX-1, shuffleB);
|
|
+ // alpha is left unchanged
|
|
+
|
|
+ *pixel = SkColorSetARGB(a, r, g, b);
|
|
+ }
|
|
+ break;
|
|
+ case kGray_8_SkColorType:
|
|
+ {
|
|
+ auto *pixel = writable_addr(uint8_t, addr, fRowBytes, x, y);
|
|
+ *pixel = shuffleComponent(*pixel, UINT8_MAX-1, shuffleB);
|
|
+ }
|
|
+ break;
|
|
+ case kRGB_565_SkColorType:
|
|
+ {
|
|
+ auto *pixel = writable_addr(uint16_t, addr, fRowBytes, x, y);
|
|
+ unsigned r = SkPacked16ToR32(*pixel);
|
|
+ unsigned g = SkPacked16ToG32(*pixel);
|
|
+ unsigned b = SkPacked16ToB32(*pixel);
|
|
+
|
|
+ r = shuffleComponent(r, 31, shuffleR);
|
|
+ g = shuffleComponent(g, 63, shuffleG);
|
|
+ b = shuffleComponent(b, 31, shuffleB);
|
|
+
|
|
+ unsigned r16 = (r & SK_R16_MASK) << SK_R16_SHIFT;
|
|
+ unsigned g16 = (g & SK_G16_MASK) << SK_G16_SHIFT;
|
|
+ unsigned b16 = (b & SK_B16_MASK) << SK_B16_SHIFT;
|
|
+
|
|
+ *pixel = r16 | g16 | b16;
|
|
+ }
|
|
+ break;
|
|
+ case kARGB_4444_SkColorType:
|
|
+ {
|
|
+ auto *pixel = writable_addr(uint16_t, addr, fRowBytes, x, y);
|
|
+ auto a = SkGetPackedA4444(*pixel), r = SkGetPackedR4444(*pixel), g = SkGetPackedG4444(*pixel), b = SkGetPackedB4444(*pixel);
|
|
+
|
|
+ r = shuffleComponent(r, 15, shuffleR);
|
|
+ g = shuffleComponent(g, 15, shuffleG);
|
|
+ b = shuffleComponent(b, 15, shuffleB);
|
|
+ // alpha is left unchanged
|
|
+
|
|
+ unsigned a4 = (a & 0xF) << SK_A4444_SHIFT;
|
|
+ unsigned r4 = (r & 0xF) << SK_R4444_SHIFT;
|
|
+ unsigned g4 = (g & 0xF) << SK_G4444_SHIFT;
|
|
+ unsigned b4 = (b & 0xF) << SK_B4444_SHIFT;
|
|
+
|
|
+ *pixel = r4 | b4 | g4 | a4;
|
|
+ }
|
|
+ break;
|
|
+ case kRGBA_8888_SkColorType:
|
|
+ {
|
|
+ auto *pixel = writable_addr(uint32_t, addr, fRowBytes, x, y);
|
|
+ auto a = SkGetPackedA32(*pixel), r = SkGetPackedR32(*pixel), g = SkGetPackedG32(*pixel), b = SkGetPackedB32(*pixel);
|
|
+
|
|
+ r = shuffleComponent(r, UINT8_MAX-1, shuffleR);
|
|
+ g = shuffleComponent(g, UINT8_MAX-1, shuffleG);
|
|
+ b = shuffleComponent(b, UINT8_MAX-1, shuffleB);
|
|
+ // alpha is left unchanged
|
|
+
|
|
+ *pixel = (a << SK_A32_SHIFT) | (r << SK_R32_SHIFT) |
|
|
+ (g << SK_G32_SHIFT) | (b << SK_B32_SHIFT);
|
|
+ }
|
|
+ break;
|
|
+ case kBGRA_8888_SkColorType:
|
|
+ {
|
|
+ auto *pixel = writable_addr(uint32_t, addr, fRowBytes, x, y);
|
|
+ auto a = SkGetPackedA32(*pixel), b = SkGetPackedR32(*pixel), g = SkGetPackedG32(*pixel), r = SkGetPackedB32(*pixel);
|
|
+
|
|
+ r = shuffleComponent(r, UINT8_MAX-1, shuffleR);
|
|
+ g = shuffleComponent(g, UINT8_MAX-1, shuffleG);
|
|
+ b = shuffleComponent(b, UINT8_MAX-1, shuffleB);
|
|
+ // alpha is left unchanged
|
|
+
|
|
+ *pixel = (a << SK_BGRA_A32_SHIFT) | (r << SK_BGRA_R32_SHIFT) |
|
|
+ (g << SK_BGRA_G32_SHIFT) | (b << SK_BGRA_B32_SHIFT);
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ // the remaining formats are not expected to be used in Chromium
|
|
+ LOG(WARNING) << "BRM: ShuffleSubchannelColorData(): Ignoring pixel format";
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // keep bisecting or reset current width/height as needed
|
|
+ if (x == 0) {
|
|
+ currentW = w;
|
|
+ } else {
|
|
+ currentW = x;
|
|
+ }
|
|
+ if (y == 0) {
|
|
+ currentH = h;
|
|
+ } else {
|
|
+ currentH = y;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+#undef writable_addr
|
|
+#undef shuffleComponent
|
|
+
|
|
} // namespace blink
|
|
diff --git a/third_party/blink/renderer/platform/graphics/static_bitmap_image.h b/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
|
|
--- a/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
|
|
+++ b/third_party/blink/renderer/platform/graphics/static_bitmap_image.h
|
|
@@ -35,6 +35,8 @@ class PLATFORM_EXPORT StaticBitmapImage : public Image {
|
|
|
|
StaticBitmapImage(ImageOrientation orientation) : orientation_(orientation) {}
|
|
|
|
+ static void ShuffleSubchannelColorData(const void *addr, const SkImageInfo& info, int srcX, int srcY);
|
|
+
|
|
bool IsStaticBitmapImage() const override { return true; }
|
|
|
|
// Methods overridden by all sub-classes
|
|
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
|
|
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
|
|
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
|
|
@@ -850,6 +850,15 @@
|
|
origin_trial_feature_name: "FeaturePolicyReporting",
|
|
status: "experimental"
|
|
},
|
|
+ {
|
|
+ name: "FingerprintingClientRectsNoise",
|
|
+ },
|
|
+ {
|
|
+ name: "FingerprintingCanvasMeasureTextNoise",
|
|
+ },
|
|
+ {
|
|
+ name: "FingerprintingCanvasImageDataNoise",
|
|
+ },
|
|
{
|
|
name: "FeaturePolicyVibrateFeature"
|
|
},
|
|
diff --git a/third_party/ungoogled/BUILD.gn b/third_party/ungoogled/BUILD.gn
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/third_party/ungoogled/BUILD.gn
|
|
@@ -0,0 +1,10 @@
|
|
+# Copyright (c) 2018 The ungoogled-chromium Authors. All rights reserved.
|
|
+# Use of this source code is governed by a BSD-style license that can be
|
|
+# found in the LICENSE file.
|
|
+
|
|
+component("switches") {
|
|
+ sources = [
|
|
+ "ungoogled_switches.h",
|
|
+ "ungoogled_switches.cc",
|
|
+ ]
|
|
+}
|
|
diff --git a/third_party/ungoogled/ungoogled_switches.cc b/third_party/ungoogled/ungoogled_switches.cc
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/third_party/ungoogled/ungoogled_switches.cc
|
|
@@ -0,0 +1,18 @@
|
|
+// Copyright (c) 2018 The ungoogled-chromium Authors. All rights reserved.
|
|
+// Use of this source code is governed by a BSD-style license that can be
|
|
+// found in the LICENSE file.
|
|
+
|
|
+#include "third_party/ungoogled/ungoogled_switches.h"
|
|
+
|
|
+namespace switches {
|
|
+
|
|
+// Enable fingerprinting deception for getClientRects and getBoundingClientRect
|
|
+const char kFingerprintingClientRectsNoise[] = "fingerprinting-client-rects-noise";
|
|
+
|
|
+// Enable fingerprinting deception for measureText
|
|
+const char kFingerprintingCanvasMeasureTextNoise[] = "fingerprinting-canvas-measuretext-noise";
|
|
+
|
|
+// Enable fingerprinting deception for Canvas image data
|
|
+const char kFingerprintingCanvasImageDataNoise[] = "fingerprinting-canvas-image-data-noise";
|
|
+
|
|
+} // namespace switches
|
|
diff --git a/third_party/ungoogled/ungoogled_switches.h b/third_party/ungoogled/ungoogled_switches.h
|
|
new file mode 100644
|
|
--- /dev/null
|
|
+++ b/third_party/ungoogled/ungoogled_switches.h
|
|
@@ -0,0 +1,18 @@
|
|
+// Copyright (c) 2018 The ungoogled-chromium Authors. All rights reserved.
|
|
+// Use of this source code is governed by a BSD-style license that can be
|
|
+// found in the LICENSE file.
|
|
+
|
|
+// Defines all the fingerprinting command-line switches.
|
|
+
|
|
+#ifndef THIRD_PARTY_UNGOOGLED_FINGERPRINTING_SWITCHES_H_
|
|
+#define THIRD_PARTY_UNGOOGLED_FINGERPRINTING_SWITCHES_H_
|
|
+
|
|
+namespace switches {
|
|
+
|
|
+extern const char kFingerprintingClientRectsNoise[];
|
|
+extern const char kFingerprintingCanvasMeasureTextNoise[];
|
|
+extern const char kFingerprintingCanvasImageDataNoise[];
|
|
+
|
|
+}
|
|
+
|
|
+#endif // THIRD_PARTY_UNGOOGLED_FINGERPRINTING_SWITCHES_H_
|
|
--
|
|
2.17.1
|
|
|