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