blob: fdab78944ac0b5f369c94fbda894e2b65a11a261 [file] [log] [blame]
// Copyright 2017 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 "third_party/blink/renderer/bindings/core/v8/binding_security.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
namespace blink {
namespace {
const char kMainFrame[] = "https://example.com/main.html";
const char kSameOriginTarget[] = "https://example.com/target.html";
const char kSameOriginDomainTarget[] = "https://sub.example.com/target.html";
const char kCrossOriginTarget[] = "https://not-example.com/target.html";
const char kTargetHTML[] =
"<!DOCTYPE html>"
"<script>"
" (window.opener || window.top).postMessage('yay', '*');"
"</script>";
const char kSameOriginDomainTargetHTML[] =
"<!DOCTYPE html>"
"<script>"
" document.domain = 'example.com';"
" (window.opener || window.top).postMessage('yay', '*');"
"</script>";
}
class BindingSecurityCounterTest
: public SimTest,
public testing::WithParamInterface<const char*> {
public:
enum class OriginDisposition { CrossOrigin, SameOrigin, SameOriginDomain };
BindingSecurityCounterTest() = default;
void LoadWindowAndAccessProperty(OriginDisposition which_origin,
const String& property) {
const char* target_url;
const char* target_html;
switch (which_origin) {
case OriginDisposition::CrossOrigin:
target_url = kCrossOriginTarget;
target_html = kTargetHTML;
break;
case OriginDisposition::SameOrigin:
target_url = kSameOriginTarget;
target_html = kTargetHTML;
break;
case OriginDisposition::SameOriginDomain:
target_url = kSameOriginDomainTarget;
target_html = kSameOriginDomainTargetHTML;
break;
}
SimRequest main(kMainFrame, "text/html");
SimRequest target(target_url, "text/html");
const String& document = String::Format(
"<!DOCTYPE html>"
"<script>"
" %s"
" window.addEventListener('message', e => {"
" window.other = e.source.%s;"
" console.log('yay');"
" });"
" var w = window.open('%s');"
"</script>",
which_origin == OriginDisposition::SameOriginDomain
? "document.domain = 'example.com';"
: "",
property.Utf8().data(), target_url);
LoadURL(kMainFrame);
main.Complete(document);
target.Complete(target_html);
test::RunPendingTasks();
}
void LoadFrameAndAccessProperty(OriginDisposition which_origin,
const String& property) {
const char* target_url;
const char* target_html;
switch (which_origin) {
case OriginDisposition::CrossOrigin:
target_url = kCrossOriginTarget;
target_html = kTargetHTML;
break;
case OriginDisposition::SameOrigin:
target_url = kSameOriginTarget;
target_html = kTargetHTML;
break;
case OriginDisposition::SameOriginDomain:
target_url = kSameOriginDomainTarget;
target_html = kSameOriginDomainTargetHTML;
break;
}
SimRequest main(kMainFrame, "text/html");
SimRequest target(target_url, "text/html");
const String& document = String::Format(
"<!DOCTYPE html>"
"<body>"
"<script>"
" %s"
" var i = document.createElement('iframe');"
" window.addEventListener('message', e => {"
" window.other = e.source.%s;"
" console.log('yay');"
" });"
" i.src = '%s';"
" document.body.appendChild(i);"
"</script>",
which_origin == OriginDisposition::SameOriginDomain
? "document.domain = 'example.com';"
: "",
property.Utf8().data(), target_url);
LoadURL(kMainFrame);
main.Complete(document);
target.Complete(target_html);
test::RunPendingTasks();
}
};
INSTANTIATE_TEST_CASE_P(WindowProperties,
BindingSecurityCounterTest,
testing::Values("window",
"self",
"location",
"close",
"closed",
"focus",
"blur",
"frames",
"length",
"top",
"opener",
"parent",
"postMessage"));
TEST_P(BindingSecurityCounterTest, CrossOriginWindow) {
LoadWindowAndAccessProperty(OriginDisposition::CrossOrigin, GetParam());
EXPECT_TRUE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kCrossOriginPropertyAccess));
EXPECT_TRUE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kCrossOriginPropertyAccessFromOpener));
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kDocumentDomainEnabledCrossOriginAccess));
}
TEST_P(BindingSecurityCounterTest, SameOriginWindow) {
LoadWindowAndAccessProperty(OriginDisposition::SameOrigin, GetParam());
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kCrossOriginPropertyAccess));
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kCrossOriginPropertyAccessFromOpener));
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kDocumentDomainEnabledCrossOriginAccess));
}
TEST_P(BindingSecurityCounterTest, SameOriginDomainWindow) {
LoadWindowAndAccessProperty(OriginDisposition::SameOriginDomain, GetParam());
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kCrossOriginPropertyAccess));
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kCrossOriginPropertyAccessFromOpener));
EXPECT_TRUE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kDocumentDomainEnabledCrossOriginAccess));
}
TEST_P(BindingSecurityCounterTest, CrossOriginFrame) {
LoadFrameAndAccessProperty(OriginDisposition::CrossOrigin, GetParam());
EXPECT_TRUE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kCrossOriginPropertyAccess));
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kCrossOriginPropertyAccessFromOpener));
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kDocumentDomainEnabledCrossOriginAccess));
}
TEST_P(BindingSecurityCounterTest, SameOriginFrame) {
LoadFrameAndAccessProperty(OriginDisposition::SameOrigin, GetParam());
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kCrossOriginPropertyAccess));
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kCrossOriginPropertyAccessFromOpener));
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kDocumentDomainEnabledCrossOriginAccess));
}
TEST_P(BindingSecurityCounterTest, SameOriginDomainFrame) {
LoadFrameAndAccessProperty(OriginDisposition::SameOriginDomain, GetParam());
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kCrossOriginPropertyAccess));
EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kCrossOriginPropertyAccessFromOpener));
EXPECT_TRUE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
WebFeature::kDocumentDomainEnabledCrossOriginAccess));
}
} // namespace