-
Notifications
You must be signed in to change notification settings - Fork 885
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue 3419: Mitigate HSTS fingerprinting #1744
Conversation
e2339a8
to
3620029
Compare
05d87d0
to
221a130
Compare
Note to reviewers: this should match the behavior in https://github.com/brave/browser-laptop/pull/13649/files, minus the behavior where the HSTS cache is cleared on startup. |
221a130
to
69e5c72
Compare
@@ -124,6 +151,10 @@ int BraveNetworkDelegateBase::OnHeadersReceived( | |||
const net::HttpResponseHeaders* original_response_headers, | |||
scoped_refptr<net::HttpResponseHeaders>* override_response_headers, | |||
GURL* allowed_unsafe_redirect_url) { | |||
brave::RemoveTrackableSecurityHeadersForThirdParty(request, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this need to check if (!request)
first?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done!
69e5c72
to
d04c1b7
Compare
057df34
to
824dcbe
Compare
return; | ||
} | ||
if (net::registry_controlled_domains::SameDomainOrHost( | ||
request->url(), request->site_for_cookies(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use request->top_frame_origin()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to site_for_cookies
, top_frame_origin
might not be set every-time. (see: https://cs.chromium.org/chromium/src/net/url_request/url_request.h?type=cs&q=top_frame_origin&sq=package:chromium&g=0&l=290)
I think using GetTabURLFromRenderFrameInfo
might be better. Let me know what you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
site_for_cookies
is intentionally blank for nested 3rdparty frames while top_frame_origin
is not. I think it may be empty for requests that are not related to any frame at all, so we can do nothing in this case.
Basically, the comment about its experimental nature is outdated, since Chromium had a successful experiment based on this value, and it will stay with us
@@ -20,6 +27,18 @@ namespace net { | |||
class URLRequest; | |||
} | |||
|
|||
namespace brave { | |||
const std::unordered_set<std::string> kTrackableSecurityHeaders = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Objects with non-trivial destructors are generally banned by CC (as well as unordered_set
), its better (but a bit wordy) to use static const base::NoDestructor<base::flat_set<base::StringPiece>>
"X-XSS-Protection: 0"; | ||
|
||
scoped_refptr<HttpResponseHeaders> headers( | ||
new HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrong indentation, please clang-format
the whole file
Had only a quick glance, will get back to the PR later today. |
9aba1c0
to
5ad1b0a
Compare
@@ -20,6 +28,17 @@ namespace net { | |||
class URLRequest; | |||
} | |||
|
|||
namespace brave { | |||
static const base::NoDestructor<base::flat_set<base::StringPiece>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From no_destructor.h
: "Furthermore, a NoDestructor should never have global scope as that may require a static initializer"
So i'd suggest to make a function that returns this set, and make NoDestructor
object a static variable in this function.
@@ -20,6 +28,17 @@ namespace net { | |||
class URLRequest; | |||
} | |||
|
|||
namespace brave { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: using namespace here looks inconsistent with other code in this file. Don't really know if it is better to not use it here.
request_url, net::IDLE, &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS); | ||
|
||
request->set_top_frame_origin(url::Origin::Create(tab_url)); | ||
std::string raw_headers = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not make a constant common for all tests?
I would also suggest making a solid browser test, though I understand that this may be time consuming. |
LGTM with nits. |
5ad1b0a
to
ff6f933
Compare
ea1f6b9
to
0d6f72b
Compare
EXPECT_TRUE(redirect_observer.has_sts_header(third_party)); | ||
} | ||
|
||
IN_PROC_BROWSER_TEST_F(BraveNetworkDelegateBaseBrowserTest, ThirdPartySTS) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also add a test checking that nothing is blocked if tracking protection is off
if (iter != sts_header_for_url.end()) { | ||
return iter->second; | ||
} | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can even DCHECK that something is found, otherwise the test can pass if there is a typo in a subframe address, for example.
} | ||
|
||
private: | ||
std::map<GURL, bool> sts_header_for_url; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sts_header_for_url_
const net::HttpResponseHeaders* response = handle->GetResponseHeaders(); | ||
if (response) { | ||
bool has_sts_header = response->HasHeader("Strict-Transport-Security"); | ||
sts_header_for_url.insert( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just sts_header_for_url[handle->GetURL()] = has_sts_header;
or sts_header_for_url.insert({handle->GetURL(), has_std_header});
void DidFinishNavigation(NavigationHandle* handle) override { | ||
const net::HttpResponseHeaders* response = handle->GetResponseHeaders(); | ||
if (response) { | ||
bool has_sts_header = response->HasHeader("Strict-Transport-Security"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: const has_sts_header
, const GURL third_party
, etc
test/BUILD.gn
Outdated
@@ -283,6 +284,7 @@ test("brave_browser_tests") { | |||
"//brave/browser/extensions/brave_extension_functional_test.h", | |||
"//brave/browser/extensions/api/brave_shields_api_browsertest.cc", | |||
"//brave/browser/extensions/api/brave_theme_api_browsertest.cc", | |||
"//brave/browser/net/brave_network_delegate_base_browsertest.cc", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe merge this and the next one? Or give more descriptive names to source files: this one against hsts, etc
0d6f72b
to
5c155b8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
e14dccf
to
71d1158
Compare
71d1158
to
213e919
Compare
HSTS supercookies are a known fingerprinting vector. This change disallow's third parties from setting security headers: 1. "Strict-Transport-Security" 2. "Expect-CT" 3. "Public-Key-Pins" 4. "Public-Key-Pins-Report-Only" that can be used for fingerprinting. auditors: @diracdeltas, @bbondy, @iefremov
213e919
to
80eaac6
Compare
fixes brave/brave-browser#3419
Description
HSTS super-cookies are used as a fingerprinting vector. This change disallow's third parties from setting trackable security headers like "Strict-Transport-Security", "Expect-CT", "Public-Key-Pins", "Public-Key-Pins-Report-Only"
Submitter Checklist:
npm test brave_unit_tests && npm test brave_browser_tests
) ongit rebase master
(if needed).git rebase -i
to squash commits (if needed).Test Plan:
https://avatars2.githubusercontent.com
and disableConnections Encrypted
https://jsfiddle.net
and disableConnections Encrypted
(see: Disabling global HTTPS Everywhere setting does not disable HTTPSEverywhere brave-browser#3424)https://jsfiddle.net/x5mqb807/
and verify thatConnections Encrypted
is disabledavatars2.githubusercontent.com
loads with a 301 redirecthttp://avatars2.githubusercontent.com
, reloadhttp://avatars2.githubusercontent.com
(not https) and verify it loads with a 307 redirecthttps://jsfiddle.net/x5mqb807/
in the first tab and verify the image is loaded with a 307 redirect.Before navigating to
avatars2.githubusercontent.com
:After navigating to
avatars2.githubusercontent.com
:Reviewer Checklist: