Commit c47ff7fb authored by arthursonzogni's avatar arthursonzogni Committed by Commit Bot

[COOP] access reporting: openeeURL, openerURL, otherDocumentURL

The [coop-reporting-explainer] defined several URLs that might be
reported:
- openeeURL
- openerURL
- otherDocumentURL
- referrerURL
- initialPopupURL

This adds the first 3.

[coop-reporting-explainer]:
https://github.com/camillelamy/explainers/blob/master/coop_reporting.md

Bug: 1090273
Change-Id: Ibd9710139e0065bd36fe6e798b50521f6d24baf6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2398619
Commit-Queue: Arthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: default avatarMike West <mkwst@chromium.org>
Reviewed-by: default avatarCamille Lamy <clamy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812144}
parent f494cb4b
......@@ -26,6 +26,9 @@ constexpr char kDisposition[] = "disposition";
constexpr char kEffectivePolicy[] = "effectivePolicy";
constexpr char kLineNumber[] = "lineNumber";
constexpr char kNextURL[] = "nextResponseURL";
constexpr char kOpeneeURL[] = "openeeURL";
constexpr char kOpenerURL[] = "openerURL";
constexpr char kOtherDocumentURL[] = "otherDocumentURL";
constexpr char kPreviousURL[] = "previousResponseURL";
constexpr char kProperty[] = "property";
constexpr char kReferrer[] = "referrer";
......@@ -181,7 +184,8 @@ void CrossOriginOpenerPolicyReporter::QueueNavigationAwayFromCOOPReport(
void CrossOriginOpenerPolicyReporter::QueueAccessReport(
network::mojom::CoopAccessReportType report_type,
const std::string& property,
network::mojom::SourceLocationPtr source_location) {
network::mojom::SourceLocationPtr source_location,
const std::string& reported_window_url) {
// Cross-Origin-Opener-Policy-Report-Only is not required to provide
// endpoints.
if (!coop_.report_only_reporting_endpoint)
......@@ -198,13 +202,35 @@ void CrossOriginOpenerPolicyReporter::QueueAccessReport(
body.SetStringPath(kEffectivePolicy,
ToString(coop_.report_only_value));
body.SetStringPath(kProperty, property);
// TODO(arthursonzogni): Fill "blocked-window-url".
if (network::IsAccessFromCoopPage(report_type) &&
source_location->url != "") {
body.SetStringPath(kSourceFile, source_location->url);
body.SetIntPath(kLineNumber, source_location->line);
body.SetIntPath(kColumnNumber, source_location->column);
}
switch (report_type) {
// Reporter is the openee:
case network::mojom::CoopAccessReportType::kAccessFromCoopPageToOpener:
case network::mojom::CoopAccessReportType::kAccessToCoopPageFromOpener:
body.SetStringPath(kOpenerURL, reported_window_url);
// TODO(arthursonzogni): Fill body.referrer.
break;
// Reporter is the opener:
case network::mojom::CoopAccessReportType::kAccessFromCoopPageToOpenee:
case network::mojom::CoopAccessReportType::kAccessToCoopPageFromOpenee:
body.SetStringPath(kOpeneeURL, reported_window_url);
// TODO(arthursonzogni): Fill body.initial_popup_url.
break;
// Other:
case network::mojom::CoopAccessReportType::kAccessFromCoopPageToOther:
case network::mojom::CoopAccessReportType::kAccessToCoopPageFromOther:
body.SetStringPath(kOtherDocumentURL, reported_window_url);
break;
}
storage_partition_->GetNetworkContext()->QueueReport(
"coop", endpoint, context_url_, base::nullopt, std::move(body));
}
......@@ -278,6 +304,7 @@ void CrossOriginOpenerPolicyReporter::MonitorAccesses(
// inside the same SiteInstance. Only one SiteInstance has to be updated.
RenderFrameHostImpl* accessing_rfh = accessing_node->current_frame_host();
RenderFrameHostImpl* accessed_rfh = accessed_node->current_frame_host();
SiteInstance* site_instance = accessing_rfh->GetSiteInstance();
base::Optional<base::UnguessableToken> accessed_window_token =
......@@ -310,12 +337,22 @@ void CrossOriginOpenerPolicyReporter::MonitorAccesses(
report_type = CoopAccessReportType::kAccessToCoopPageFromOther;
}
bool same_origin = accessing_rfh->GetLastCommittedOrigin().IsSameOriginWith(
accessed_rfh->GetLastCommittedOrigin());
RenderFrameHostImpl* reported_rfh =
access_from_coop_page ? accessed_rfh : accessing_rfh;
std::string reported_window_url =
same_origin ? SanitizedURL(reported_rfh->GetLastCommittedURL()) : "";
bool endpoint_defined =
coop_.report_only_reporting_endpoint || coop_.reporting_endpoint;
// Warning: Do not send cross-origin sensitive data. They will be read from:
// 1) A potentially compromised renderer (the accessing window).
// 2) A network server (defined from the reporter).
accessing_rfh->GetAssociatedLocalMainFrame()->InstallCoopAccessMonitor(
report_type, *accessed_window_token, std::move(remote_reporter),
endpoint_defined);
endpoint_defined, std::move(reported_window_url));
}
// static
......
......@@ -46,10 +46,10 @@ class CONTENT_EXPORT CrossOriginOpenerPolicyReporter final
}
// network::mojom::CrossOriginOpenerPolicyReporter implementation.
void QueueAccessReport(
network::mojom::CoopAccessReportType report_type,
const std::string& property,
network::mojom::SourceLocationPtr source_location) final;
void QueueAccessReport(network::mojom::CoopAccessReportType report_type,
const std::string& property,
network::mojom::SourceLocationPtr source_location,
const std::string& reported_window_url) final;
// Sends reports when COOP causing a browsing context group switch that
// breaks opener relationships.
......
......@@ -25,8 +25,11 @@ interface CrossOriginOpenerPolicyReporter {
// context groups tries to access each other.
// - |property| is the name of the access property (postMessage, open, ...).
// - |source_location| represents the line of code that triggered the access.
// - |reported_window_url| the sanitized URL of the second window. Empty when
// cross-origin with the reporting window.
QueueAccessReport(CoopAccessReportType report_type, string property,
SourceLocation source_location);
SourceLocation source_location,
string reported_window_url);
// Connects a new pipe to this instance.
Clone(pending_receiver<CrossOriginOpenerPolicyReporter> receiver);
......
......@@ -907,11 +907,15 @@ interface LocalMainFrame {
// 3) Devtool will be notified.
//
// |endpoint_defined|: The COOP header defines at least one endpoint.
// |reported_window_url|: The reported window's sanitized URL. This
// corresponds to openerURL, openeeURL or otherDocumentURL depending on the
// |report_type|.
InstallCoopAccessMonitor(
network.mojom.CoopAccessReportType report_type,
mojo_base.mojom.UnguessableToken accessed_window,
pending_remote<network.mojom.CrossOriginOpenerPolicyReporter> reporter,
bool endpoint_defined);
bool endpoint_defined,
string reported_window_url);
// Called on the main frame of a page embedded in a Portal when it is
// activated. The frame has the option to adopt the previous page as a portal
......
......@@ -441,13 +441,16 @@ void DOMWindow::InstallCoopAccessMonitor(
LocalFrame* accessing_frame,
mojo::PendingRemote<network::mojom::blink::CrossOriginOpenerPolicyReporter>
pending_reporter,
bool endpoint_defined) {
bool endpoint_defined,
const WTF::String& reported_window_url) {
CoopAccessMonitor monitor;
DCHECK(accessing_frame->IsMainFrame());
monitor.report_type = report_type;
monitor.accessing_main_frame = accessing_frame->GetFrameToken();
monitor.endpoint_defined = endpoint_defined;
monitor.reported_window_url = std::move(reported_window_url);
monitor.reporter.Bind(std::move(pending_reporter));
// CoopAccessMonitor are cleared when their reporter are gone. This avoids
// accumulation. However it would have been interesting continuing reporting
......@@ -533,9 +536,12 @@ void DOMWindow::ReportCoopAccess(const char* property_name) {
// interested.
if (it->endpoint_defined) {
it->reporter->QueueAccessReport(it->report_type, property_name,
std::move(source_location));
std::move(source_location),
std::move(it->reported_window_url));
// Send a coop-access-violation report.
if (network::IsAccessFromCoopPage(it->report_type)) {
// TODO(arthursonzogni): Fill the openeeURL, openerURL and
// otherDocumentURL.
ReportingContext::From(accessing_main_frame.DomWindow())
->QueueReport(MakeGarbageCollected<Report>(
ReportType::kCoopAccessViolation,
......
......@@ -141,7 +141,8 @@ class CORE_EXPORT DOMWindow : public EventTargetWithInlineData {
LocalFrame* accessing_frame,
mojo::PendingRemote<
network::mojom::blink::CrossOriginOpenerPolicyReporter> reporter,
bool endpoint_defined);
bool endpoint_defined,
const WTF::String& reported_window_url);
// Whenever we detect that the enforcement of a report-only COOP policy would
// have resulted in preventing access to this window, a report is potentially
// sent when calling this function.
......@@ -195,6 +196,7 @@ class CORE_EXPORT DOMWindow : public EventTargetWithInlineData {
mojo::Remote<network::mojom::blink::CrossOriginOpenerPolicyReporter>
reporter;
bool endpoint_defined;
WTF::String reported_window_url;
};
WTF::Vector<CoopAccessMonitor> coop_access_monitor_;
};
......
......@@ -2535,14 +2535,16 @@ void LocalFrame::InstallCoopAccessMonitor(
const base::UnguessableToken& accessed_window,
mojo::PendingRemote<network::mojom::blink::CrossOriginOpenerPolicyReporter>
reporter,
bool endpoint_defined) {
bool endpoint_defined,
const WTF::String& reported_window_url) {
blink::Frame* accessed_frame = Frame::ResolveFrame(accessed_window);
// The Frame might have been deleted during the cross-process communication.
if (!accessed_frame)
return;
accessed_frame->DomWindow()->InstallCoopAccessMonitor(
report_type, this, std::move(reporter), endpoint_defined);
report_type, this, std::move(reporter), endpoint_defined,
std::move(reported_window_url));
}
void LocalFrame::OnPortalActivated(
......
......@@ -660,7 +660,8 @@ class CORE_EXPORT LocalFrame final
const base::UnguessableToken& accessed_window,
mojo::PendingRemote<
network::mojom::blink::CrossOriginOpenerPolicyReporter> reporter,
bool endpoint_defined) final;
bool endpoint_defined,
const WTF::String& reported_window_url) final;
void OnPortalActivated(
const PortalToken& portal_token,
mojo::PendingAssociatedRemote<mojom::blink::Portal> portal,
......
......@@ -69,6 +69,9 @@ let runTest = (openee_redirect, name) => promise_test(async t => {
assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
assert_equals(report.body.property, "blur");
assert_source_location_found(report);
assert_equals(report.body.openerURL, undefined);
assert_equals(report.body.openeeURL, openee_url);
assert_equals(report.body.otherDocumentURL, undefined);
}, name);
runTest(false, "access-from-coop-page-to-openee, same-origin");
......
......@@ -70,6 +70,9 @@ let runTest = (openee_redirect, name) => promise_test(async t => {
assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
assert_equals(report.body.property, "blur");
assert_source_location_found(report);
assert_equals(report.body.openerURL, undefined);
assert_equals(report.body.openeeURL, "");
assert_equals(report.body.otherDocumentURL, undefined);
}, name);
runTest(false, "access-from-coop-page-to-openee, cross-origin");
......
......@@ -21,6 +21,8 @@ let runTest = (openee_redirect, name) => promise_test(async t => {
const report_token = token();
const openee_token = token();
const opener_url = location.href;
const reportTo = reportToHeaders(report_token);
const openee_url = same_origin + executor_path +
reportTo.header + reportTo.coopReportOnlySameOriginHeader + coep_header +
......@@ -46,6 +48,9 @@ let runTest = (openee_redirect, name) => promise_test(async t => {
assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
assert_equals(report.body.property, "blur");
assert_source_location_found(report);
assert_equals(report.body.openerURL, opener_url);
assert_equals(report.body.openeeURL, undefined);
assert_equals(report.body.otherDocumentURL, undefined);
}, name);
runTest(false, "access-from-coop-page-to-opener, same-origin");
......
......@@ -47,6 +47,9 @@ let runTest = (openee_redirect, name) => promise_test(async t => {
assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
assert_equals(report.body.property, "blur");
assert_source_location_found(report);
assert_equals(report.body.openerURL, "");
assert_equals(report.body.openeeURL, undefined);
assert_equals(report.body.otherDocumentURL, undefined);
}, name);
runTest(false, "access-from-coop-page-to-opener, cross-origin");
......
......@@ -81,6 +81,9 @@ promise_test(async t => {
assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
assert_equals(report.body.property, "blur");
assert_source_location_found(report);
assert_equals(report.body.openerURL, undefined);
assert_equals(report.body.openeeURL, undefined);
assert_equals(report.body.otherDocumentURL, other_url.replace(/"/g, '%22'));
}, "access-from-coop-page-to-other (COOP-RO)");
</script>
......@@ -82,6 +82,9 @@ promise_test(async t => {
assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
assert_equals(report.body.property, "blur");
assert_source_location_found(report);
assert_equals(report.body.openerURL, undefined);
assert_equals(report.body.openeeURL, undefined);
assert_equals(report.body.otherDocumentURL, "");
}, "access-from-coop-page-to-other (COOP-RO)");
</script>
......@@ -63,6 +63,9 @@ let runTest = (openee_redirect, name) => promise_test(async t => {
assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
assert_equals(report.body.property, "blur");
assert_source_location_missing(report);
assert_equals(report.body.openerURL, undefined);
assert_equals(report.body.openeeURL, openee_url);
assert_equals(report.body.otherDocumentURL, undefined);
}, name);
runTest(false, "access-to-coop-page-from-openee, same-origin");
......
......@@ -64,6 +64,9 @@ let runTest = (openee_redirect, name) => promise_test(async t => {
assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
assert_equals(report.body.property, "blur");
assert_source_location_missing(report);
assert_equals(report.body.openerURL, undefined);
assert_equals(report.body.openeeURL, "");
assert_equals(report.body.otherDocumentURL, undefined);
}, name);
runTest(false, "access-to-coop-page-from-openee, cross-origin");
......
......@@ -22,6 +22,8 @@ let runTest = (openee_redirect, name) => promise_test(async t => {
const openee_token = token();
const opener_token = token(); // The current test window.
const opener_url = location.href;
const reportTo = reportToHeaders(report_token);
const openee_url = same_origin + executor_path + reportTo.header +
reportTo.coopReportOnlySameOriginHeader + coep_header +
......@@ -53,6 +55,9 @@ let runTest = (openee_redirect, name) => promise_test(async t => {
assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
assert_equals(report.body.property, "blur");
assert_source_location_missing(report);
assert_equals(report.body.openerURL, opener_url);
assert_equals(report.body.openeeURL, undefined);
assert_equals(report.body.otherDocumentURL, undefined);
}, name);
runTest(false, "access-to-coop-page-from-opener, same-origin");
......
......@@ -54,6 +54,9 @@ let runTest = (openee_redirect, name) => promise_test(async t => {
assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
assert_equals(report.body.property, "blur");
assert_source_location_missing(report);
assert_equals(report.body.openerURL, "");
assert_equals(report.body.openeeURL, undefined);
assert_equals(report.body.otherDocumentURL, undefined);
}, name);
runTest(false, "access-to-coop-page-from-opener, cross-origin");
......
......@@ -69,6 +69,9 @@ promise_test(async t => {
assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
assert_equals(report.body.property, "blur");
assert_source_location_missing(report);
assert_equals(report.body.openerURL, undefined);
assert_equals(report.body.openeeURL, undefined);
assert_equals(report.body.otherDocumentURL, other_url);
}, "access-to-coop-page-from-other (COOP-RO)");
</script>
......@@ -70,6 +70,9 @@ promise_test(async t => {
assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
assert_equals(report.body.property, "blur");
assert_source_location_missing(report);
assert_equals(report.body.openerURL, undefined);
assert_equals(report.body.openeeURL, undefined);
assert_equals(report.body.otherDocumentURL, "");
}, "access-to-coop-page-from-other (COOP-RO)");
</script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment