New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.
Starred by 10 users

Issue metadata

Status: WontFix
Owner:
Closed: Dec 2014
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: ----
Pri: 1
Type: Bug


Participants' hotlists:
HSTS-History-Sniffing


Sign in to add a comment
link

Issue 436451: Remote websites can know which HSTS enabled websites the users have visited

Reported by imfaster...@gmail.com, Nov 25 2014

Issue description

VULNERABILITY DETAILS
If we ask Chrome to load http://example.com:443, it will definitely fail, because Chrome will make plain-text HTTP request to port 443 of the server. However, if example.com is a Known HSTS Host of Chrome (meaning either the user has visited https://example.com before, or it is on the HSTS preload list), it will send request to https://example.com:443, and the request will succeed. We can use JavaScript to differentiate the two cases, since in the first case, onerror event is triggered, while in the second case, onload event is triggered.

Therefore, a malicious website can include well-chosen cross-domain images and use this trick to brute-force a list of domains that users have visited. Note that the list could only contain HSTS-enabled but not preloaded websites.

One possible fix I can think of is to always treat http://example.com:443 as  https://example.com:443 regardless of whether HSTS is set or not, while other ports are unaffected. 443 is reserved for HTTPS anyway.

VERSION
Chrome Version: [39.0.2171.65] + [stable]
Operating System: Windows 8.1

REPRODUCTION CASE
Just use Chrome to open the attached file, HSTSpoc.html.
 
HSTSpoc.html
1.8 KB View Download

Comment 1 by kenrb@chromium.org, Nov 25 2014

Labels: Security_Severity-Low Pri-2 Security_Impact-Stable
Owner: palmer@chromium.org
Status: Assigned
There has been discussion about browsing history leakage via HSTS in the past, and I believe certain risks are inherent in the spec. This is mentioned in  issue 33445 .

palmer: The suggested improvement is interesting, but I am not sure it would really help. WDYT?

Comment 2 by imfaster...@gmail.com, Nov 25 2014

Thank you for your reply! I read  issue 33445 , but I believe my report is quite different from that. What  issue 33445  describes is that websites can use one subdomain of a HSTS enabled host to store 1 bit of data, so that HSTS can be used as cookie in order to track users. However this issue is about the leak of information. The major difference is that in  issue 33445 , a website can only know if the users have visited his own website. What I propose is that a website can know if users have visited any specific HSTS-enabled non-preloaded websites, which is quite similar to the CSS :visited issue [1].

I'm not sure if this is inherent from the spec, but it seems to me that it's a vulnerability in Chrome's way of parsing the URL like "http://example:443". If Chrome always treats it as a https request (may be against some spec), then this issue is gone, because I can no longer use onerror, onload to differentiate http and https requests.

[1] https://hacks.mozilla.org/2010/03/privacy-related-changes-coming-to-css-vistited/

Comment 3 by imfaster...@gmail.com, Nov 25 2014

Of course, another way to fix is to always throw an error whenever the browser encounters a http link that explicitly specifies port 443. I see neither of two methods will cause compatibility issue, because it's really unlikely that some people use the well-known 443 port to do http connections.

Comment 4 by palmer@chromium.org, Nov 26 2014

Cc: lgar...@chromium.org cbentzel@chromium.org battre@chromium.org
Labels: Cr-Privacy Cr-Internals-Network-SSL
The problem is indeed more like the CSS :visited thing than the ever-cookie thing. Both of the proposed fixes seem potentially workable to me. lgarron, any interest in taking this one on?

battre, cbentzel: Any opinions?

Comment 5 by lgar...@chromium.org, Nov 26 2014

Yep, definitely looks like the CSS :visited problem (the proof of concept works for me). Clever.
I care about HSTS and am about to start URL normalization work, so this definitely sounds relevant.

Serving HTTP over port 443 is definitely possible right now (`sudo python -m SimpleHTTPServer 443` works in Chrome just like any other port).
Are there any legitimate use cases for it? Testing? Workarounds for proxies?

The HSTS spec already has special cases for ports 80 and 443: http://tools.ietf.org/html/rfc6797#section-8.3
As long as there is no other precedent/guidance, either fix sounds sensible.

--------------------------------

As long as there are no/few legitimate use cases, I think blocking HTTP over 443 is cleaner: no new magical rewriting rules, just blocked requests (which are a common failure mode).

How about this?
- Block HTTP requests over port 443.
- Log how many requests are blocked by the code (for opted-in UMA users).
- Carefully watch the stats. Also announce the change and see if people report legitimate, unfixable breakage.
- If there are problems, change to rewrite instead of blocking.

--------------------------------

The proof of concept also works in Firefox, so it's not just Chrome.
I suppose we don't have to implement the same fix if it's not in any spec, but is there a usual plan for coordination/timeline/disclosure?

Comment 6 by lgar...@chromium.org, Nov 26 2014

Setting to medium severity, given that http://www.chromium.org/developers/severity-guidelines explicitly lists this as an example: "Bug that allows an attacker to enumerate recently visited URLs."

Arguably, this doesn't affect all sites.
But I presume it affects sites with a strong tendency to value user privacy, and we want HSTS to be a good value proposition for them (even if they're not on the preload list [yet] – and they wouldn't be able to get on the preload list before we can fix this, either way).

Comment 7 by lgar...@chromium.org, Nov 26 2014

Labels: -Security_Severity-Low Security_Severity-Medium

Comment 8 by lgar...@chromium.org, Nov 26 2014

Labels: -Pri-2 Pri-1
Also changing to Priority 1, to match the severity guidelines.

Comment 9 by lgar...@chromium.org, Nov 26 2014

Adding davidben@ for input from networking about the choices. (I also pinged rsleevi@ separately.)

Here's a possible fix based on redirect suggestion: https://codereview.chromium.org/764473002/

Comment 10 by battre@chromium.org, Nov 26 2014

Cc: mkwst@chromium.org
+mkwst FYI.

I think that the proposal in #5 sounds good. Please make sure to document in the code why we decided to blog HTTP over port 443. ;-) I wonder whether we should have a "This page has been blocked to protect your privacy and work around  crbug.com/436451 . If you really need this, start Chrome with parameter --foobar".

Comment 11 Deleted

Comment 12 by imfaster...@gmail.com, Nov 26 2014

I largely agree with #5 as well. But how about just only blocking cross-domain HTTP requests on port 443, while allowing base html pages and same-domain resources? Of course, totally blocking http on 443 seems fine for me as well.

And yes, this issue exists in Firefox as well, and I have privately reported it to Mozilla.

Comment 13 by lgar...@chromium.org, Nov 26 2014

I talked with rsleevi@, and realized we didn't articulate why this is different from fingerprinting.

If you own 1.example.com, 2.example.com, etc, you can make calls to https://#.example.com/setHSTS that returns an HSTS header, and then query http://#.example.com/get to see if you get an HTTP or an HTTPS response (don't redirect, send different responses based on the scheme).

However, this issue describes a way to determine if someone has visited a non-preloaded HSTS site:
1) trivially and reliably (just check an error code, no need to do something like timing, no need to rely on a rarer feature like CORS misconfiguration or CSP:  https://crbug.com/313737  and  https://crbug.com/366251 ), and
2) even (especially!) if the site in question is following best practices.

So long as we haven't completely given up on the "I know what sites you visited last summer" battle, this issue sounds worth fixing to me.
(Whereas the fingerprinting battle is explicitly lost: http://www.chromium.org/Home/chromium-security/security-faq#TOC-Why-isn-t-passive-browser-fingerprinting-including-passive-cookies-in-Chrome-s-threat-model- .)

Blocking cross-domain HTTP requests over port 443 (at least for <img> sources, but might as well do it for anything) sounds like a reasonable compromise, but I don't know how easy that would be.

Comment 14 by lgar...@chromium.org, Nov 27 2014

Cc: davidben@chromium.org
Actually adding davidben@ now.

Comment 15 by imfaster...@gmail.com, Nov 29 2014

After reconsidering this issue, I changed my mind. Now I think it's better to completely block HTTP requests over 443. The reason is that RFC 3986 section 7.2 says:
   Applications should prevent dereference of a URI that specifies a TCP
   port number within the "well-known port" range (0 - 1023) unless the
   protocol being used to dereference that URI is compatible with the
   protocol expected on that well-known port.

The spec explicitly requires UA to block non-compatible well-known ports. If some people really use port 443 for the purpose other than HTTPS, it's better to break them now, rather than causing problems in the future.

[1] https://tools.ietf.org/html/rfc3986#section-7.2

Comment 16 by kenrb@chromium.org, Dec 1 2014

Labels: M-41

Comment 17 by lgar...@chromium.org, Dec 2 2014

Owner: lgar...@chromium.org
Assigning to myself, since I've been working on it.

(I'm currently in some pretty heavy debugging to figure out how to block port 443 properly for non-HTTPS protocols.)

Comment 18 by lgar...@chromium.org, Dec 4 2014

Labels: -Restrict-View-SecurityTeam
I'm making this bug public in preparation for announcing https://crrev.com/770343003 on a few mailing lists.

This is certainly not urgent enough for a merge to stable, so the information would be out for a while, anyhow.
There's also a public Bugzilla bug about this, so the technique is nominally public already: https://bugzilla.mozilla.org/show_bug.cgi?id=1090433

Comment 19 by bugdroid1@chromium.org, Dec 5 2014

Project Member
The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/b6cf19c7b9dd536405c3c4f80876411733c9d5a5

commit b6cf19c7b9dd536405c3c4f80876411733c9d5a5
Author: lgarron <lgarron@chromium.org>
Date: Fri Dec 05 02:08:19 2014

Block port 443 for all protocols other than HTTPS or WSS.

This addresses the history leak (on non-preloaded HSTS sites) from  https://crbug.com/436451 :

  "If we ask Chrome to load http://example.com:443, it will definitely fail, because Chrome will make plain-text HTTP request to port 443 of the server. However, if example.com is a Known HSTS Host of Chrome (meaning either the user has visited https://example.com before, or it is on the HSTS preload list), it will send request to https://example.com:443, and the request will succeed. We can use JavaScript to differentiate the two cases, since in the first case, onerror event is triggered, while in the second case, onload event is triggered.

  Therefore, a malicious website can include well-chosen cross-domain images and use this trick to brute-force a list of domains that users have visited. Note that the list could only contain HSTS-enabled but not preloaded websites."

BUG= 436451 

Review URL: https://codereview.chromium.org/770343003

Cr-Commit-Position: refs/heads/master@{#306959}

[modify] http://crrev.com/b6cf19c7b9dd536405c3c4f80876411733c9d5a5/net/base/net_util.cc
[modify] http://crrev.com/b6cf19c7b9dd536405c3c4f80876411733c9d5a5/net/base/net_util.h
[modify] http://crrev.com/b6cf19c7b9dd536405c3c4f80876411733c9d5a5/net/http/http_stream_factory_impl_job.cc
[modify] http://crrev.com/b6cf19c7b9dd536405c3c4f80876411733c9d5a5/net/url_request/url_request_unittest.cc

Comment 20 by lgar...@chromium.org, Dec 5 2014

Note: The previous fix doesn't completely address the problem; HTTP over port 80 is blocked by default, but HSTS still redirects. I *thought* I had tested it against the proof of concept, but I must have tested against a different fix.

The remaining part is looking bigger than I thought (adding a condition inside URLRequest::GetHSTSRedirect), so I'll have to get to it later.

Comment 21 by jsc...@chromium.org, Dec 5 2014

Cc: jsc...@chromium.org
Labels: -Security_Severity-Medium -Security_Impact-Stable
I don't see a legitimate argument that this is a vulnerability, because unless I'm missing something significant, the issue here is already known. That is, HSTS can leak the fact that a given origin has been previously visited, which is a very coarse piece of information and of limited value.

By contrast, CSS :visited disclosed the visited details of whatever URL the attacker chose. And timing measurement still provides a more granular enumeration than the described HSTS approach, with effectively 100% reliability (e.g. http://lcamtuf.coredump.cx/cachetime/) and enumeration of login state for most sites.

My suggestion is WontFix and revert that CL, since blocking this kind of enumeration isn't a tractable problem on the Web as it currently exists.

Comment 22 by imfaster...@gmail.com, Dec 5 2014

Sometimes the domain name itself is valuable to attackers. For instance, people don't want others to know they have visited porn sites. *.xxx domain itself reveals the fact. More importantly, this bug harms the reputation of HSTS. Some sensitive websites will therefore disable HSTS to protect their uses from being tracked by other sites.

Comment 23 by lgar...@chromium.org, Dec 5 2014

From docs/asking around, I gathered that while we've given up the war on fingerprinting, we still care about something like this (which is certainly trivial and deterministic). I also didn't find anyone who has particular concerns about blocking HTTP over port 443.

If we don't think this fix is warranted, we should update the severity guidelines/Chromium security FAQs with more detail about what kind of history leaks we consider unmitigatable.

And we should have something to say to people who would like HSTS to be pretty much an unconditionally good thing for protecting users. (Answers might include "we consider such history leaks just as trivial without HSTS" or "get on the preload list".)

Comment 24 by jsc...@chromium.org, Dec 5 2014

I'm sorry, but I think there's too much generalization going on here, rather than focusing on the concrete details of this report. The fact is that this cannot be used to "enumerate recently visited URLs" (many bits). The only information that it provides is whether a user retrieved at least one resource from a given origin (one bit per HSTS origin). Simply put, that information is so coarse as to not be of much use to an attacker, and far more detailed history information can be trivially obtained via resource load timing (a fast, reliable approach that we cannot prevent).

My point here is that changing the behavior identified in this report won't do anything to prevent the same or greater information disclosure by readily available means. And we've already accepted the current state as an inherent deficiency of the platform. Moreover, HSTS's potential as a single-bit oracle was already known, which is why we don't retain HSTS state received in incognito sessions. So, unless there's a fix that addresses the larger problem regarding cross origin history probing, I don't see any point in violating the standard to break this narrow case.

Comment 25 by imfaster...@gmail.com, Dec 5 2014

Which standard does it violate to block HTTP over port 443? As I stated in post #15, not blocking violates the spec.
   Applications should prevent dereference of a URI that specifies a TCP
   port number within the "well-known port" range (0 - 1023) unless the
   protocol being used to dereference that URI is compatible with the
   protocol expected on that well-known port.

I don't think HTTP is compatible with port 443.

Comment 26 by jsc...@chromium.org, Dec 5 2014

Labels: -Type-Bug-Security -Cr-Internals-Network-SSL Type-Bug Cr-Internals-Network Cr-Security
Summary: Only HTTPS transports (including WSS) should be allowed to port 443 (was: Security: Remote websites can know which HSTS enabled websites the users have visited)
Okay, the advisory component of RFC 3986 can certainly be read to supersede the port mapping requirement in RFC 6797. So, I'm fine with landing a patch that correctly blocks HTTP to port 443, regardless of whether or not HSTS is enabled. However, that's a spec compliance issue and still does nothing significant to address history enumeration. So, I'll fix the title and flags, and lucas should land a fix for his patch.

Comment 27 by cbentzel@chromium.org, Dec 6 2014

#26: Seems like you'd want to change this to only allow schemes to go to ports > 1023 or their assigned IANA port if <= 1023 to match RFC3986?

I'm mildly concerned about compat issues with that. Agree that the potential privacy leak of this HSTS approach compared to other approaches is not terribly significant, and if security win of being that restrictive also not too high that this may not be worth it.

Comment 28 by battre@chromium.org, Dec 8 2014

@ #24: Do we have a document like http://www.chromium.org/Home/chromium-security/client-identification-mechanisms that outlines the currently existing paths to explain whether a user has visited a specific domain across origins?

Comment 29 by jsc...@chromium.org, Dec 8 2014

Comment 30 by lgar...@chromium.org, Dec 8 2014

So, after talking with Justin on Friday, and looking more into the timing attack website, I've been convinced that timing attacks are in fact basically as easy and reliable as this particular vector.

This leaves me with no security argument for blocking HTTP over port 443, so I'm going to revert the change for now. If we think we should re-introduce it (e.g. because it helps avoids bugs or something like that), at least we have the code for it.

Comment 31 by phistuck@gmail.com, Dec 8 2014

I think this should be done (not reverted) anyway - the specification asks for it.

Comment 32 by mmenke@chromium.org, Dec 8 2014

Another reason to revert:  Port 443 is also often used for websockets, to circumvent broken "transparent" proxies that break websockets.

See  issue 439797 .

Comment 33 by bugdroid1@chromium.org, Dec 8 2014

Project Member
The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/3e9300a62343005f995db4a6a72728381993081f

commit 3e9300a62343005f995db4a6a72728381993081f
Author: lgarron <lgarron@chromium.org>
Date: Mon Dec 08 21:28:46 2014

Revert of Block port 443 for all protocols other than HTTPS or WSS. (patchset #7 id:120001 of https://codereview.chromium.org/770343003/)

Reason for revert:
Unfortunately, this fix didn't do enough to mitigate the original problem (it's easy to tell if a site has been visited).

It's also incomplete on its own (i.e. it needs further changes to prevent the HSTS redirect).

See  https://crbug.com/436451#c30 

Original issue's description:
> Block port 443 for all protocols other than HTTPS or WSS.
>
> This addresses the history leak (on non-preloaded HSTS sites) from  https://crbug.com/436451 :
>
>   "If we ask Chrome to load http://example.com:443, it will definitely fail, because Chrome will make plain-text HTTP request to port 443 of the server. However, if example.com is a Known HSTS Host of Chrome (meaning either the user has visited https://example.com before, or it is on the HSTS preload list), it will send request to https://example.com:443, and the request will succeed. We can use JavaScript to differentiate the two cases, since in the first case, onerror event is triggered, while in the second case, onload event is triggered.
>
>   Therefore, a malicious website can include well-chosen cross-domain images and use this trick to brute-force a list of domains that users have visited. Note that the list could only contain HSTS-enabled but not preloaded websites."
>
> BUG= 436451 
>
> Committed: https://crrev.com/b6cf19c7b9dd536405c3c4f80876411733c9d5a5
> Cr-Commit-Position: refs/heads/master@{#306959}

TBR=davidben@chromium.org,phistuck@gmail.com,mmenke@chromium.org
NOTREECHECKS=true
NOTRY=true
BUG= 436451 

Review URL: https://codereview.chromium.org/780943003

Cr-Commit-Position: refs/heads/master@{#307340}

[modify] http://crrev.com/3e9300a62343005f995db4a6a72728381993081f/net/base/net_util.cc
[modify] http://crrev.com/3e9300a62343005f995db4a6a72728381993081f/net/base/net_util.h
[modify] http://crrev.com/3e9300a62343005f995db4a6a72728381993081f/net/http/http_stream_factory_impl_job.cc
[modify] http://crrev.com/3e9300a62343005f995db4a6a72728381993081f/net/url_request/url_request_unittest.cc

Comment 34 by lgar...@chromium.org, Dec 9 2014

Status: WontFix
Summary: Remote websites can know which HSTS enabled websites the users have visited (was: Only HTTPS transports (including WSS) should be allowed to port 443 )
I'm changing the bug title back and marking as WontFix for now.
Makes me sad, but 1) it seems to me that Justin is right about the futility of preventing origin-level leakage, and 2)  issue #439797  is already one use case this would break. (I've asked for more feedback about this in #439797.)

If we want to block HTTP over port 443 for more compelling reasons, I think it should go in a new issue.
(And if that happens, I'll follow up and make sure it mitigates this HSTS issue.)

Sign in to add a comment