Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mechanism to translate timestamps between globals #29

Closed
wants to merge 2 commits into from

Conversation

igrigorik
Copy link
Member

@igrigorik igrigorik commented Jul 13, 2016

A first run at exposing ~globalOffset like mechanism to translate timestamps between globals:

Preview: https://cdn.rawgit.com/w3c/hr-time/offset/index.html

I'm sure the above needs more work, but hopefully it's a step in the right direction..

/cc @toddreifsteck @sicking for review.

@sicking
Copy link

sicking commented Jul 13, 2016

I don't have any other feedback other than what's already been mentioned in #22.

In particular my proposal in #22 (comment) seems essentially as easy to use for developers, but with none of the privacy issues.

But if @martinthomson has no privacy concerns, then I'm fine with this too.

@toddreifsteck
Copy link
Member

Will review on 7/26 and share feedback then.

@toddreifsteck
Copy link
Member

Talked with the dev team and we are good with the timeOrigin proposal. We still believe that using a machine-specific timeOrigin is probably a bad idea so we believe a comment should be added that the timeOrigin chosen should not be easily identifiable. (Unix epoch meets this requirement but so does my birthday.)

@sicking
Copy link

sicking commented Jul 26, 2016

@toddreifsteck Did you see the updated proposal from @igrigorik at #22 (comment) ?

It does not expose any machine-specific information.

@toddreifsteck
Copy link
Member

Just updated my comment. I believe that proposal does not allow a cloud entity to build the timeline and only allows for client-side coordination.

@toddreifsteck
Copy link
Member

@sicking By the way, please correct me if I'm mistaken or missing how performance.timeOrigin() at #22 (comment) could be used to create a conslidated timeline in the cloud.

@igrigorik
Copy link
Member Author

@toddreifsteck you'd have one context gather the timeline from the contexts it cares about, run all the translations locally, and send the merged timeline to the server.

@toddreifsteck
Copy link
Member

@igrigorik But why force that restriction on the space? We don't have a strong argument for doing so at this point that I'm aware of.

@igrigorik
Copy link
Member Author

Thinking out loud, and in no particular order...

I'm afraid that explicitly linking time-origin and Date.now (e.g. #27) has subtle failure scenarios that will plague both browser and web developers...

  • To satisfy requirements of hr-time we need a monotonic clock that has a constant tick rate, not subject to skew, and is independent of your logical time. As such, if we do link hr-time to epoch time then we'd have to snapshot it at some arbitrary point in time (e.g. browser startup) and then tick from that time; in the meantime the time reported by Date.now can change arbitrarily due to clock adjustments, user settings, etc.
  • As a developer I can't trust the ~"epoch time" returned by hr-time and compare it against Date.now because any number of variables could have introduced skew between them. As a corollary: if I beacon back ~epoch metrics reported by hr-time they may not align with other timestamps. This will become a source of confusion; I can guarantee we'll see bugs reporting that perf.now doesn't align with Date.now.. and that's not something we can fix.
    • As a browser we're now also exposing a new bit of information which reveals skew between the time when we start our monotonic clock and now(). It's not clear to me how big of a risk this is (shrug), but we are leaking new bits and avoiding that is a plus in my books.

Another subtle failure scenario: user loads my site and logs ~timeOrigin + timestamps from multiple contexts; user closes browser. Next, user realizes they forgot something and launches the browser again and repeats same operation.. resulting in another set of metrics sent to the server.

  • The problem with the above is that we'd reset our monotic clocks between restarts and now we have an unknown skew between two sets of metrics.. unless you also start timestamping Date.now along side all of your reports and try to offset that, but even that has failure scenarios.

In short, it seems that there are many subtle and not so subtle gotchas with linking hr-time with Date.now, and it'd be nice if we could avoid introducing those into the ecosystem.


Conversely, if we force the developer to translate timestamps locally..

  • We don't leak any additional entropy about the client; we don't reveal skew, etc.
  • We allow any reachable contexts to translate timestamps and use that for coordinating work, assembling a merged timeline, etc. The actual amount of work is equivalent: either you send a timestamp against which receiver has to offset everything, or you send an object against which receiver resolves timestamps.
  • I think there is some additional utility to exposing 'time origin' as a first class API; it can help applications assemble their own logical timelines which are not tied to 'navigation time origin'.

The returned value is the global time of the "zero time" of the time
origin. This allows multiple contexts, each with own time origin, to
translate timestamps with sub-millisecond resolution, either by
communicating their global time to the other context, or first
translating their timestamps against the global time of their time
origin. Related discussions in #21 and #22.

A polyfill for this is ~: Date.now()-performance.now(), modulo clock
skew and adjustments that Date.now() is subject to.
@igrigorik
Copy link
Member Author

Jumped on a call with @toddreifsteck earlier this week to work through above concerns. Long story short, he convinced me that #22 (comment) doesn't win us much and that timeOrigin is both simpler and more flexible. I've updated the pull request in ce0d9cd to reflect outcome of that discussion.

Preview: https://cdn.rawgit.com/w3c/hr-time/offset/index.html

@toddreifsteck can you take a quick pass, does it match what you had in mind?
@MartinThompson as a followup to #22 (comment), can you also please take a pass over the proposed change? In particular, any comments or thoughts on the security/privacy section?

@bmaurer
Copy link

bmaurer commented Aug 16, 2016

To reduce accuracy of such attacks the user agent is recommended to periodically update the zero time time-of-day reference of its global monotonic clock

How would this work? When would a browser know it was safe to change the zero time of day reference of the monotonic clock (ie that nobody had cached a timeOrigin between documents).

One other quick thought here -- is it possible for one to translate time across distinct requests. For example, let's say a SW runs into a situation where it needs to do a full page reload (because the version of code is too far out of sync w the server). Can one redirect to mysite.com/?reload_reason=code_sync&timeOrigin=&navStart=).

@igrigorik
Copy link
Member Author

To reduce accuracy of such attacks the user agent is recommended to periodically update the zero time time-of-day reference of its global monotonic clock

How would this work? When would a browser know it was safe to change the zero time of day reference of the monotonic clock (ie that nobody had cached a timeOrigin between documents).

I think one instance would be opening an incognito window: the UA can update its reference for the incognito session. However, you're right, the 'periodically' part is harder to reason about.. I didn't want to rule it out and left if there, but I could be convinced that we should reword that: ~ s/periodically update/update, when possible,/, or some such.

is it possible for one to translate time across distinct requests. For example, let's say a SW runs into a situation where it needs to do a full page reload (because the version of code is too far out of sync w the server). Can one redirect to mysite.com/?reload_reason=code_sync&timeOrigin=&navStart=).

I'm not sure I understand what you're trying to solve... You're reloading the page and passing the previous page's navStart / timeOrigin? Why?

the issues summarized in this section by providing a monotonically
increasing time value in sub-millisecond resolution.</p>
of usage. The <a>DOMHighResTimeStamp</a> type, <a>performance.now</a>
method, and <a>performance.timeOrigin</a> attribute of the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on the call today, I don't think we can guarantee the monotonic clock on timeOrign in case the computer is restarted and its clock gets updated before the browser is launched.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. timeOrigin is a snapshot that should be taken when first browser context is launched. Then.. it should ideally remain monotonic until all contexts are closed. It could then be possible to snapshot a new timeOrigin that is before the previous context set's timeOrigin used.

@bmaurer
Copy link

bmaurer commented Aug 17, 2016

Sent from my iPhone

On Aug 16, 2016, at 11:36 AM, Ilya Grigorik notifications@github.com wrote:

To reduce accuracy of such attacks the user agent is recommended to periodically update the zero time time-of-day reference of its global monotonic clock

How would this work? When would a browser know it was safe to change the zero time of day reference of the monotonic clock (ie that nobody had cached a timeOrigin between documents).

I think one instance would be opening an incognito window: the UA can update its reference for the incognito session. However, you're right, the 'periodically' part is harder to reason about.. I didn't want to rule it out and left if there, but I could be convinced that we should reword that: ~ s/periodically update/update, when possible,/, or some such.

is it possible for one to translate time across distinct requests. For example, let's say a SW runs into a situation where it needs to do a full page reload (because the version of code is too far out of sync w the server). Can one redirect to mysite.com/?reload_reason=code_sync&timeOrigin=&navStart=).

I'm not sure I understand what you're trying to solve... You're reloading the page and passing the previous page's navStart / timeOrigin? Why?

Sometimes we have to get a fresh start. For example let's say we've updated react and the user has an old version cached. We might no longer have a server that can interop with the old js code. Also we force a full page refresh after 30 page navigations to mitigate the risk of memory leaks. We'd like to be able to measure the perf of these interactions end to end. For example if we make a request to the server and the server tells us "you need to refresh the page" we'd like to pass the time the user clicked the button that caused the navigation to the next page. If we can ensure that the time origin allows us to translate timestamps that will let us accomplish that


You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.

between any two chronologically recorded time values returned from the
<a>Performance.now</a> method MUST never be negative if the two time values
have the same <a>time origin</a>.</p>
<p>The time values returned when getting <a>performance.timeOrigin</a> MUST
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto re guarantee of monotonic clock.

@igrigorik
Copy link
Member Author

For example if we make a request to the server and the server tells us "you need to refresh the page" we'd like to pass the time the user clicked the button that caused the navigation to the next page. If we can ensure that the time origin allows us to translate timestamps that will let us accomplish that

You can do that already with ms resolution, right? Just append result of Date.now() to the query string of the page you're navigating to. With mechanism we're discussing here you could get higher resolution by doing performance.timeOrigin+performance.now(), but I'm not sure that would win you much in practice... Besides zero time for navigation is what you're looking for, so you can just use timeOrigin directly on the destination page.

@igrigorik
Copy link
Member Author

Some thoughts based on discussion last week + comments above...

  1. Existing: monotonic clock that starts ticking from context time origin
  2. New:
    1. global monotonic clock that starts ticking at ~browser start
    2. high resolution UTC reference timestamp of zero time for 2.i

timeOrigin is defined as 2.i + value of 2.ii when context's time origin is zero. The global monotonic clock value is not exposed directly to the application.

  • 2.ii will be reset across browser restarts
  • 2.ii may be reset when opening an isolated profile (e.g. incognito)

That said, I don't think we can, nor is it our goal, to address either of the above limitations; it's something we can mention as a heads up but not much more. Practically speaking, it means that if you get a message from another context, then you can use it for the duration of time that you yourself are around; you cannot cache and reuse this value in another context.


The question that remains in my head is how much of a concern is the increased resolution of clock skew detection if 2.ii is not at least periodically updated. On the one hand, there is existing research that indicates that clock skew is ~constant:

"As we shall show, and as others have also concluded [22, 20, 26], it is often reasonable to assume that a clock’s skew is constant." source

If you accept that, then a longer time horizon doesn't yield much. However, I still have a nagging feeling that there is additional exposure here, if not in terms of accuracy, then in terms of speed.

The earlier discussion on inducing and measuring clock skew (#22 (comment)) seems mostly orthogonal to the above, as it addresses a different threat model (inducing clock skew and remotely measuring it to compromise anonymity of a remote node).

/cc @martinthomson please chime if otherwise.


If we do want to eliminate this, then I think we have to rethink how (and if) we can expose the zero time. Today developers have to pass Date.now() timestamps to synchronize time across contexts.. However, the caveat with that approach is that the transfer itself takes some unknown period of time, and nothing stops the clock from changing while that's happening either. To eliminate both of these, without exposing some fixed global time, the only way I see is for the receiver context to resolve the time, not the sender, because there is an unknown delta between sender resolving time and receiver actually getting their hands on it. Which takes us back to something like #22 (comment).

@@ -186,6 +183,7 @@

port.postMessage({
'task': 'Some worker task',
'time_origin': performance.timeOrigin,
'start_time': task_start,
'end_time': task_end,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super nitpicky but.. should we encourage sending the timeOrigin in each postMessage? I'd imagine we'd want to encourage sending this once with some type of context ID for a smaller postMessage payload. "Sample code becomes product code."

@toddreifsteck
Copy link
Member

@igrigorik Can we list any open issues blocking this being added to L3 here? (Yes.. I'm being a paperwork nag. Just tell me if you are tracking in another location and put link here. :-))

@igrigorik
Copy link
Member Author

Based on our discussion at TPAC:

  1. We agreed that we'll move forward with timeOrigin route (i.e. what we have in this pull)
  2. We need to better explain and document the implications of exposing timeOrigin with respect to privacy/security.
  3. Once (2) is in place and merged, we should solicit 'wide review' from other groups.

I'm working on (2), stay tuned.

@igrigorik igrigorik added this to the Level 3 milestone Oct 3, 2016
@igrigorik igrigorik self-assigned this Oct 3, 2016
@igrigorik
Copy link
Member Author

@toddreifsteck @bzbarsky @rniwa updated the privacy/security section based on our discussion at TPAC: 3ed76dd. Would appreciate any feedback!

If you prefer, the more human-readable version:

@toddreifsteck
Copy link
Member

@plehegar had a few comments. Have they been resolved?

I'd like to get @bzbarsky and @rniwa to give a quick read of 3ed76dd and then I'm good for us to merge.

Otherwise, LGTM!

@igrigorik
Copy link
Member Author

@plehegar had a few comments. Have they been resolved?

I believe so, but I'll let @plehegar confirm :)

@rniwa
Copy link

rniwa commented Oct 18, 2016

I talked with my colleagues about performance.timeOrigin and we couldn't find any security implications that are new to this API beyond what's already possible with Date.now() and performance.now().

@plehegar plehegar added the security-tracker Group bringing to attention of security, or tracked by the security Group but not needing response. label Oct 20, 2016
@plehegar
Copy link
Member

LGTM.

@igrigorik
Copy link
Member Author

Thanks for the feedback and reviews everyone! Rebased and merged (6d4edaa, 4f49403), not sure why GH PR did not pick it up. Closing this PR.

Live: https://w3c.github.io/hr-time/ -- note that timeOrigin is part of HR-Time L3.

p.s. @bzbarsky if you have any feedback or nits, please let us know / file a new bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
security-tracker Group bringing to attention of security, or tracked by the security Group but not needing response.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants