Commit 052a1f25 authored by arthursonzogni's avatar arthursonzogni Committed by Commit Bot

[OutOfBlinkOrigin] Plug sandbox flags in GetOriginForURLLoaderFactory().

The value is not sent to blink yet. As a result, the same origin
computed from blink and the browser process might differ by their
|nonce_|.

Bug: 888079
Change-Id: I1c884a2e72e4d79fb9663d152cb011cc219f320f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2502477Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarMatt Menke <mmenke@chromium.org>
Reviewed-by: default avatarŁukasz Anforowicz <lukasza@chromium.org>
Commit-Queue: Arthur Sonzogni <arthursonzogni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#824010}
parent ecac50b4
......@@ -3693,4 +3693,151 @@ IN_PROC_BROWSER_TEST_F(DocumentPolicyBrowserTest,
EXPECT_FALSE(last_metadata.is_scroll_offset_at_top);
}
IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, OriginToCommitBasic) {
GURL url = embedded_test_server()->GetURL("a.com", "/empty.html");
auto origin_expected = url::Origin::Create(url);
TestNavigationManager manager(web_contents(), url);
shell()->LoadURL(url);
EXPECT_TRUE(manager.WaitForResponse());
NavigationRequest* navigation = main_frame()->navigation_request();
url::Origin origin_to_commit = navigation->GetOriginForURLLoaderFactory();
manager.WaitForNavigationFinished();
url::Origin origin_committed = current_frame_host()->GetLastCommittedOrigin();
EXPECT_FALSE(origin_to_commit.opaque());
EXPECT_FALSE(origin_committed.opaque());
EXPECT_EQ(origin_expected, origin_to_commit);
EXPECT_EQ(origin_expected, origin_committed);
}
IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
OriginToCommitSandboxFromResponse) {
GURL url = embedded_test_server()->GetURL(
"a.com", "/set-header?Content-Security-Policy: sandbox");
TestNavigationManager manager(web_contents(), url);
shell()->LoadURL(url);
EXPECT_TRUE(manager.WaitForResponse());
NavigationRequest* navigation = main_frame()->navigation_request();
url::Origin origin_to_commit = navigation->GetOriginForURLLoaderFactory();
manager.WaitForNavigationFinished();
url::Origin origin_committed = current_frame_host()->GetLastCommittedOrigin();
EXPECT_TRUE(origin_to_commit.opaque());
EXPECT_TRUE(origin_committed.opaque());
// TODO(https://crbug.com/888079). The nonce must match.
EXPECT_NE(origin_to_commit, origin_committed);
}
IN_PROC_BROWSER_TEST_F(NavigationBrowserTest,
OriginToCommitSandboxFromParentDocument) {
GURL url_top = embedded_test_server()->GetURL(
"a.com", "/set-header?Content-Security-Policy: sandbox allow-scripts");
EXPECT_TRUE(NavigateToURL(shell(), url_top));
GURL url_iframe = embedded_test_server()->GetURL("a.com", "/empty.html");
TestNavigationManager manager(web_contents(), url_iframe);
ExecuteScriptAsync(current_frame_host(), R"(
let iframe = document.createElement("iframe");
iframe.src = "./empty.html";
document.body.appendChild(iframe);
)");
EXPECT_TRUE(manager.WaitForResponse());
FrameTreeNode* iframe = current_frame_host()->child_at(0);
NavigationRequest* navigation = iframe->navigation_request();
url::Origin origin_to_commit = navigation->GetOriginForURLLoaderFactory();
manager.WaitForNavigationFinished();
url::Origin origin_committed =
iframe->current_frame_host()->GetLastCommittedOrigin();
EXPECT_TRUE(origin_to_commit.opaque());
EXPECT_TRUE(origin_committed.opaque());
// TODO(https://crbug.com/888079). The nonce must match.
EXPECT_NE(origin_to_commit, origin_committed);
// Both document have the same URL. Only the first sets CSP:sandbox, but both
// are sandboxed. They get an opaque origin different from each others.
EXPECT_NE(current_frame_host()->GetLastCommittedOrigin(), origin_committed);
}
IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, OriginToCommitSandboxFromFrame) {
GURL url = embedded_test_server()->GetURL("a.com", "/empty.html");
EXPECT_TRUE(NavigateToURL(shell(), url));
TestNavigationManager manager(web_contents(), url);
ExecuteScriptAsync(current_frame_host(), R"(
let iframe = document.createElement("iframe");
iframe.src = location.href;
iframe.sandbox = "";
document.body.appendChild(iframe);
)");
EXPECT_TRUE(manager.WaitForResponse());
FrameTreeNode* iframe = current_frame_host()->child_at(0);
NavigationRequest* navigation = iframe->navigation_request();
url::Origin origin_to_commit = navigation->GetOriginForURLLoaderFactory();
manager.WaitForNavigationFinished();
url::Origin origin_committed =
iframe->current_frame_host()->GetLastCommittedOrigin();
EXPECT_TRUE(origin_to_commit.opaque());
EXPECT_TRUE(origin_committed.opaque());
// TODO(https://crbug.com/888079). Make the nonce to match.
EXPECT_NE(origin_to_commit, origin_committed);
}
class NetworkIsolationSplitCacheAppendIframeOrigin
: public NavigationBaseBrowserTest {
public:
NetworkIsolationSplitCacheAppendIframeOrigin() {
feature_list_.InitWithFeatures(
{net::features::kSplitCacheByNetworkIsolationKey,
net::features::kAppendFrameOriginToNetworkIsolationKey},
{});
}
private:
base::test::ScopedFeatureList feature_list_;
};
// Make a main document, have it request a cacheable subresources. Then make a
// same-site document in an iframe that serves the CSP:Sandbox header. Stop the
// test server, have the sandboxed document requests the same subresource. The
// request should fail. To make sure the request is actually in the cache, the
// main document should be able to request it again.
IN_PROC_BROWSER_TEST_F(NetworkIsolationSplitCacheAppendIframeOrigin,
SandboxedUsesDifferentCache) {
auto server = std::make_unique<net::EmbeddedTestServer>();
server->AddDefaultHandlers(GetTestDataFilePath());
EXPECT_TRUE(server->Start());
GURL url_main_document = server->GetURL("a.com", "/empty.html");
EXPECT_TRUE(NavigateToURL(shell(), url_main_document));
EXPECT_TRUE(ExecJs(current_frame_host(), R"(
new Promise(resolve => {
let iframe = document.createElement("iframe");
iframe.onload = resolve;
iframe.src = "/set-header?Content-Security-Policy: sandbox allow-scripts";
document.body.appendChild(iframe);
})
)"));
EXPECT_TRUE(WaitForLoadStop(web_contents()));
RenderFrameHostImpl* main_rfh = current_frame_host();
RenderFrameHostImpl* sub_rfh = main_rfh->child_at(0)->current_frame_host();
EXPECT_FALSE(main_rfh->GetLastCommittedOrigin().opaque());
EXPECT_TRUE(sub_rfh->GetLastCommittedOrigin().opaque());
const char* fetch_cacheable = R"(
fetch("cacheable.svg")
.then(() => "success")
.catch(() => "error")
)";
EXPECT_EQ("success", EvalJs(main_rfh, fetch_cacheable));
server.reset();
EXPECT_EQ("error", EvalJs(sub_rfh, fetch_cacheable));
EXPECT_EQ("success", EvalJs(main_rfh, fetch_cacheable));
}
} // namespace content
......@@ -681,15 +681,10 @@ url::Origin GetOriginForURLLoaderFactoryUnchecked(
return url::Origin::Create(common_params.base_url_for_data_url);
}
// MHTML frames should commit as a opaque origin (and should not be able to
// make network requests on behalf of the real origin).
if (navigation_request->IsLoadedFromMhtmlArchive())
return url::Origin();
// Srcdoc subframes need to inherit their origin from their parent frame.
if (navigation_request->GetURL().IsAboutSrcdoc()) {
// Srcdoc navigations in main frames should be blocked before this function
// is called. This should guarantee existence of a parent here.
// Srcdoc navigations in main frames are blocked before this function is
// called. This should guarantee existence of a parent here.
RenderFrameHostImpl* parent =
navigation_request->frame_tree_node()->parent();
DCHECK(parent);
......@@ -4350,10 +4345,33 @@ bool NavigationRequest::IsLoadDataWithBaseURL(
}
url::Origin NavigationRequest::GetOriginForURLLoaderFactory() {
// Calculate an approximation (sandbox/csp is ignored - see
DCHECK_GE(state_, WILL_PROCESS_RESPONSE);
// Calculate an approximation of the origin. The sandbox/csp are ignored.
url::Origin origin = GetOriginForURLLoaderFactoryUnchecked(this);
// Apply sandbox flags.
// See https://html.spec.whatwg.org/#sandboxed-origin-browsing-context-flag
// ```
// The 'sandboxed origin browsing context flag' forces content into a unique
// origin, thus preventing it from accessing other content from the same
// origin.
//
// This flag also prevents script from reading from or writing to the
// document.cookie IDL attribute, and blocks access to localStorage.
// ```
const bool use_opaque_origin = (sandbox_flags_to_commit_.value() &
network::mojom::WebSandboxFlags::kOrigin) ==
network::mojom::WebSandboxFlags::kOrigin;
if (use_opaque_origin)
origin = origin.DeriveNewOpaqueOrigin();
// MHTML documents should commit as an opaque origin. They should not be able
// to make network request on behalf of the real origin.
DCHECK(!IsLoadedFromMhtmlArchive() || use_opaque_origin);
// https://crbug.com/1041376) of the origin that will be committed because of
// |this| NavigationRequest.
url::Origin result = GetOriginForURLLoaderFactoryUnchecked(this);
// Note that GetRenderFrameHost() only allows to retrieve the RenderFrameHost
// once it has been set for this navigation. This will happens either at
......@@ -4362,14 +4380,22 @@ url::Origin NavigationRequest::GetOriginForURLLoaderFactory() {
RenderFrameHostImpl* target_frame = GetRenderFrameHost();
DCHECK(target_frame);
// Check that |result| origin is allowed to be accessed from the process that
// is the target of this navigation.
// Check that |origin| is allowed to be accessed from the process that is the
// target of this navigation.
if (target_frame->ShouldBypassSecurityChecksForErrorPage(this))
return result;
return origin;
// MHTML iframes can load documents from any origin, no matter the current
// policy of the process being used. This is because the content is loaded
// from the MHTML archive within the process. There are no data loaded from
// the network.
if (IsLoadedFromMhtmlArchive() && !IsInMainFrame())
return origin;
int process_id = target_frame->GetProcess()->GetID();
auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
CHECK(policy->CanAccessDataForOrigin(process_id, result));
return result;
CHECK(policy->CanAccessDataForOrigin(process_id, origin));
return origin;
}
void NavigationRequest::AsValueInto(
......
......@@ -712,9 +712,9 @@ class CONTENT_EXPORT NavigationRequest
// called after a response has been delivered for processing, or after the
// navigation fails with an error page.
//
// TODO(lukasza, arthursonzogni): https://crbug.com/888079: Once the browser
// process is able to calculate the exact origin to commit, the method below
// should be renamed to something like GetOriginToCommit().
// TODO(lukasza, arthursonzogni): https://crbug.com/888079: The browser and
// blink are both computing the origin to commit. This method should be
// renamed GetOriginToCommit() and the value pushed to blink.
url::Origin GetOriginForURLLoaderFactory();
// Add information about this NavigationRequest to |traced_value| for
......
<svg version="1.1"
baseProfile="full"
width="300" height="200"
xmlns="http://www.w3.org/2000/svg">
<text x="150"
y="125"
font-size="60"
text-anchor="middle"
fill="white">
SVG
</text>
</svg>
HTTP/1.1 200 OK
Content-Type: text/svg+xml
Cache-Control: max-age=3600
Access-Control-Allow-Origin: *
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