New issue
Advanced search Search tips

Issue 891712 link

Starred by 1 user

Issue metadata

Status: Duplicate
Merged: issue 835590
Owner:
Closed: Nov 24
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Android , Windows , Chrome , Mac , Fuchsia
Pri: 1
Type: Bug-Security



Sign in to add a comment

Security: Visited Links Leak

Reported by va...@marylab.com, Oct 3

Issue description

VULNERABILITY DETAILS
By applyng linear-gradient or radial-gradient to the "a" element, javascript can determine whether a given URL has been visited or not by evaluating the speed of rendering single color gradient vs multiple colors gradient when one is used for not visited URL and another for visited.

The method is almost 100% efficient, but it can be tweaked for a specific platform and CPU.

VERSION
Chrome Version: 69.0.3497.100 (Official Build) (64-bit) [stable]
and 71.0.3569.0 (Official Build) canary (64-bit)
Operating System: macOS 10.13.6, MacBook Pro (Retina, 15-inch, Mid 2015), 2,2 GHz Intel Core i7

Chrome Version: 69.0.3497.100 (Official Build) (32-bit) [stable]
Operating System: Windows 8.1

Chrome Version: 69.0.3497.100
Operating System: Android 5.1.1; Nexus 4

REPRODUCTION CASE
See attached .html file. Also attaching a screenshot with the results.
 
bb.html
2.5 KB View Download
Screen Shot 2018-10-03 at 18.03.43.png
63.0 KB View Download
Components: Blink>Paint
Labels: Security_Severity-Medium Security_Impact-Stable OS-Android OS-Chrome OS-Fuchsia OS-Linux OS-Mac OS-Windows
Owner: fmalita@chromium.org
Status: Assigned (was: Unconfirmed)
Thank you for the report. I seem to be able to repro this, but the PoC runs slow as expected.

Assigning medium severity based on our severity guidelines, but it might be debated how reliable this method is, given that it relies on timing.

fmalita: Can you please take a look? Thanks.
Thank you!

1. Sorry, my next testings show that even without gradients visited links are rendered slower than not visited. Gradients helped to slow down rendering and get better results. So the cause of slow down is not gradient itself.

2. I think there are many ways to make this faster, its run slow because of the slow creation of nodes, I speed it up a little bit (in bb2.html), and can try to search ways to make it faster (maybe reuse of nodes). See attached bb2.html file.
bb2.html
2.4 KB View Download
Project Member

Comment 3 by sheriffbot@chromium.org, Oct 4

Labels: Target-70 M-70
Cc: mtklein@chromium.org reed@google.com
FYI, attaching the rendered version for visited (repeating gradient block, red/blue) vs. not visited (solid red block) links.

The relevant style is

		a { 
			font-size: 98px;
			display: inline-block;
			color: red;
			
			background: repeating-linear-gradient(red 3%, currentColor 6%);
		}

		a:visited {
			color: blue;
		}
visited-vs-notvisited.png
20.4 KB View Download
Cc: chrishtr@chromium.org pdr@chromium.org schenney@chromium.org
+more paint folks

In general, gradients will always render slower than solid colors.

In this particular case, the solid block is still defined as a repeating gradient (red, red) though.  At some level we must be optimizing that away and taking a more efficient draw-solid-red code path.

So one option would be to chase down and disable that optimization.  Not 100% sure that's a good idea in general.

Another option might be to restrict this at the CSS level (e.g. currentColor could ignore the :visited selector) to avoid discriminating visited/not-visited for certain properties.  I believe we already do this to some degree (e.g. 'background' on :visited appears to be ignored).

Cc: futhark@chromium.org
I agree that locking this down at the css layer seems like the best choice.

@Chrishtr, there was some discussion about finally fixing this whole class of issues by restricting visited link information to the current origin. Did that go anywhere?
Project Member

Comment 7 by sheriffbot@chromium.org, Oct 4

Labels: Pri-1
I wrote in my second commend that is not about gradients. Visited and not visited links are rendered at a different speed, even without any style applied to "a" element.

Check my attached bb3.html. 

I do not know why gradients help only for the first run when is calculated initial information about timing. 
Screen Shot 2018-10-04 at 17.28.47.png
211 KB View Download
Screen Shot 2018-10-04 at 17.30.07.png
209 KB View Download
bb3.html
2.4 KB View Download
Re c#8: are you getting stable numbers?  What platform are you testing on?

On my desktop, timings without gradient are noisy/inconsistent:

bb3.html:29 Without gradient
bb3.html:86 26.10000013373792 "test known URL to calculate visited timing"
bb3.html:92 22.200000006705523 "test known URL to calculate NOT visited timing"
bb3.html:86 21.499999798834324 "test known URL to calculate visited timing"
bb3.html:92 23.099999874830246 "test known URL to calculate NOT visited timing"
bb3.html:86 20.400000037625432 "test known URL to calculate visited timing"
bb3.html:92 23.000000044703484 "test known URL to calculate NOT visited timing"
bb3.html:86 21.19999984279275 "test known URL to calculate visited timing"
bb3.html:92 22.70000008866191 "test known URL to calculate NOT visited timing"
bb3.html:86 23.000000044703484 "test known URL to calculate visited timing"
bb3.html:92 21.99999988079071 "test known URL to calculate NOT visited timing"

Re c#9:

I think is inconsistent because tested visited URL is empty href (<a href="">) but for real URL it's working. The second method is to uncomment "a" style from html and results will be consistent.
Re comment 6: no it did not go anywhere (yet). See also CSSWG  issue 3012  for
recent discussion.
Owner: chrishtr@google.com
Re c#10: if I plug a non-empty visited link for calibration, I do get a consistent bias:

34.49999960139394 "test known URL to calculate visited timing"
21.000000182539225 "test known URL to calculate NOT visited timing"
28.200000058859587 "test known URL to calculate visited timing"
21.50000026449561 "test known URL to calculate NOT visited timing"
28.4000001847744 "test known URL to calculate visited timing"
22.59999979287386 "test known URL to calculate NOT visited timing"
27.10000006482005 "test known URL to calculate visited timing"
24.10000003874302 "test known URL to calculate NOT visited timing"
28.599999845027924 "test known URL to calculate visited timing"
19.79999989271164 "test known URL to calculate NOT visited timing"

The numbers are quite noisy and actual detection is unreliable, but the bias looks real and intriguing.  Note that unlike your previous two examples, bb3.html does not actually render these links (missing <a> text node):

	const newlink = document.createElement('a')
        // missing: newlink.appendChild(document.createTextNode("This is new."))

	newlink.setAttribute('href', notVisited)
	container.appendChild(newlink)

So in this case the timing difference is not in rasterization -- I'm guessing style recalc?

Assigning to chrishtr@ for triage.

Chris, we may have two actionable issues here:

1) ability to pull the :visited color into an expensive gradient (as 'currentColor'), allowing rasterization timing attacks; see bb.html, bb2.html, c#4-6; probably best addressed with additional CSS/:visited restrictions.

2) looks like there's also a non-raster timing vector (style recalc?); see bb3.html, c#8-10.
Cc: fmalita@chromium.org
Owner: chrishtr@chromium.org
Re c#12:

Sure, in bb3.html is more noise because is just to check that links even without text and style are rendered at a different speed.

In bb2.html are better results, there are links with text node and some styles. Also, N - the count of nodes matters a lot for less noise.
Re c#12:

My results for bb2.html and I want to mention that there is not 'currentColor' in bb2, just some styles. For now, I'm not sure that 'currentColor' matter.

56.40000011771917 "test known URL to calculate visited timing"
26.199999963864684 "test known URL to calculate NOT visited timing"
58.39999997988343 "test known URL to calculate visited timing"
25.800000177696347 "test known URL to calculate NOT visited timing"
58.499999810010195 "test known URL to calculate visited timing"
25.800000177696347 "test known URL to calculate NOT visited timing"
65.89999981224537 "test known URL to calculate visited timing"
26.70000004582107 "test known URL to calculate NOT visited timing"

Project Member

Comment 17 by sheriffbot@chromium.org, Oct 20

chrishtr: Uh oh! This issue still open and hasn't been updated in the last 14 days. This is a serious vulnerability, and we want to ensure that there's progress. Could you please leave an update with the current status and any potential blockers?

If you're not the right owner for this issue, could you please remove yourself as soon as possible or help us find the right one?

If the issue is fixed or you can't reproduce it, please close the bug. If you've started working on a fix, please set the status to Started.

Thanks for your time! To disable nags, add the Disable-Nags label.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
My final thoughts. Not visited link retrieves the internal representation of css styles much faster than visited. So when browser shows a link it made request (select) to "css store" and this store works faster for not visited links. I made a file with aprox. 40 css styles for <a>. Some styles add a bigger difference to render speed, some less. 

I attach final.html and screenshot for N = 6000 and N = 10000. For N = 6000 visited links are rendered ~ 15ms and not v. ~ 49ms. For N = 10000 v. speed ~ 27ms and not v. ~ 150ms. 

I used requestAnimationFrame method to calculate render speed, it's not very good because, I think, it works with 15ms steps. But, I guess, in future will be better API to calculate render speed, and then will be easier to find more subtle differences.
final.html
3.5 KB View Download
FinalN6000.png
421 KB View Download
FinalN10000.png
412 KB View Download
New Update: I made PoC to runs much faster.
1. <a> contains many <div>
2. Many styles are applied to <div>

When each <div> styles need to be calculated, the process goes to slow visited or fast not visited parent link. The difference is very big when are many nodes with many styles inside parent <a>.

(So for more/less noise you can add/sub child <div>s.)

3. window.getComputedStyle(el).color instead of requestAnimationFrame or setTimeout
finalFast.html
6.6 KB View Download
And more, I deleted unused code. 

Now it's really fast, 106 links in 90ms total to check all of them.
finalFastClean.html
6.7 KB View Download
Project Member

Comment 21 by sheriffbot@chromium.org, Nov 3

chrishtr: Uh oh! This issue still open and hasn't been updated in the last 28 days. This is a serious vulnerability, and we want to ensure that there's progress. Could you please leave an update with the current status and any potential blockers?

If you're not the right owner for this issue, could you please remove yourself as soon as possible or help us find the right one?

If the issue is fixed or you can't reproduce it, please close the bug. If you've started working on a fix, please set the status to Started.

Thanks for your time! To disable nags, add the Disable-Nags label.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
This bugs looks the same to me as issue 835590. chrishtr or pdr: Do you see anything unique here, compared to that?
Mergedinto: 835590
Status: Duplicate (was: Assigned)
Don't think there is anything unique, except perhaps a different vector.
Duplicating.
Request for disclosure. 

Issue 835590 was open more than 7 months ago! This is not reasonable timescale
Cc: rorymcclelland@google.com rpop@google.com
Labels: -Restrict-View-SecurityTeam allpublic
Hi vadim@, I am making this issue public, thanks!

Sign in to add a comment