blob: a6a14db6b0fed6ebde492258da20e9cb5d374e44 [file] [log] [blame]
/*
* Copyright (C) 2011 Google Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "third_party/blink/renderer/core/execution_context/security_context.h"
#include "base/metrics/histogram_macros.h"
#include "services/network/public/cpp/web_sandbox_flags.h"
#include "third_party/blink/public/common/feature_policy/document_policy.h"
#include "third_party/blink/public/common/feature_policy/document_policy_features.h"
#include "third_party/blink/public/common/feature_policy/feature_policy.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
#include "third_party/blink/public/mojom/feature_policy/policy_value.mojom-blink.h"
#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
namespace blink {
// static
WTF::Vector<unsigned> SecurityContext::SerializeInsecureNavigationSet(
const InsecureNavigationsSet& set) {
// The set is serialized as a sorted array. Sorting it makes it easy to know
// if two serialized sets are equal.
WTF::Vector<unsigned> serialized;
serialized.ReserveCapacity(set.size());
for (unsigned host : set)
serialized.emplace_back(host);
std::sort(serialized.begin(), serialized.end());
return serialized;
}
SecurityContext::SecurityContext(ExecutionContext* execution_context)
: execution_context_(execution_context),
insecure_request_policy_(
mojom::blink::InsecureRequestPolicy::kLeaveInsecureRequestsAlone) {}
SecurityContext::~SecurityContext() = default;
void SecurityContext::Trace(Visitor* visitor) const {
visitor->Trace(execution_context_);
visitor->Trace(content_security_policy_);
}
void SecurityContext::SetSecurityOrigin(
scoped_refptr<SecurityOrigin> security_origin) {
// Enforce that we don't change access, we might change the reference (via
// IsolatedCopy but we can't change the security policy).
CHECK(security_origin);
// The purpose of this check is to ensure that the SecurityContext does not
// change after script has executed in the ExecutionContext. If this is a
// RemoteSecurityContext, then there is no local script execution and the
// context is permitted to represent multiple origins over its lifetime, so it
// is safe for the SecurityOrigin to change.
// NOTE: A worker may need to make its origin opaque after the main worker
// script is loaded if the worker is origin-sandboxed. Specifically exempt
// that transition. See https://crbug.com/1068008. It would be great if we
// could get rid of this exemption.
bool is_worker_transition_to_opaque =
execution_context_ &&
execution_context_->IsWorkerOrWorkletGlobalScope() &&
IsSandboxed(network::mojom::blink::WebSandboxFlags::kOrigin) &&
security_origin->IsOpaque() &&
security_origin->GetOriginOrPrecursorOriginIfOpaque() == security_origin_;
CHECK(!execution_context_ || !security_origin_ ||
security_origin_->CanAccess(security_origin.get()) ||
is_worker_transition_to_opaque);
security_origin_ = std::move(security_origin);
if (!security_origin_->IsPotentiallyTrustworthy()) {
secure_context_mode_ = SecureContextMode::kInsecureContext;
secure_context_explanation_ = SecureContextModeExplanation::kInsecureScheme;
} else if (SchemeRegistry::SchemeShouldBypassSecureContextCheck(
security_origin_->Protocol())) {
secure_context_mode_ = SecureContextMode::kSecureContext;
secure_context_explanation_ = SecureContextModeExplanation::kSecure;
} else if (execution_context_) {
if (execution_context_->HasInsecureContextInAncestors()) {
secure_context_mode_ = SecureContextMode::kInsecureContext;
secure_context_explanation_ =
SecureContextModeExplanation::kInsecureAncestor;
} else {
secure_context_mode_ = SecureContextMode::kSecureContext;
secure_context_explanation_ =
security_origin_->IsLocalhost()
? SecureContextModeExplanation::kSecureLocalhost
: SecureContextModeExplanation::kSecure;
}
}
bool is_secure = secure_context_mode_ == SecureContextMode::kSecureContext;
if (sandbox_flags_ != network::mojom::blink::WebSandboxFlags::kNone) {
UseCounter::Count(
execution_context_,
is_secure ? WebFeature::kSecureContextCheckForSandboxedOriginPassed
: WebFeature::kSecureContextCheckForSandboxedOriginFailed);
}
UseCounter::Count(execution_context_,
is_secure ? WebFeature::kSecureContextCheckPassed
: WebFeature::kSecureContextCheckFailed);
}
void SecurityContext::SetSecurityOriginForTesting(
scoped_refptr<SecurityOrigin> security_origin) {
security_origin_ = std::move(security_origin);
}
void SecurityContext::SetContentSecurityPolicy(
ContentSecurityPolicy* content_security_policy) {
content_security_policy_ = content_security_policy;
}
bool SecurityContext::IsSandboxed(
network::mojom::blink::WebSandboxFlags mask) const {
if (RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled()) {
mojom::blink::FeaturePolicyFeature feature =
FeaturePolicy::FeatureForSandboxFlag(mask);
if (feature != mojom::blink::FeaturePolicyFeature::kNotFound)
return !feature_policy_->IsFeatureEnabled(feature);
}
return (sandbox_flags_ & mask) !=
network::mojom::blink::WebSandboxFlags::kNone;
}
void SecurityContext::ApplySandboxFlags(
network::mojom::blink::WebSandboxFlags flags) {
sandbox_flags_ |= flags;
}
void SecurityContext::SetRequireTrustedTypes() {
DCHECK(require_safe_types_ ||
content_security_policy_->IsRequireTrustedTypes());
require_safe_types_ = true;
}
void SecurityContext::SetRequireTrustedTypesForTesting() {
require_safe_types_ = true;
}
bool SecurityContext::TrustedTypesRequiredByPolicy() const {
return require_safe_types_;
}
void SecurityContext::SetFeaturePolicy(
std::unique_ptr<FeaturePolicy> feature_policy) {
feature_policy_ = std::move(feature_policy);
}
void SecurityContext::SetReportOnlyFeaturePolicy(
std::unique_ptr<FeaturePolicy> feature_policy) {
report_only_feature_policy_ = std::move(feature_policy);
}
void SecurityContext::SetDocumentPolicy(
std::unique_ptr<DocumentPolicy> policy) {
document_policy_ = std::move(policy);
}
void SecurityContext::SetReportOnlyDocumentPolicy(
std::unique_ptr<DocumentPolicy> policy) {
report_only_document_policy_ = std::move(policy);
}
bool SecurityContext::IsFeatureEnabled(
mojom::blink::FeaturePolicyFeature feature,
bool* should_report) const {
DCHECK(feature_policy_);
bool feature_policy_result = feature_policy_->IsFeatureEnabled(feature);
bool report_only_feature_policy_result =
!report_only_feature_policy_ ||
report_only_feature_policy_->IsFeatureEnabled(feature);
if (should_report) {
*should_report =
!feature_policy_result || !report_only_feature_policy_result;
}
return feature_policy_result;
}
bool SecurityContext::IsFeatureEnabled(
mojom::blink::DocumentPolicyFeature feature) const {
DCHECK(GetDocumentPolicyFeatureInfoMap().at(feature).default_value.Type() ==
mojom::blink::PolicyValueType::kBool);
return IsFeatureEnabled(feature, PolicyValue::CreateBool(true)).enabled;
}
SecurityContext::FeatureStatus SecurityContext::IsFeatureEnabled(
mojom::blink::DocumentPolicyFeature feature,
PolicyValue threshold_value) const {
DCHECK(document_policy_);
bool policy_result =
document_policy_->IsFeatureEnabled(feature, threshold_value);
bool report_only_policy_result =
!report_only_document_policy_ ||
report_only_document_policy_->IsFeatureEnabled(feature, threshold_value);
return {policy_result, !policy_result || !report_only_policy_result};
}
} // namespace blink