Commit bc9a80d4 authored by Domenic Denicola's avatar Domenic Denicola Committed by Commit Bot

Origin isolation: parse the header

Bug: 1066930
Change-Id: Ib1c79f8c9218821c7da3640e012cf042666e6d50
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2222692
Commit-Queue: Domenic Denicola <domenic@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#773706}
parent af3be81c
......@@ -1805,12 +1805,8 @@ NavigationRequest::IsOptInIsolationRequested(const GURL& url) {
url, response()->headers.get(),
"OriginIsolationHeader", base::Time::Now()));
// TODO(https://crbug.com/1066930): For now we just check the presence of the
// header; we do not parse/validate it. When we do, that will have to be
// outside the browser process.
const bool requests_via_header =
header_is_enabled && response()->headers &&
response()->headers->HasHeader("origin-isolation");
header_is_enabled && response_head_->parsed_headers->origin_isolation;
if (requests_via_header)
return OptInIsolationCheckResult::HEADER;
......
......@@ -67,6 +67,8 @@ jumbo_component("cpp") {
"network_quality_tracker.h",
"network_switches.cc",
"network_switches.h",
"origin_isolation_parser.cc",
"origin_isolation_parser.h",
"parsed_headers.cc",
"parsed_headers.h",
"request_destination.cc",
......@@ -289,6 +291,7 @@ source_set("tests") {
"network_mojom_traits_unittest.cc",
"network_quality_tracker_unittest.cc",
"optional_trust_token_params_unittest.cc",
"origin_isolation_parser_unittest.cc",
"proxy_config_mojom_traits_unittest.cc",
"simple_url_loader_unittest.cc",
"site_for_cookies_mojom_traits_unittest.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/public/cpp/origin_isolation_parser.h"
#include "net/http/structured_headers.h"
namespace network {
bool ParseOriginIsolation(const std::string& header_value) {
const auto item = net::structured_headers::ParseItem(header_value);
return item && item->item.is_boolean() && item->item.GetBoolean();
}
} // namespace network
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SERVICES_NETWORK_PUBLIC_CPP_ORIGIN_ISOLATION_PARSER_H_
#define SERVICES_NETWORK_PUBLIC_CPP_ORIGIN_ISOLATION_PARSER_H_
#include <string>
#include "base/component_export.h"
namespace network {
// Parsing is done following the Origin-Isolation spec draft:
// https://github.com/whatwg/html/pull/5545
//
// See the comment in network::PopulateParsedHeaders for restrictions on this
// function.
COMPONENT_EXPORT(NETWORK_CPP)
bool ParseOriginIsolation(const std::string&);
} // namespace network
#endif // SERVICES_NETWORK_PUBLIC_CPP_ORIGIN_ISOLATION_PARSER_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/public/cpp/origin_isolation_parser.h"
#include <string>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
namespace network {
TEST(OriginIsolationHeaderTest, Parse) {
EXPECT_EQ(ParseOriginIsolation(""), false);
EXPECT_EQ(ParseOriginIsolation("?1"), true);
EXPECT_EQ(ParseOriginIsolation("?0"), false);
EXPECT_EQ(ParseOriginIsolation("?1;param"), true);
EXPECT_EQ(ParseOriginIsolation("?1;param=value"), true);
EXPECT_EQ(ParseOriginIsolation("?1;param=value;param2=value2"), true);
EXPECT_EQ(ParseOriginIsolation("true"), false);
EXPECT_EQ(ParseOriginIsolation("\"?1\""), false);
EXPECT_EQ(ParseOriginIsolation("1"), false);
EXPECT_EQ(ParseOriginIsolation("?2"), false);
EXPECT_EQ(ParseOriginIsolation("(?1)"), false);
}
} // namespace network
......@@ -10,6 +10,7 @@
#include "services/network/public/cpp/cross_origin_embedder_policy_parser.h"
#include "services/network/public/cpp/cross_origin_opener_policy_parser.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/origin_isolation_parser.h"
namespace network {
......@@ -30,6 +31,10 @@ mojom::ParsedHeadersPtr PopulateParsedHeaders(
parsed_headers->cross_origin_opener_policy =
ParseCrossOriginOpenerPolicy(*headers);
std::string origin_isolation;
if (headers->GetNormalizedHeader("Origin-Isolation", &origin_isolation))
parsed_headers->origin_isolation = ParseOriginIsolation(origin_isolation);
std::string accept_ch;
if (headers->GetNormalizedHeader("Accept-CH", &accept_ch))
parsed_headers->accept_ch = ParseAcceptCH(accept_ch);
......
......@@ -23,6 +23,9 @@ struct ParsedHeaders {
// Cross-Origin-opener-Policy-Report-Only headers.
CrossOriginOpenerPolicy cross_origin_opener_policy;
// The parsed value of the Origin-Isolation header.
bool origin_isolation;
// The parsed Accept-CH from response headers.
//
// If this is missing, there is no valid accept-ch header, so client hints
......
......@@ -127,6 +127,7 @@ blink::ParsedHeadersPtr ConvertToBlink(ParsedHeadersPtr parsed_headers) {
ConvertToBlink(std::move(parsed_headers->content_security_policy)),
std::move(parsed_headers->cross_origin_embedder_policy),
std::move(parsed_headers->cross_origin_opener_policy),
parsed_headers->origin_isolation,
parsed_headers->accept_ch.has_value()
? base::make_optional(
ConvertToBlink(parsed_headers->accept_ch.value()))
......
<!DOCTYPE html>
<meta charset="utf-8">
<title>Parent is not isolated, child attempts to isolate but uses a bad header value, child is a subdomain of the parent</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script type="module">
import { insertIframe, sendWasmModule, setBothDocumentDomains } from "./resources/helpers.mjs";
for (const badValue of ["", "?0", "true", "\"?1\"", "1", "?2", "(?1)"]) {
let frameWindow;
promise_test(async () => {
frameWindow = await insertIframe("{{hosts[][www]}}", badValue);
}, `"${badValue}": frame insertion`);
// Since the header values are bad there should be no isolation
promise_test(async () => {
const whatHappened = await sendWasmModule(frameWindow);
assert_equals(whatHappened, "WebAssembly.Module message received");
}, `"${badValue}": message event must occur for`);
promise_test(async () => {
await setBothDocumentDomains(frameWindow);
// Must not throw
frameWindow.document;
}, `"${badValue}": setting document.domain must give sync access`);
}
</script>
<!DOCTYPE html>
<meta charset="utf-8">
<title>Parent is not isolated, child is isolated using parameters on its structured header, child is a subdomain of the parent</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script type="module">
import { insertIframe, sendWasmModule, setBothDocumentDomains } from "./resources/helpers.mjs";
let frameWindow;
promise_setup(async () => {
frameWindow = await insertIframe("{{hosts[][www]}}", "?1;param1;param2=value2");
});
// Since they're different-origin, the child's isolation request is respected,
// so the parent ends up in the site-keyed agent cluster and the child in the
// origin-keyed one.
promise_test(async () => {
const whatHappened = await sendWasmModule(frameWindow);
assert_equals(whatHappened, "messageerror");
}, "messageerror event must occur");
promise_test(async () => {
await setBothDocumentDomains(frameWindow);
assert_throws_dom("SecurityError", DOMException, () => {
frameWindow.document;
});
}, "setting document.domain should no-op instead of giving sync access");
</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