@@ -32,6 +32,7 @@ Ignored Vars: identifier, i
32
32
<pre class=link-defaults>
33
33
spec:css-values-4; type:dfn; text:identifier
34
34
spec:css-display-3; type:property; text:display
35
+ spec:css-display-4; type:property; text:visibility
35
36
spec:css-pseudo-4; type:selector;
36
37
text: ::before
37
38
text: ::after
@@ -2136,10 +2137,11 @@ The Hyperlink Pseudo-class: '':any-link''</h3>
2136
2137
<h3 id="link">
2137
2138
The Link History Pseudo-classes: '':link'' and '':visited''</h3>
2138
2139
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:
2143
2145
2144
2146
<ul>
2145
2147
<li> The '':link'' pseudo-class applies to links that have
@@ -2148,23 +2150,53 @@ The Link History Pseudo-classes: '':link'' and '':visited''</h3>
2148
2150
been visited by the user.
2149
2151
</ul>
2150
2152
2151
- After some amount of time, user agents may choose to return a
2152
- visited link to the (unvisited) '':link'' state.
2153
-
2154
2153
The two states are mutually exclusive.
2155
2154
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> ,
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>
2159
2191
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.
2161
2198
</div>
2162
2199
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.
2168
2200
2169
2201
<h3 id="the-local-link-pseudo">
2170
2202
The Local Link Pseudo-class: '':local-link''</h3>
@@ -4199,6 +4231,106 @@ Appendix B: Obsolete but Required <code>-webkit-</code> Parsing Quirks for Web C
4199
4231
and all right-thinking web developers.
4200
4232
</details>
4201
4233
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
+ With 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
+
4202
4334
4203
4335
<h2 id="changes">
4204
4336
Changes</h2>
0 commit comments