@@ -32,6 +32,7 @@ Ignored Vars: identifier, i
3232<pre class=link-defaults>
3333spec:css-values-4; type:dfn; text:identifier
3434spec:css-display-3; type:property; text:display
35+ spec:css-display-4; type:property; text:visibility
3536spec:css-pseudo-4; type:selector;
3637 text: ::before
3738 text: ::after
@@ -2136,10 +2137,11 @@ The Hyperlink Pseudo-class: '':any-link''</h3>
21362137<h3 id="link">
21372138The Link History Pseudo-classes: '':link'' and '':visited''</h3>
21382139
2139- User agents commonly display unvisited <a href="#the-any-link-pseudo">hyperlinks</a> differently from
2140- previously visited ones. Selectors
2141- provides the pseudo-classes <dfn id='link-pseudo'>:link</dfn> and
2142- <dfn id='visited-pseudo'>:visited</dfn> to distinguish them:
2140+ User agents commonly display unvisited [[#the-any-link-pseudo|hyperlinks]]
2141+ differently from previously visited ones.
2142+ Selectors provides the pseudo-classes
2143+ <dfn id='link-pseudo'>:link</dfn> and <dfn id='visited-pseudo'>:visited</dfn>
2144+ to distinguish them:
21432145
21442146 <ul>
21452147 <li> The '':link'' pseudo-class applies to links that have
@@ -2148,23 +2150,53 @@ The Link History Pseudo-classes: '':link'' and '':visited''</h3>
21482150 been visited by the user.
21492151 </ul>
21502152
2151- After some amount of time, user agents may choose to return a
2152- visited link to the (unvisited) '':link'' state.
2153-
21542153 The two states are mutually exclusive.
21552154
2156- <div class="example">
2157- The following selector represents links carrying class
2158- <code> footnote</code> and already visited:
2155+ After some amount of time,
2156+ user agents may choose to return a visited link
2157+ to the (unvisited) '':link'' state.
2158+
2159+ The '':visited'' pseudo-class comes with obvious privacy implications--
2160+ letting random websites know what <em> other</em> websites you've visited
2161+ can be problematic for a number of reasons--
2162+ and so user agents <em> must</em> preserve user privacy
2163+ in their implementation of '':visited'' .
2164+
2165+ <div class=note>
2166+ This specification intentionally does not specify
2167+ exactly how to preserve user privacy in this regard,
2168+ to allow for user agents to innovate in this space.
2169+ The following methods are suggested, however:
2170+
2171+ * Have '':visited'' never match,
2172+ so all links match '':link'' instead.
2173+ * Carefully track what history entries
2174+ could have been observed by a given origin on their own,
2175+ and only have links match '':visited''
2176+ if that visit would have been observable from the site's origin.
2177+ A possible specific approach for this
2178+ is described in [[#visited-privacy]] .
2179+ * Allow links to match '':visited'' on any origin,
2180+ but carefully restrict what styles they can apply
2181+ and what information is returned by style-querying APIs
2182+ like {{getComputedStyle()}} ,
2183+ to prevent sites from observing
2184+ whether a link is styled with '':link'' or '':visited'' .
2185+ (This is documented at <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Privacy_and_the_:visited_selector">MDN</a&
EF2F
gt; ,
2186+ and was the historical approach browsers took,
2187+ but is not perfect;
2188+ there are several ways for a hostile page
2189+ to still extract history information.)
2190+ </div>
21592191
2160- <pre> .footnote:visited </pre>
2192+ <div class="example">
2193+ For example, the selector ''.footnote:visited''
2194+ would allow styling footnote links differently
2195+ if they've been previously followed,
2196+ allowing users of the page to know
2197+ they might not need to click the footnote again.
21612198 </div>
21622199
2163- Since it is possible for style sheet authors to abuse the :link and :visited pseudo-classes
2164- to determine which sites a user has visited without the user's consent,
2165- UAs may treat all links as unvisited links
2166- or implement other measures to preserve the user's privacy
2167- while rendering visited and unvisited links differently.
21682200
21692201<h3 id="the-local-link-pseudo">
21702202The Local Link Pseudo-class: '':local-link''</h3>
@@ -4199,6 +4231,106 @@ Appendix B: Obsolete but Required <code>-webkit-</code> Parsing Quirks for Web C
41994231 and all right-thinking web developers.
42004232 </details>
42014233
4234+ <h2 id="visited-privacy">
4235+ Appendix C: Example Privacy-Preserving '':visited'' Restrictions</h2>
4236+
4237+ Previous attempts to protect user privacy in '':visited''
4238+ involved <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Privacy_and_the_:visited_selector">complex restrictions and behaviors</a>
4239+ to "lie" about whether the link match '':visited'' or '':link'' ,
4240+ to reduce the chance that a hostile site
4241+ could observe what unrelated sites a user had visited
4242+ while still allowing '':visited'' to work in all cases
4243+ and help the user know what links they'd already clicked.
4244+ This is ultimately an arms race that can't be won;
4245+ there are multiple documented ways to still extract a user's browsing history
4246+ even with these mitigations.
4247+
4248+ This section describes an approach first developed and documented at
4249+ <a href="https://github.com/explainers-by-googlers/Partitioning-visited-links-history">https://github.com/explainers-by-googlers/Partitioning-visited-links-history</a> ,
4250+ that partitions a user's browsing history information,
4251+ to allow '':visited'' to only match links
4252+ corresponding to navigations that the site's origin could have observed on its own.
4253+ W
EF2F
ith this, '':visited'' can be treated as a normal pseudo-class,
4254+ without any of the complex mitigations described above,
4255+ as it doesn't expose any information not already theoretically available to the site,
4256+ while still preserving as much of the <em> usefulness</em> of '':visited'' as possible for the user.
4257+
4258+ 1. Let |visited history| be a [=/set=]
4259+ containing [=tuples=] of three pieces of information:
4260+ * a visited [=/URL=]
4261+ * an [=/origin=] for the site that started a navigation
4262+ * an [=/origin=] for the top-level site containing the frame that started the navigation.
4263+ (This will often be the same as the previous,
4264+ but can differ if the user clicks a link in a iframe, for example.)
4265+
4266+ 2. Whenever a navigation is triggered <em> from within a page</em> --
4267+ e.g.,
4268+ from the user clicking a link,
4269+ or a script on the page initiating a navigation--
4270+ add an entry to |visited history|
4271+ recording the navigation's destination URL,
4272+ the origin of the page containing the link or script,
4273+ and the origin of the top-level site containing that page
4274+ (which might be the same as the previous origin).
4275+
4276+ Note: This allows a site to see '':visited'' information
4277+ for links that the user has clicked
4278+ from anywhere in that site's origin.
4279+ In other words, any <code> A -> B</code> navigation
4280+ where the site is A.
4281+
4282+ Additionally, add an entry to |visited history|
4283+ recording the destination's URL,
4284+ and the <em> destination's</em> origin
4285+ for both origin values.
4286+
4287+ Note: This allows for a site to see '':visited'' information about its own pages
4288+ (which is already observable by the site)
4289+ regardless of what site initiated the navigation to that page.
4290+ In other words, any <code> A -> B</code> navigation
4291+ where the site is B.
4292+
4293+ Note: Notably, direct navigations triggered by the <em> user agent's</em> UI,
4294+ such as typing into the address bar,
4295+ clicking on bookmarks,
4296+ or dragging a link from another program into the page,
4297+ <em> do not</em> add a |visited history| entry.
4298+ These can, of course,
4299+ still add to the browser's record of visited sites
4300+ that it uses for other purposes,
4301+ such as suggesting URLs as the user types into the URL bar.
4302+
4303+ 3. When determining if a link element should match '':link'' or '':visited'' ,
4304+ only allow it to match '':visited'' if
4305+ the link's destination,
4306+ the origin of the page containing the link,
4307+ and the origin of the top-level site containing the link
4308+ match a tuple in |visited history|.
4309+
4310+ <div class=note>
4311+ The inclusion of both page origin and top-level site origin
4312+ prevents several possible privacy attacks,
4313+ such as:
4314+
4315+ * If history entries were <em> only</em> keyed by the starting site's URL,
4316+ a tracking site could be embedded in a hidden iframe on multiple sites
4317+ which triggers a navigation to a unique URL for a user on the first visit,
4318+ and then uses many such links on subsequent visits
4319+ to see which one had been visited,
4320+ effectively becoming a new "third-party cookie"
4321+ identifying the user across the web.
4322+ By keying the history entry with the top-level site,
4323+ this information can't be shared across different sites.
4324+
4325+ * If history entires were <em> only</em> keyed by the top-level site's URL,
4326+ a hostile iframe,
4327+ perhaps included in a page as part of an advertisement,
4328+ could observe what sites were visited from the top-level site.
4329+ By keying the history entry with the link's own site,
4330+ the top-level site's information can't "leak" into cross-origin iframes.
4331+ </div>
4332+
4333+
42024334
42034335<h2 id="changes">
42044336Changes</h2>
0 commit comments