Implement content-sensitive canvas farbling
add missing patch fewer patches refactor content settings agent, add support for brave shields down, WIP browser tests fix browser test lint types lint .
This commit is contained in:
@@ -3,12 +3,25 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "base/feature_list.h"
|
||||
#include "brave/components/brave_shields/common/brave_shield_constants.h"
|
||||
#include "brave/components/brave_shields/common/features.h"
|
||||
|
||||
#define BRAVE_GET_RENDER_CONTENT_SETTING_RULES \
|
||||
map->GetSettingsForOneType(ContentSettingsType::AUTOPLAY, \
|
||||
ResourceIdentifier(), &(rules->autoplay_rules)); \
|
||||
map->GetSettingsForOneType(ContentSettingsType::PLUGINS, "fingerprinting", \
|
||||
&(rules->fingerprinting_rules)); \
|
||||
map->GetSettingsForOneType(ContentSettingsType::PLUGINS, "braveShields", \
|
||||
if (base::FeatureList::IsEnabled( \
|
||||
brave_shields::features::kFingerprintingProtectionV2)) { \
|
||||
map->GetSettingsForOneType(ContentSettingsType::PLUGINS, \
|
||||
brave_shields::kFingerprintingV2, \
|
||||
&(rules->fingerprinting_rules)); \
|
||||
} else { \
|
||||
map->GetSettingsForOneType(ContentSettingsType::PLUGINS, \
|
||||
brave_shields::kFingerprinting, \
|
||||
&(rules->fingerprinting_rules)); \
|
||||
} \
|
||||
map->GetSettingsForOneType(ContentSettingsType::PLUGINS, \
|
||||
brave_shields::kBraveShields, \
|
||||
&(rules->brave_shields_rules));
|
||||
|
||||
#include "../../../../../components/content_settings/core/browser/content_settings_utils.cc" // NOLINT
|
||||
|
||||
+38
-17
@@ -31,13 +31,17 @@ BraveSessionCache::BraveSessionCache(Document& document)
|
||||
base::StringPiece(document.TopFrameOrigin()->ToUrlOrigin().host());
|
||||
std::string domain = net::registry_controlled_domains::GetDomainAndRegistry(
|
||||
host, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
|
||||
crypto::HMAC h(crypto::HMAC::SHA256);
|
||||
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
|
||||
DCHECK(cmd_line->HasSwitch(kBraveSessionToken));
|
||||
uint64_t key;
|
||||
base::StringToUint64(cmd_line->GetSwitchValueASCII(kBraveSessionToken), &key);
|
||||
CHECK(h.Init(reinterpret_cast<const unsigned char*>(&key), sizeof key));
|
||||
CHECK(h.Sign(domain, domain_key_, sizeof domain_key_));
|
||||
farbling_enabled_ = !domain.empty();
|
||||
if (farbling_enabled_) {
|
||||
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
|
||||
DCHECK(cmd_line->HasSwitch(kBraveSessionToken));
|
||||
base::StringToUint64(cmd_line->GetSwitchValueASCII(kBraveSessionToken),
|
||||
&session_key_);
|
||||
crypto::HMAC h(crypto::HMAC::SHA256);
|
||||
CHECK(h.Init(reinterpret_cast<const unsigned char*>(&session_key_),
|
||||
sizeof session_key_));
|
||||
CHECK(h.Sign(domain, domain_key_, sizeof domain_key_));
|
||||
}
|
||||
}
|
||||
|
||||
BraveSessionCache& BraveSessionCache::From(Document& document) {
|
||||
@@ -51,17 +55,20 @@ BraveSessionCache& BraveSessionCache::From(Document& document) {
|
||||
}
|
||||
|
||||
double BraveSessionCache::GetFudgeFactor() {
|
||||
const uint64_t* fudge = reinterpret_cast<const uint64_t*>(domain_key_);
|
||||
const double maxUInt64AsDouble = UINT64_MAX;
|
||||
double fudge_factor = 0.99 + ((*fudge / maxUInt64AsDouble) / 100);
|
||||
VLOG(1) << "audio fudge factor (based on session token) = " << fudge_factor;
|
||||
double fudge_factor = 1.0;
|
||||
if (farbling_enabled_) {
|
||||
const uint64_t* fudge = reinterpret_cast<const uint64_t*>(domain_key_);
|
||||
const double maxUInt64AsDouble = UINT64_MAX;
|
||||
fudge_factor = 0.99 + ((*fudge / maxUInt64AsDouble) / 100);
|
||||
VLOG(1) << "audio fudge factor (based on session token) = " << fudge_factor;
|
||||
}
|
||||
return fudge_factor;
|
||||
}
|
||||
|
||||
scoped_refptr<blink::StaticBitmapImage> BraveSessionCache::PerturbPixels(
|
||||
blink::LocalFrame* frame,
|
||||
scoped_refptr<blink::StaticBitmapImage> image_bitmap) {
|
||||
if (!frame || !frame->GetContentSettingsClient()) {
|
||||
if (!farbling_enabled_ || !frame || !frame->GetContentSettingsClient()) {
|
||||
return image_bitmap;
|
||||
}
|
||||
switch (frame->GetContentSettingsClient()->GetBraveFarblingLevel()) {
|
||||
@@ -91,18 +98,32 @@ scoped_refptr<blink::StaticBitmapImage> BraveSessionCache::PerturbBalanced(
|
||||
std::unique_ptr<blink::ImageDataBuffer> data_buffer =
|
||||
blink::ImageDataBuffer::Create(image_bitmap);
|
||||
uint8_t* pixels = const_cast<uint8_t*>(data_buffer->Pixels());
|
||||
const uint64_t pixel_count = data_buffer->Width() * data_buffer->Height();
|
||||
// This needs to be type size_t because we pass it to base::StringPiece
|
||||
// later for content hashing. This is safe because the maximum canvas
|
||||
// dimensions are less than SIZE_T_MAX. (Width and height are each
|
||||
// limited to 32,767 pixels.)
|
||||
const size_t pixel_count = data_buffer->Width() * data_buffer->Height();
|
||||
// choose which channel (R, G, or B) to perturb
|
||||
const uint8_t* first_byte = reinterpret_cast<const uint8_t*>(domain_key_);
|
||||
uint8_t channel = *first_byte % 3;
|
||||
// initial seed to find first pixel to perturb
|
||||
uint64_t v = *reinterpret_cast<uint64_t*>(domain_key_);
|
||||
// calculate initial seed to find first pixel to perturb, based on session
|
||||
// key, domain key, and canvas contents
|
||||
crypto::HMAC h(crypto::HMAC::SHA256);
|
||||
uint64_t session_plus_domain_key =
|
||||
session_key_ ^ *reinterpret_cast<uint64_t*>(domain_key_);
|
||||
CHECK(h.Init(reinterpret_cast<const unsigned char*>(&session_plus_domain_key),
|
||||
sizeof session_plus_domain_key));
|
||||
uint8_t canvas_key[32];
|
||||
CHECK(h.Sign(
|
||||
base::StringPiece(reinterpret_cast<const char*>(pixels), pixel_count),
|
||||
canvas_key, sizeof canvas_key));
|
||||
uint64_t v = *reinterpret_cast<uint64_t*>(canvas_key);
|
||||
const uint64_t zero = 0;
|
||||
uint64_t pixel_index;
|
||||
// iterate through 32-byte domain key and use each bit to determine how to
|
||||
// iterate through 32-byte canvas key and use each bit to determine how to
|
||||
// perturb the current pixel
|
||||
for (int i = 0; i < 32; i++) {
|
||||
uint8_t bit = domain_key_[i];
|
||||
uint8_t bit = canvas_key[i];
|
||||
for (int j = 8; j >= 0; j--) {
|
||||
pixel_index = 4 * (v % pixel_count) + channel;
|
||||
pixels[pixel_index] = pixels[pixel_index] ^ (bit & 0x1);
|
||||
|
||||
@@ -41,6 +41,8 @@ class CORE_EXPORT BraveSessionCache final
|
||||
scoped_refptr<blink::StaticBitmapImage> image_bitmap);
|
||||
|
||||
private:
|
||||
bool farbling_enabled_;
|
||||
uint64_t session_key_;
|
||||
uint8_t domain_key_[32];
|
||||
|
||||
scoped_refptr<blink::StaticBitmapImage> PerturbBalanced(
|
||||
|
||||
@@ -47,20 +47,35 @@ GURL GetOriginOrURL(
|
||||
return top_origin.GetURL();
|
||||
}
|
||||
|
||||
bool IsBraveShieldsDown(const blink::WebFrame* frame,
|
||||
const GURL& secondary_url,
|
||||
const ContentSettingsForOneType& rules) {
|
||||
ContentSetting setting = CONTENT_SETTING_DEFAULT;
|
||||
const GURL& primary_url = GetOriginOrURL(frame);
|
||||
|
||||
for (const auto& rule : rules) {
|
||||
if (rule.primary_pattern.Matches(primary_url) &&
|
||||
rule.secondary_pattern.Matches(secondary_url)) {
|
||||
setting = rule.GetContentSetting();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return setting == CONTENT_SETTING_BLOCK;
|
||||
}
|
||||
|
||||
// This method can only be used for brave plugin content settings because
|
||||
// they are implemented incorrectly and swap primary/secondary url
|
||||
template <typename URL>
|
||||
ContentSetting GetBraveContentSettingFromRules(
|
||||
const ContentSettingsForOneType& shield_rules,
|
||||
const ContentSettingsForOneType& rules,
|
||||
const blink::WebFrame* frame,
|
||||
const URL& secondary_url) {
|
||||
// If there is only one rule, it's the default rule and we don't need to match
|
||||
// the patterns.
|
||||
if (rules.size() == 1) {
|
||||
DCHECK(rules[0].primary_pattern == ContentSettingsPattern::Wildcard());
|
||||
DCHECK(rules[0].secondary_pattern == ContentSettingsPattern::Wildcard());
|
||||
return rules[0].GetContentSetting();
|
||||
}
|
||||
// if shields is down, allow everything
|
||||
if (IsBraveShieldsDown(frame, secondary_url, shield_rules))
|
||||
return CONTENT_SETTING_ALLOW;
|
||||
|
||||
const GURL& primary_url = GetOriginOrURL(frame);
|
||||
const GURL& secondary_gurl = secondary_url;
|
||||
for (const auto& rule : rules) {
|
||||
@@ -219,20 +234,9 @@ ContentSetting BraveContentSettingsAgentImpl::GetFPContentSettingFromRules(
|
||||
bool BraveContentSettingsAgentImpl::IsBraveShieldsDown(
|
||||
const blink::WebFrame* frame,
|
||||
const GURL& secondary_url) {
|
||||
ContentSetting setting = CONTENT_SETTING_DEFAULT;
|
||||
const GURL& primary_url = GetOriginOrURL(frame);
|
||||
|
||||
if (content_setting_rules_) {
|
||||
for (const auto& rule : content_setting_rules_->brave_shields_rules) {
|
||||
if (rule.primary_pattern.Matches(primary_url) &&
|
||||
rule.secondary_pattern.Matches(secondary_url)) {
|
||||
setting = rule.GetContentSetting();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return setting == CONTENT_SETTING_BLOCK;
|
||||
return !content_setting_rules_ ||
|
||||
::IsBraveShieldsDown(frame, secondary_url,
|
||||
content_setting_rules_->brave_shields_rules);
|
||||
}
|
||||
|
||||
bool BraveContentSettingsAgentImpl::AllowFingerprinting(
|
||||
@@ -279,6 +283,7 @@ BraveFarblingLevel BraveContentSettingsAgentImpl::GetBraveFarblingLevel() {
|
||||
ContentSetting setting = CONTENT_SETTING_DEFAULT;
|
||||
if (content_setting_rules_) {
|
||||
setting = GetBraveContentSettingFromRules(
|
||||
content_setting_rules_->brave_shields_rules,
|
||||
content_setting_rules_->fingerprinting_rules, frame,
|
||||
url::Origin(frame->GetDocument().GetSecurityOrigin()).GetURL());
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ const char kGetImageDataScript[] =
|
||||
"domAutomationController.send(ctx.getImageData(0, 0, canvas.width, "
|
||||
"canvas.height).data.reduce(adder));";
|
||||
|
||||
const int kExpectedImageDataHashFarblingBalanced = 261040;
|
||||
const int kExpectedImageDataHashFarblingBalanced = 261046;
|
||||
const int kExpectedImageDataHashFarblingOff = 261120;
|
||||
const int kExpectedImageDataHashFarblingMaximum = 127574;
|
||||
|
||||
@@ -303,11 +303,11 @@ class BraveContentSettingsAgentImplBrowserTest : public InProcessBrowserTest {
|
||||
|
||||
// See https://github.com/brave/brave-browser/issues/8937
|
||||
// Fails on Linux
|
||||
// #if defined(OS_LINUX)
|
||||
#if defined(OS_LINUX)
|
||||
#define MAYBE_FarbleGetImageData DISABLED_FarbleGetImageData
|
||||
// #else
|
||||
// #define MAYBE_FarbleGetImageData FarbleGetImageData
|
||||
// #endif
|
||||
#else
|
||||
#define MAYBE_FarbleGetImageData FarbleGetImageData
|
||||
#endif
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(BraveContentSettingsAgentImplBrowserTest,
|
||||
MAYBE_FarbleGetImageData) {
|
||||
@@ -344,8 +344,8 @@ IN_PROC_BROWSER_TEST_F(BraveContentSettingsAgentImplBrowserTest,
|
||||
ExecuteScriptAndExtractInt(contents(), kGetImageDataScript, &hash));
|
||||
EXPECT_EQ(kExpectedImageDataHashFarblingOff, hash);
|
||||
|
||||
// Farbling should be default if 3rd-party fingerpringint is blocked
|
||||
// via content settings and kBraveFingerpringintV2 is disabled
|
||||
// Farbling should be default if 3rd-party fingerprinting is blocked
|
||||
// via content settings and kBraveFingerprintingV2 is disabled
|
||||
BlockThirdPartyFingerprinting();
|
||||
NavigateToPageWithIframe();
|
||||
hash = -1;
|
||||
@@ -354,28 +354,40 @@ IN_PROC_BROWSER_TEST_F(BraveContentSettingsAgentImplBrowserTest,
|
||||
EXPECT_EQ(kExpectedImageDataHashFarblingBalanced, hash);
|
||||
|
||||
// Farbling should be default if fingerprinting is blocked via
|
||||
// content settings and kBraveFingerpringintV2 is disabled
|
||||
// content settings and kBraveFingerprintingV2 is disabled
|
||||
BlockFingerprinting();
|
||||
NavigateToPageWithIframe();
|
||||
hash = -1;
|
||||
EXPECT_TRUE(
|
||||
ExecuteScriptAndExtractInt(contents(), kGetImageDataScript, &hash));
|
||||
EXPECT_EQ(kExpectedImageDataHashFarblingBalanced, hash);
|
||||
}
|
||||
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
scoped_feature_list_.InitAndEnableFeature(
|
||||
class BraveContentSettingsAgentImplV2BrowserTest
|
||||
: public BraveContentSettingsAgentImplBrowserTest {
|
||||
public:
|
||||
void SetUp() override {
|
||||
scoped_feature_list_.InitAndEnableFeature(
|
||||
brave_shields::features::kFingerprintingProtectionV2);
|
||||
BraveContentSettingsAgentImplBrowserTest::SetUp();
|
||||
}
|
||||
|
||||
// Farbling should be default when kBraveFingerpringintV2 is enabled
|
||||
private:
|
||||
base::test::ScopedFeatureList scoped_feature_list_;
|
||||
};
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(BraveContentSettingsAgentImplV2BrowserTest,
|
||||
MAYBE_FarbleGetImageData) {
|
||||
// Farbling should be default when kBraveFingerprintingV2 is enabled
|
||||
// because it uses a different content setting
|
||||
NavigateToPageWithIframe();
|
||||
hash = -1;
|
||||
int hash = -1;
|
||||
EXPECT_TRUE(
|
||||
ExecuteScriptAndExtractInt(contents(), kGetImageDataScript, &hash));
|
||||
EXPECT_EQ(kExpectedImageDataHashFarblingBalanced, hash);
|
||||
|
||||
// Farbling should be maximum if finerprinting is blocked via content settings
|
||||
// and kBraveFingerpringintV2 is enabled
|
||||
// Farbling should be maximum if fingerprinting is blocked via content
|
||||
// settings and kBraveFingerprintingV2 is enabled
|
||||
BlockFingerprinting();
|
||||
NavigateToPageWithIframe();
|
||||
hash = -1;
|
||||
@@ -384,7 +396,7 @@ IN_PROC_BROWSER_TEST_F(BraveContentSettingsAgentImplBrowserTest,
|
||||
EXPECT_EQ(kExpectedImageDataHashFarblingMaximum, hash);
|
||||
|
||||
// Farbling should be balanced if fingerprinting is default via
|
||||
// content settings and kBraveFingerpringintV2 is enabled
|
||||
// content settings and kBraveFingerprintingV2 is enabled
|
||||
SetFingerprintingDefault();
|
||||
NavigateToPageWithIframe();
|
||||
hash = -1;
|
||||
@@ -393,7 +405,7 @@ IN_PROC_BROWSER_TEST_F(BraveContentSettingsAgentImplBrowserTest,
|
||||
EXPECT_EQ(kExpectedImageDataHashFarblingBalanced, hash);
|
||||
|
||||
// Farbling should be off if fingerprinting is allowed via
|
||||
// content settings and kBraveFingerpringintV2 is enabled
|
||||
// content settings and kBraveFingerprintingV2 is enabled
|
||||
AllowFingerprinting();
|
||||
NavigateToPageWithIframe();
|
||||
hash = -1;
|
||||
|
||||
Reference in New Issue
Block a user