mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-23 04:55:15 +00:00
LibWeb: Implement basic high resolution time coarsening
Several interfaces that return a high resolution time require that time to be coarsened, in order to prevent timing attacks. This implementation simply reduces the resolution of the returned timestamp to the minimum values given in the specification. Further work may be needed to make our implementation more robust to the kind of attacks that this mechanism is designed to prevent.
This commit is contained in:
parent
a5be7cb6fb
commit
39445d6dd6
Notes:
github-actions[bot]
2025-01-30 17:39:14 +00:00
Author: https://github.com/tcl3 Commit: https://github.com/LadybirdBrowser/ladybird/commit/39445d6dd68 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3381 Reviewed-by: https://github.com/AtkinsSJ ✅
7 changed files with 100 additions and 5 deletions
|
@ -330,7 +330,8 @@ WebIDL::ExceptionOr<GC::Ref<Document>> Document::create_and_initialize(Type type
|
|||
DOM::DocumentLoadTimingInfo load_timing_info;
|
||||
// AD-HOC: The response object no longer has an associated timing info object. For now, we use response's non-standard response time property,
|
||||
// which represents the time that the time that the response object was created.
|
||||
load_timing_info.navigation_start_time = navigation_params.response->response_time().nanoseconds() / 1e6;
|
||||
auto response_creation_time = navigation_params.response->response_time().nanoseconds() / 1e6;
|
||||
load_timing_info.navigation_start_time = HighResolutionTime::coarsen_time(response_creation_time, HTML::relevant_settings_object(*window).cross_origin_isolated_capability() == HTML::CanUseCrossOriginIsolatedAPIs::Yes);
|
||||
|
||||
// 9. Let document be a new Document, with
|
||||
// type: type
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Math.h>
|
||||
#include <AK/Time.h>
|
||||
#include <LibWeb/HTML/Scripting/Environments.h>
|
||||
#include <LibWeb/HighResolutionTime/TimeOrigin.h>
|
||||
|
@ -46,8 +47,19 @@ DOMHighResTimeStamp get_time_origin_timestamp(JS::Object const& global)
|
|||
// https://w3c.github.io/hr-time/#dfn-coarsen-time
|
||||
DOMHighResTimeStamp coarsen_time(DOMHighResTimeStamp timestamp, bool cross_origin_isolated_capability)
|
||||
{
|
||||
// FIXME: Implement this.
|
||||
(void)cross_origin_isolated_capability;
|
||||
// 1. Let time resolution be 100 microseconds, or a higher implementation-defined value.
|
||||
auto time_resolution_milliseconds = 0.1;
|
||||
|
||||
// 2. If crossOriginIsolatedCapability is true, set time resolution to be 5 microseconds, or a higher implementation-defined value.
|
||||
if (cross_origin_isolated_capability)
|
||||
time_resolution_milliseconds = 0.005;
|
||||
|
||||
// 3. In an implementation-defined manner, coarsen and potentially jitter timestamp such that its resolution will not exceed time resolution
|
||||
timestamp = floor(timestamp / time_resolution_milliseconds) * time_resolution_milliseconds;
|
||||
|
||||
// FIXME: Applying jitter to the coarsened timestamp here may decrease our susceptibility to timing attacks.
|
||||
|
||||
// 4. Return timestamp as a moment
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,5 +2,5 @@ Harness status: OK
|
|||
|
||||
Found 1 tests
|
||||
|
||||
1 Fail
|
||||
Fail Event timestamp should not have a resolution better than 5 microseconds
|
||||
1 Pass
|
||||
Pass Event timestamp should not have a resolution better than 5 microseconds
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass The recommended minimum resolution of the Performance interface has been set to 100 microseconds for cross-origin isolated contexts.
|
|
@ -5,6 +5,14 @@
|
|||
bufferedMessages.push(message);
|
||||
}
|
||||
|
||||
function synchronousWaitMicroseconds(microseconds) {
|
||||
var start = performance.now() * 1000,
|
||||
now = start;
|
||||
while (now - start < microseconds) {
|
||||
now = performance.now() * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
const globalObserver = new PerformanceObserver((list, observer) => {
|
||||
printlnBuffered(`observer === globalObserver: ${observer === globalObserver}`);
|
||||
printlnBuffered(
|
||||
|
@ -53,7 +61,11 @@
|
|||
globalObserver.observe({ entryTypes: ["measure", "mark"] });
|
||||
|
||||
const startMark = performance.mark("start");
|
||||
// The resolution of the clock used by the Performance interface is 100 microseconds, so we wait twice that time
|
||||
// between calls to ensure they are ordered as we expect.
|
||||
synchronousWaitMicroseconds(200);
|
||||
const endMark = performance.mark("end");
|
||||
synchronousWaitMicroseconds(200);
|
||||
const measureMark = performance.measure("measure", "start", "end");
|
||||
|
||||
function printCatchedException(func) {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
function run_test(isolated) {
|
||||
let resolution = 100;
|
||||
if (isolated) {
|
||||
resolution = 5;
|
||||
}
|
||||
test(function() {
|
||||
function check_resolutions(times, length) {
|
||||
const end = length - 2;
|
||||
|
||||
// we compare each value with the following ones
|
||||
for (let i = 0; i < end; i++) {
|
||||
const h1 = times[i];
|
||||
for (let j = i+1; j < end; j++) {
|
||||
const h2 = times[j];
|
||||
const diff = h2 - h1;
|
||||
assert_true((diff === 0) || ((diff * 1000) >= resolution),
|
||||
"Differences smaller than ' + resolution + ' microseconds: " + diff);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const times = new Array(10);
|
||||
let index = 0;
|
||||
let hrt1, hrt2, hrt;
|
||||
assert_equals(self.crossOriginIsolated, isolated, "Document cross-origin isolated value matches");
|
||||
|
||||
// rapid firing of performance.now
|
||||
hrt1 = performance.now();
|
||||
hrt2 = performance.now();
|
||||
times[index++] = hrt1;
|
||||
times[index++] = hrt2;
|
||||
|
||||
// ensure that we get performance.now() to return a different value
|
||||
do {
|
||||
hrt = performance.now();
|
||||
times[index++] = hrt;
|
||||
} while ((hrt - hrt1) === 0);
|
||||
|
||||
assert_true(check_resolutions(times, index), 'Difference should be at least ' + resolution + ' microseconds.');
|
||||
}, 'The recommended minimum resolution of the Performance interface has been set to ' + resolution + ' microseconds for cross-origin isolated contexts.');
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>window.performance.now should not enable timing attacks</title>
|
||||
<link rel="author" title="W3C" href="http://www.w3.org/" />
|
||||
<link rel="help" href="http://w3c.github.io/hr-time/#privacy-security"/>
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<script src="resources/timing-attack.js"></script>
|
||||
<script>
|
||||
run_test(/*isolated=*/false);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Description</h1>
|
||||
<p>The recommended minimum resolution of the Performance interface should be set to 100 microseconds for non-isolated contexts.</p>
|
||||
|
||||
<div id="log"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Reference in a new issue