1 /*
2 * Copyright (C) 2011 Google Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27 #include "third_party/blink/renderer/core/execution_context/security_context.h"
28
29 #include "base/metrics/histogram_macros.h"
30 #include "services/network/public/cpp/web_sandbox_flags.h"
31 #include "third_party/blink/public/common/feature_policy/document_policy.h"
32 #include "third_party/blink/public/common/feature_policy/document_policy_features.h"
33 #include "third_party/blink/public/common/feature_policy/feature_policy.h"
34 #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
35 #include "third_party/blink/public/mojom/feature_policy/policy_value.mojom-blink.h"
36 #include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h"
37 #include "third_party/blink/public/platform/platform.h"
38 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
39 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
40 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
41 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
42
43 namespace blink {
44
45 // static
SerializeInsecureNavigationSet(const InsecureNavigationsSet & set)46 WTF::Vector<unsigned> SecurityContext::SerializeInsecureNavigationSet(
47 const InsecureNavigationsSet& set) {
48 // The set is serialized as a sorted array. Sorting it makes it easy to know
49 // if two serialized sets are equal.
50 WTF::Vector<unsigned> serialized;
51 serialized.ReserveCapacity(set.size());
52 for (unsigned host : set)
53 serialized.emplace_back(host);
54 std::sort(serialized.begin(), serialized.end());
55
56 return serialized;
57 }
58
SecurityContext(ExecutionContext * execution_context)59 SecurityContext::SecurityContext(ExecutionContext* execution_context)
60 : execution_context_(execution_context),
61 insecure_request_policy_(
62 mojom::blink::InsecureRequestPolicy::kLeaveInsecureRequestsAlone) {}
63
64 SecurityContext::~SecurityContext() = default;
65
Trace(Visitor * visitor) const66 void SecurityContext::Trace(Visitor* visitor) const {
67 visitor->Trace(execution_context_);
68 visitor->Trace(content_security_policy_);
69 }
70
SetSecurityOrigin(scoped_refptr<SecurityOrigin> security_origin)71 void SecurityContext::SetSecurityOrigin(
72 scoped_refptr<SecurityOrigin> security_origin) {
73 // Enforce that we don't change access, we might change the reference (via
74 // IsolatedCopy but we can't change the security policy).
75 CHECK(security_origin);
76 // The purpose of this check is to ensure that the SecurityContext does not
77 // change after script has executed in the ExecutionContext. If this is a
78 // RemoteSecurityContext, then there is no local script execution and the
79 // context is permitted to represent multiple origins over its lifetime, so it
80 // is safe for the SecurityOrigin to change.
81 // NOTE: A worker may need to make its origin opaque after the main worker
82 // script is loaded if the worker is origin-sandboxed. Specifically exempt
83 // that transition. See https://crbug.com/1068008. It would be great if we
84 // could get rid of this exemption.
85 bool is_worker_transition_to_opaque =
86 execution_context_ &&
87 execution_context_->IsWorkerOrWorkletGlobalScope() &&
88 IsSandboxed(network::mojom::blink::WebSandboxFlags::kOrigin) &&
89 security_origin->IsOpaque() &&
90 security_origin->GetOriginOrPrecursorOriginIfOpaque() == security_origin_;
91 CHECK(!execution_context_ || !security_origin_ ||
92 security_origin_->CanAccess(security_origin.get()) ||
93 is_worker_transition_to_opaque);
94 security_origin_ = std::move(security_origin);
95
96 if (!security_origin_->IsPotentiallyTrustworthy()) {
97 secure_context_mode_ = SecureContextMode::kInsecureContext;
98 secure_context_explanation_ = SecureContextModeExplanation::kInsecureScheme;
99 } else if (SchemeRegistry::SchemeShouldBypassSecureContextCheck(
100 security_origin_->Protocol())) {
101 secure_context_mode_ = SecureContextMode::kSecureContext;
102 secure_context_explanation_ = SecureContextModeExplanation::kSecure;
103 } else if (execution_context_) {
104 if (execution_context_->HasInsecureContextInAncestors()) {
105 secure_context_mode_ = SecureContextMode::kInsecureContext;
106 secure_context_explanation_ =
107 SecureContextModeExplanation::kInsecureAncestor;
108 } else {
109 secure_context_mode_ = SecureContextMode::kSecureContext;
110 secure_context_explanation_ =
111 security_origin_->IsLocalhost()
112 ? SecureContextModeExplanation::kSecureLocalhost
113 : SecureContextModeExplanation::kSecure;
114 }
115 }
116
117 bool is_secure = secure_context_mode_ == SecureContextMode::kSecureContext;
118 if (sandbox_flags_ != network::mojom::blink::WebSandboxFlags::kNone) {
119 UseCounter::Count(
120 execution_context_,
121 is_secure ? WebFeature::kSecureContextCheckForSandboxedOriginPassed
122 : WebFeature::kSecureContextCheckForSandboxedOriginFailed);
123 }
124
125 UseCounter::Count(execution_context_,
126 is_secure ? WebFeature::kSecureContextCheckPassed
127 : WebFeature::kSecureContextCheckFailed);
128 }
129
SetSecurityOriginForTesting(scoped_refptr<SecurityOrigin> security_origin)130 void SecurityContext::SetSecurityOriginForTesting(
131 scoped_refptr<SecurityOrigin> security_origin) {
132 security_origin_ = std::move(security_origin);
133 }
134
SetContentSecurityPolicy(ContentSecurityPolicy * content_security_policy)135 void SecurityContext::SetContentSecurityPolicy(
136 ContentSecurityPolicy* content_security_policy) {
137 content_security_policy_ = content_security_policy;
138 }
139
IsSandboxed(network::mojom::blink::WebSandboxFlags mask) const140 bool SecurityContext::IsSandboxed(
141 network::mojom::blink::WebSandboxFlags mask) const {
142 if (RuntimeEnabledFeatures::FeaturePolicyForSandboxEnabled()) {
143 mojom::blink::FeaturePolicyFeature feature =
144 FeaturePolicy::FeatureForSandboxFlag(mask);
145 if (feature != mojom::blink::FeaturePolicyFeature::kNotFound)
146 return !feature_policy_->IsFeatureEnabled(feature);
147 }
148 return (sandbox_flags_ & mask) !=
149 network::mojom::blink::WebSandboxFlags::kNone;
150 }
151
ApplySandboxFlags(network::mojom::blink::WebSandboxFlags flags)152 void SecurityContext::ApplySandboxFlags(
153 network::mojom::blink::WebSandboxFlags flags) {
154 sandbox_flags_ |= flags;
155 }
156
SetRequireTrustedTypes()157 void SecurityContext::SetRequireTrustedTypes() {
158 DCHECK(require_safe_types_ ||
159 content_security_policy_->IsRequireTrustedTypes());
160 require_safe_types_ = true;
161 }
162
SetRequireTrustedTypesForTesting()163 void SecurityContext::SetRequireTrustedTypesForTesting() {
164 require_safe_types_ = true;
165 }
166
TrustedTypesRequiredByPolicy() const167 bool SecurityContext::TrustedTypesRequiredByPolicy() const {
168 return require_safe_types_;
169 }
170
SetFeaturePolicy(std::unique_ptr<FeaturePolicy> feature_policy)171 void SecurityContext::SetFeaturePolicy(
172 std::unique_ptr<FeaturePolicy> feature_policy) {
173 feature_policy_ = std::move(feature_policy);
174 }
175
SetReportOnlyFeaturePolicy(std::unique_ptr<FeaturePolicy> feature_policy)176 void SecurityContext::SetReportOnlyFeaturePolicy(
177 std::unique_ptr<FeaturePolicy> feature_policy) {
178 report_only_feature_policy_ = std::move(feature_policy);
179 }
180
SetDocumentPolicy(std::unique_ptr<DocumentPolicy> policy)181 void SecurityContext::SetDocumentPolicy(
182 std::unique_ptr<DocumentPolicy> policy) {
183 document_policy_ = std::move(policy);
184 }
185
SetReportOnlyDocumentPolicy(std::unique_ptr<DocumentPolicy> policy)186 void SecurityContext::SetReportOnlyDocumentPolicy(
187 std::unique_ptr<DocumentPolicy> policy) {
188 report_only_document_policy_ = std::move(policy);
189 }
190
IsFeatureEnabled(mojom::blink::FeaturePolicyFeature feature,bool * should_report) const191 bool SecurityContext::IsFeatureEnabled(
192 mojom::blink::FeaturePolicyFeature feature,
193 bool* should_report) const {
194 DCHECK(feature_policy_);
195 bool feature_policy_result = feature_policy_->IsFeatureEnabled(feature);
196 bool report_only_feature_policy_result =
197 !report_only_feature_policy_ ||
198 report_only_feature_policy_->IsFeatureEnabled(feature);
199
200 if (should_report) {
201 *should_report =
202 !feature_policy_result || !report_only_feature_policy_result;
203 }
204
205 return feature_policy_result;
206 }
207
IsFeatureEnabled(mojom::blink::DocumentPolicyFeature feature) const208 bool SecurityContext::IsFeatureEnabled(
209 mojom::blink::DocumentPolicyFeature feature) const {
210 DCHECK(GetDocumentPolicyFeatureInfoMap().at(feature).default_value.Type() ==
211 mojom::blink::PolicyValueType::kBool);
212 return IsFeatureEnabled(feature, PolicyValue::CreateBool(true)).enabled;
213 }
214
IsFeatureEnabled(mojom::blink::DocumentPolicyFeature feature,PolicyValue threshold_value) const215 SecurityContext::FeatureStatus SecurityContext::IsFeatureEnabled(
216 mojom::blink::DocumentPolicyFeature feature,
217 PolicyValue threshold_value) const {
218 DCHECK(document_policy_);
219 bool policy_result =
220 document_policy_->IsFeatureEnabled(feature, threshold_value);
221 bool report_only_policy_result =
222 !report_only_document_policy_ ||
223 report_only_document_policy_->IsFeatureEnabled(feature, threshold_value);
224 return {policy_result, !policy_result || !report_only_policy_result};
225 }
226
227 } // namespace blink
228