Bug 207207

Summary: Make WKWebView._negotiatedLegacyTLS accurate when loading main resouorce from network or cache
Product: WebKit Reporter: Alex Christensen <achristensen>
Component: New BugsAssignee: Alex Christensen <achristensen>
Status: RESOLVED FIXED    
Severity: Normal CC: benjamin, cdumez, cgarcia, cmarcelo, dbates, ews-watchlist, ggaren, koivisto, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
cdumez: review+
patch without affecting cache achristensen: review-, achristensen: commit-queue-

Description Alex Christensen 2020-02-04 09:46:11 PST
Fix race condition for WKWebView._negotiatedLegacyTLS when loading main resouorce
Comment 1 Alex Christensen 2020-02-04 10:13:24 PST
Created attachment 389676 [details]
Patch
Comment 2 Radar WebKit Bug Importer 2020-02-04 10:21:29 PST
<rdar://problem/59153742>
Comment 3 Alex Christensen 2020-02-04 12:00:53 PST
Created attachment 389688 [details]
Patch
Comment 4 Alex Christensen 2020-02-04 12:43:19 PST
Created attachment 389692 [details]
Patch
Comment 5 Alex Christensen 2020-02-04 13:50:24 PST
Created attachment 389699 [details]
Patch
Comment 6 Alex Christensen 2020-02-04 14:03:06 PST
Created attachment 389704 [details]
Patch
Comment 7 Alex Christensen 2020-02-04 14:51:05 PST
Created attachment 389713 [details]
Patch
Comment 8 Chris Dumez 2020-02-04 15:16:41 PST
Comment on attachment 389713 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=389713&action=review

> Source/WebCore/platform/network/ResourceResponseBase.h:285
> +    uint8_t isRedirectedAndUsedLegacyTLS = (m_isRedirected ? 0x1 : 0x0) | (m_usedLegacyTLS == UsedLegacyTLS::Yes ? 0x2 : 0x0);

Can we please avoid obscure code like this simply to encode a boolean? I'm really not convinced the extra complexity is worth the very slight saving of data sent over IPC.

> Source/WebKit/NetworkProcess/NetworkLoad.cpp:236
> +        response.includeCertificateInfo(negotiatedLegacyTLS == NegotiatedLegacyTLS::Yes ? UsedLegacyTLS::Yes : UsedLegacyTLS::No);

Do we really need both NegotiatedLegacyTLS and UsedLegacyTLS?
Comment 9 Alex Christensen 2020-02-04 15:33:59 PST
(In reply to Chris Dumez from comment #8)
> Comment on attachment 389713 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=389713&action=review
> 
> > Source/WebCore/platform/network/ResourceResponseBase.h:285
> > +    uint8_t isRedirectedAndUsedLegacyTLS = (m_isRedirected ? 0x1 : 0x0) | (m_usedLegacyTLS == UsedLegacyTLS::Yes ? 0x2 : 0x0);
> 
> Can we please avoid obscure code like this simply to encode a boolean? I'm
> really not convinced the extra complexity is worth the very slight saving of
> data sent over IPC.
This isn't about IPC.  This is about reading from existing disk caches.  I did not think this was enough to increment the disk cache version.
 
> > Source/WebKit/NetworkProcess/NetworkLoad.cpp:236
> > +        response.includeCertificateInfo(negotiatedLegacyTLS == NegotiatedLegacyTLS::Yes ? UsedLegacyTLS::Yes : UsedLegacyTLS::No);
> 
> Do we really need both NegotiatedLegacyTLS and UsedLegacyTLS?
We need something in WebCore, and I'm trying to make this patch as easy to merge as possible.  I'll clean this up with one type with its own header after landing.
Comment 10 Chris Dumez 2020-02-04 15:59:11 PST
Comment on attachment 389713 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=389713&action=review

>>> Source/WebCore/platform/network/ResourceResponseBase.h:285
>>> +    uint8_t isRedirectedAndUsedLegacyTLS = (m_isRedirected ? 0x1 : 0x0) | (m_usedLegacyTLS == UsedLegacyTLS::Yes ? 0x2 : 0x0);
>> 
>> Can we please avoid obscure code like this simply to encode a boolean? I'm really not convinced the extra complexity is worth the very slight saving of data sent over IPC.
> 
> This isn't about IPC.  This is about reading from existing disk caches.  I did not think this was enough to increment the disk cache version.

Still, I do not like the added complexity. I'd still prefer bumping the cache version. One alternative: Do we really need to save this bit to the disk cache, or is IPC encoding/decoding sufficient?
Comment 11 Alex Christensen 2020-02-04 16:18:11 PST
Created attachment 389734 [details]
Patch
Comment 12 Geoffrey Garen 2020-02-04 16:28:00 PST
Comment on attachment 389734 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=389734&action=review

> Source/WebKit/ChangeLog:18
> +        In order to maintain binary compatibility with existing disk caches, I bundle two booleans together
> +        when encoding.  This results in existing disk caches saying they loaded nothing over legacy TLS,
> +        which is somewhat correct because TLS 1.0 and 1.1 were not deprecated when the resources were fetched.
> +        Going forward, the bit will be set and the disk cache entries will store whether they were loaded
> +        over legacy TLS.

This isn't true in the newest patch.

Also, this is a separate change that is unrelated to the race condition you're trying to fix. Can you make two separate patches? The choice for what's right for the disk cache probably deserves some discussion, and the fix for the race condition need not wait on that discussion.
Comment 13 Alex Christensen 2020-02-04 16:37:29 PST
Created attachment 389740 [details]
Patch
Comment 14 Alex Christensen 2020-02-04 16:39:31 PST
(In reply to Geoffrey Garen from comment #12)
> Comment on attachment 389734 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=389734&action=review
> 
> > Source/WebKit/ChangeLog:18
> > +        In order to maintain binary compatibility with existing disk caches, I bundle two booleans together
> > +        when encoding.  This results in existing disk caches saying they loaded nothing over legacy TLS,
> > +        which is somewhat correct because TLS 1.0 and 1.1 were not deprecated when the resources were fetched.
> > +        Going forward, the bit will be set and the disk cache entries will store whether they were loaded
> > +        over legacy TLS.
> 
> This isn't true in the newest patch.
You're right.  I updated the changelog to reflect the changes that were made in the updated patch.
> 
> Also, this is a separate change that is unrelated to the race condition
> you're trying to fix. Can you make two separate patches? The choice for
> what's right for the disk cache probably deserves some discussion, and the
> fix for the race condition need not wait on that discussion.

The title was indeed misleading, so I changed it.  This patch fixes the actual problem which was that users observe _negotiatedLegacyTLS to be incorrectly false because of a race condition and because of the disk cache.  Luckily the same code fixes both: the ResourceResponseBase serialization code.
Comment 15 Alex Christensen 2020-02-04 16:46:04 PST
Created attachment 389744 [details]
Patch
Comment 16 Alex Christensen 2020-02-04 17:07:05 PST
Created attachment 389748 [details]
Patch
Comment 17 Alex Christensen 2020-02-04 17:21:27 PST
Created attachment 389750 [details]
Patch
Comment 18 Alex Christensen 2020-02-04 18:00:32 PST
Created attachment 389756 [details]
Patch
Comment 19 Geoffrey Garen 2020-02-05 10:23:50 PST
You’ve made an important discover: We didn’t previously consider the http cache.

Given that discovery, I’d like you to facilitate a discussion about how the http cache should interact with the legacy TLS warning.

Some questions I have for that discussion:

1. If an existing cache entry was loaded over unknown or legacy TLS, and then the user updates WebKit, should WebKit evict that cache entry, load it and show it as insecure, load it and show it as secure, or select a behavior based on whether a new connection to the server yields modern TLS?

2. If an existing cache entry was loaded over unknown or legacy TLS, and then the server updates to modern TLS…. { Same questions as 1 }?

3. Is it accurate to say that a connection to a server is insecure when, in fact, no connection to the server has been made (and the connection, if made, might be secure)?

4. What do other browsers do?

5. Is it acceptable to pay the cost of evicting all caches worldwide in order to get the behavior we want here?

6. Should we put a cap on the lifetime of legacy TLS resources in the cache, to avoid the case where a long-lived resource never gets upgraded to modern TLS?
Comment 20 Alex Christensen 2020-02-05 11:07:23 PST
(In reply to Geoffrey Garen from comment #19)
> You’ve made an important discover: We didn’t previously consider the http
> cache.
> 
> Given that discovery, I’d like you to facilitate a discussion about how the
> http cache should interact with the legacy TLS warning.
> 
> Some questions I have for that discussion:
> 
> 1. If an existing cache entry was loaded over unknown or legacy TLS, and
> then the user updates WebKit, should WebKit evict that cache entry, load it
> and show it as insecure, load it and show it as secure, or select a behavior
> based on whether a new connection to the server yields modern TLS?
This will remove all existing cache entries, so this question is invalid.

> 2. If an existing cache entry was loaded over unknown or legacy TLS, and
> then the server updates to modern TLS…. { Same questions as 1 }?
The only mechanism for this is the existing mechanism for if they change the content on their server, at which point the cache will be updated.  Other than that, we can't know what the server does if we don't connect to the server.

> 3. Is it accurate to say that a connection to a server is insecure when, in
> fact, no connection to the server has been made (and the connection, if
> made, might be secure)?
We want our users to consistently see that a web page has negotiated legacy TLS, whether it is loaded from the server or from the cache.  We already have people wondering why it is sometimes true and sometimes false for the same site, and that is the problem to be fixed by this patch.

> 4. What do other browsers do?
There is no precedent, and this is intentionally different than their stated plans.

> 5. Is it acceptable to pay the cost of evicting all caches worldwide in
> order to get the behavior we want here?
I thought it was not, but responding to Chris's review feedback I did it.

> 6. Should we put a cap on the lifetime of legacy TLS resources in the cache,
> to avoid the case where a long-lived resource never gets upgraded to modern
> TLS?
No.
Comment 21 Alex Christensen 2020-02-05 11:23:49 PST
Created attachment 389833 [details]
patch without affecting cache
Comment 22 Alex Christensen 2020-02-05 11:37:35 PST
I feel an urgency to land this. If you feel it would be better to not affect the cache and respond to users' visible inconsistency on the same page later, feel free to review that patch.
Comment 23 Chris Dumez 2020-02-05 11:42:30 PST
Comment on attachment 389756 [details]
Patch

r=me
Comment 24 Geoffrey Garen 2020-02-05 12:41:00 PST
I'm OK with landing this patch.

It seems like we do need to blow away existing cache entries. Otherwise, the behavior of our insecure warning will be inconsistent and confusing, with some users getting the warning and some not, depending on pre-existing cache state. Also wouldn't be great to load an insecure resource from the cache and call it secure.

I do think we should consider limiting the lifetime of legacy TLS resources in the disk cache, or not storing them at all. A long-lived legacy TLS resource in the disk cache makes it much harder for a website to upgrade to modern TLS, since it will need not only to start supporting modern TLS but also to rename a lot resources to prevent pulling old resources from the cache. And it feels like an own goal to keep loading an insecure resource when a secure resource is available.
Comment 25 Alex Christensen 2020-02-05 13:08:07 PST
https://trac.webkit.org/changeset/255846/webkit
Comment 26 Chris Dumez 2020-02-05 14:57:09 PST
Follow-up build fix: <https://trac.webkit.org/changeset/255863>
Comment 27 Chris Dumez 2020-02-05 16:56:43 PST
(In reply to Chris Dumez from comment #26)
> Follow-up build fix: <https://trac.webkit.org/changeset/255863>

And another build fix: <https://trac.webkit.org/changeset/255880>