1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_CSP_DIRECTIVE_LIST_H_
6 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_CSP_DIRECTIVE_LIST_H_
7 
8 #include "base/macros.h"
9 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
10 #include "third_party/blink/renderer/core/frame/csp/media_list_directive.h"
11 #include "third_party/blink/renderer/core/frame/csp/require_trusted_types_for_directive.h"
12 #include "third_party/blink/renderer/core/frame/csp/source_list_directive.h"
13 #include "third_party/blink/renderer/core/frame/csp/string_list_directive.h"
14 #include "third_party/blink/renderer/platform/heap/handle.h"
15 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
16 #include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
17 #include "third_party/blink/renderer/platform/network/http_parsers.h"
18 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
19 #include "third_party/blink/renderer/platform/weborigin/reporting_disposition.h"
20 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
21 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
22 #include "third_party/blink/renderer/platform/wtf/vector.h"
23 
24 namespace blink {
25 
26 class ContentSecurityPolicy;
27 enum class ResourceType : uint8_t;
28 
29 typedef HeapVector<Member<SourceListDirective>> SourceListDirectiveVector;
30 
31 class CORE_EXPORT CSPDirectiveList final
32     : public GarbageCollected<CSPDirectiveList> {
33  public:
34   static CSPDirectiveList* Create(ContentSecurityPolicy*,
35                                   const UChar* begin,
36                                   const UChar* end,
37                                   network::mojom::ContentSecurityPolicyType,
38                                   network::mojom::ContentSecurityPolicySource,
39                                   bool should_parse_wasm_eval = false);
40 
41   CSPDirectiveList(ContentSecurityPolicy*,
42                    network::mojom::ContentSecurityPolicyType,
43                    network::mojom::ContentSecurityPolicySource);
44 
45   void Parse(const UChar* begin,
46              const UChar* end,
47              bool should_parse_wasm_eval = false);
48 
Header()49   const String& Header() const { return header_; }
HeaderType()50   network::mojom::ContentSecurityPolicyType HeaderType() const {
51     return header_type_;
52   }
HeaderSource()53   network::mojom::ContentSecurityPolicySource HeaderSource() const {
54     return header_source_;
55   }
56 
57   bool AllowInline(ContentSecurityPolicy::InlineType,
58                    Element*,
59                    const String& content,
60                    const String& nonce,
61                    const String& context_url,
62                    const WTF::OrdinalNumber& context_line,
63                    ReportingDisposition) const;
64 
65   // Returns whether or not the Javascript code generation should call back the
66   // CSP checker before any script evaluation from a string is being made.
67   bool ShouldCheckEval() const;
68 
69   bool AllowEval(ReportingDisposition,
70                  ContentSecurityPolicy::ExceptionStatus,
71                  const String& script_content) const;
72   bool AllowWasmEval(ReportingDisposition,
73                      ContentSecurityPolicy::ExceptionStatus,
74                      const String& script_content) const;
75   bool AllowPluginType(const String& type,
76                        const String& type_attribute,
77                        const KURL&,
78                        ReportingDisposition) const;
79 
80   bool AllowFromSource(ContentSecurityPolicy::DirectiveType,
81                        const KURL&,
82                        const KURL& url_before_redirects,
83                        ResourceRequest::RedirectStatus,
84                        ReportingDisposition,
85                        const String& nonce = String(),
86                        const IntegrityMetadataSet& = IntegrityMetadataSet(),
87                        ParserDisposition = kParserInserted) const;
88 
89   bool AllowTrustedTypePolicy(const String& policy_name,
90                               bool is_duplicate) const;
91 
92   bool AllowDynamic(ContentSecurityPolicy::DirectiveType) const;
93   bool AllowDynamicWorker() const;
94 
95   bool AllowTrustedTypeAssignmentFailure(const String& message,
96                                          const String& sample,
97                                          const String& sample_prefix) const;
98 
StrictMixedContentChecking()99   bool StrictMixedContentChecking() const {
100     return strict_mixed_content_checking_enforced_;
101   }
102   void ReportMixedContent(const KURL& blocked_url,
103                           ResourceRequest::RedirectStatus) const;
104 
ShouldDisableEval()105   bool ShouldDisableEval() const {
106     return ShouldDisableEvalBecauseScriptSrc() ||
107            ShouldDisableEvalBecauseTrustedTypes();
108   }
109   bool ShouldDisableEvalBecauseScriptSrc() const;
110   bool ShouldDisableEvalBecauseTrustedTypes() const;
EvalDisabledErrorMessage()111   const String& EvalDisabledErrorMessage() const {
112     return eval_disabled_error_message_;
113   }
IsReportOnly()114   bool IsReportOnly() const {
115     return header_type_ == network::mojom::ContentSecurityPolicyType::kReport;
116   }
IsActiveForConnections()117   bool IsActiveForConnections() const {
118     return OperativeDirective(
119         ContentSecurityPolicy::DirectiveType::kConnectSrc);
120   }
ReportEndpoints()121   const Vector<String>& ReportEndpoints() const { return report_endpoints_; }
UseReportingApi()122   bool UseReportingApi() const { return use_reporting_api_; }
123 
124   // Used to copy plugin-types into a plugin document in a nested
125   // browsing context.
HasPluginTypes()126   bool HasPluginTypes() const { return !!plugin_types_; }
127   const String& PluginTypesText() const;
128 
129   bool ShouldSendCSPHeader(ResourceType) const;
130 
131   bool AllowHash(const CSPHashValue& hash_value,
132                  const ContentSecurityPolicy::InlineType inline_type) const;
133 
134   // The algorithm is described here:
135   // https://w3c.github.io/webappsec-csp/embedded/#subsume-policy
136   bool Subsumes(const CSPDirectiveListVector&);
137 
138   // Export a subset of the Policy. The primary goal of this method is to make
139   // the embedders aware of the directives that affect navigation, as the
140   // embedder is responsible for navigational enforcement.
141   // It currently contains the following ones:
142   // * default-src
143   // * child-src
144   // * frame-src
145   // * form-action
146   // * upgrade-insecure-requests
147   // * navigate-to
148   // The exported directives only contains sources that affect navigation. For
149   // instance it doesn't contains 'unsafe-inline' or 'unsafe-eval'
150   network::mojom::blink::ContentSecurityPolicyPtr ExposeForNavigationalChecks()
151       const;
152 
153   // We consider `object-src` restrictions to be reasonable iff they're
154   // equivalent to `object-src 'none'`.
155   bool IsObjectRestrictionReasonable() const;
156 
157   // We consider `base-uri` restrictions to be reasonable iff they're equivalent
158   // to `base-uri 'none'` or `base-uri 'self'`.
159   bool IsBaseRestrictionReasonable() const;
160 
161   // We consider `script-src` restrictions to be reasonable iff they're not
162   // URL-based (e.g. they contain only nonces and hashes, or they use
163   // 'strict-dynamic'). Neither `'unsafe-eval'` nor `'unsafe-hashes'` affect
164   // this judgement.
165   bool IsScriptRestrictionReasonable() const;
166 
RequiresTrustedTypes()167   bool RequiresTrustedTypes() const {
168     return require_trusted_types_for_ && require_trusted_types_for_->require();
169   }
TrustedTypesAllowDuplicates()170   bool TrustedTypesAllowDuplicates() const {
171     return trusted_types_ && trusted_types_->IsAllowDuplicates();
172   }
173 
174   void Trace(Visitor*) const;
175 
176  private:
177   FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, IsMatchingNoncePresent);
178   FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, GetSourceVector);
179   FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, OperativeDirectiveGivenType);
180 
181   bool ParseDirective(const UChar* begin,
182                       const UChar* end,
183                       String* name,
184                       String* value);
185   void ParseReportURI(const String& name, const String& value);
186   void ParseReportTo(const String& name, const String& value);
187   void ParseAndAppendReportEndpoints(const String& value);
188   void ParsePluginTypes(const String& name, const String& value);
189   void AddDirective(const String& name, const String& value);
190   void ApplySandboxPolicy(const String& name, const String& sandbox_policy);
191   void ApplyTreatAsPublicAddress();
192   void EnforceStrictMixedContentChecking(const String& name,
193                                          const String& value);
194   void EnableInsecureRequestsUpgrade(const String& name, const String& value);
195   void AddTrustedTypes(const String& name, const String& value);
196   void RequireTrustedTypesFor(const String& name, const String& value);
197 
198   template <class CSPDirectiveType>
199   void SetCSPDirective(const String& name,
200                        const String& value,
201                        Member<CSPDirectiveType>&,
202                        bool should_parse_wasm_eval = false);
203 
204   ContentSecurityPolicy::DirectiveType FallbackDirective(
205       const ContentSecurityPolicy::DirectiveType current_directive,
206       const ContentSecurityPolicy::DirectiveType original_directive) const;
207   void ReportViolation(
208       const String& directive_text,
209       const ContentSecurityPolicy::DirectiveType,
210       const String& console_message,
211       const KURL& blocked_url,
212       ResourceRequest::RedirectStatus,
213       ContentSecurityPolicy::ContentSecurityPolicyViolationType violation_type =
214           ContentSecurityPolicy::kURLViolation,
215       const String& sample = String(),
216       const String& sample_prefix = String()) const;
217   void ReportViolationWithFrame(const String& directive_text,
218                                 const ContentSecurityPolicy::DirectiveType,
219                                 const String& console_message,
220                                 const KURL& blocked_url,
221                                 LocalFrame*) const;
222   void ReportViolationWithLocation(const String& directive_text,
223                                    const ContentSecurityPolicy::DirectiveType,
224                                    const String& console_message,
225                                    const KURL& blocked_url,
226                                    const String& context_url,
227                                    const WTF::OrdinalNumber& context_line,
228                                    Element*,
229                                    const String& source) const;
230   void ReportEvalViolation(const String& directive_text,
231                            const ContentSecurityPolicy::DirectiveType,
232                            const String& message,
233                            const KURL& blocked_url,
234                            const ContentSecurityPolicy::ExceptionStatus,
235                            const String& content) const;
236 
237   bool CheckEval(SourceListDirective*) const;
238   bool CheckWasmEval(SourceListDirective*) const;
239   bool CheckDynamic(SourceListDirective*) const;
240   bool IsMatchingNoncePresent(SourceListDirective*, const String&) const;
241   bool AreAllMatchingHashesPresent(SourceListDirective*,
242                                    const IntegrityMetadataSet&) const;
243   bool CheckHash(SourceListDirective*, const CSPHashValue&) const;
244   bool CheckUnsafeHashesAllowed(SourceListDirective*) const;
245   bool CheckSource(SourceListDirective*,
246                    const KURL&,
247                    ResourceRequest::RedirectStatus) const;
248   bool CheckMediaType(MediaListDirective*,
249                       const String& type,
250                       const String& type_attribute) const;
251 
SetEvalDisabledErrorMessage(const String & error_message)252   void SetEvalDisabledErrorMessage(const String& error_message) {
253     eval_disabled_error_message_ = error_message;
254   }
255 
256   bool CheckEvalAndReportViolation(SourceListDirective*,
257                                    const String& console_message,
258                                    ContentSecurityPolicy::ExceptionStatus,
259                                    const String& script_content) const;
260   bool CheckWasmEvalAndReportViolation(SourceListDirective*,
261                                        const String& console_message,
262                                        ContentSecurityPolicy::ExceptionStatus,
263                                        const String& script_content) const;
264   bool CheckInlineAndReportViolation(
265       SourceListDirective*,
266       const String& console_message,
267       Element*,
268       const String& source,
269       const String& context_url,
270       const WTF::OrdinalNumber& context_line,
271       bool is_script,
272       const String& hash_value,
273       ContentSecurityPolicy::DirectiveType effective_type) const;
274 
275   bool CheckSourceAndReportViolation(SourceListDirective*,
276                                      const KURL&,
277                                      const ContentSecurityPolicy::DirectiveType,
278                                      const KURL& url_before_redirects,
279                                      ResourceRequest::RedirectStatus) const;
280   bool CheckMediaTypeAndReportViolation(MediaListDirective*,
281                                         const String& type,
282                                         const String& type_attribute,
283                                         const String& console_message) const;
284 
DenyIfEnforcingPolicy()285   bool DenyIfEnforcingPolicy() const { return IsReportOnly(); }
286 
287   // This function returns a SourceListDirective of a given type
288   // or if it is not defined, the fallback SourceListDirective for that type.
289   SourceListDirective* OperativeDirective(
290       const ContentSecurityPolicy::DirectiveType type,
291       ContentSecurityPolicy::DirectiveType original_type =
292           ContentSecurityPolicy::DirectiveType::kUndefined) const;
293 
294   // This function aggregates from a vector of policies all operative
295   // SourceListDirectives of a given type into a vector.
296   static SourceListDirectiveVector GetSourceVector(
297       const ContentSecurityPolicy::DirectiveType,
298       const CSPDirectiveListVector& policies);
299 
300   Member<ContentSecurityPolicy> policy_;
301 
302   String header_;
303   network::mojom::ContentSecurityPolicyType header_type_;
304   network::mojom::ContentSecurityPolicySource header_source_;
305 
306   bool has_sandbox_policy_;
307 
308   bool strict_mixed_content_checking_enforced_;
309 
310   bool upgrade_insecure_requests_;
311 
312   Member<MediaListDirective> plugin_types_;
313   Member<SourceListDirective> base_uri_;
314   Member<SourceListDirective> child_src_;
315   Member<SourceListDirective> connect_src_;
316   Member<SourceListDirective> default_src_;
317   Member<SourceListDirective> font_src_;
318   Member<SourceListDirective> form_action_;
319   Member<SourceListDirective> frame_ancestors_;
320   Member<SourceListDirective> frame_src_;
321   Member<SourceListDirective> img_src_;
322   Member<SourceListDirective> media_src_;
323   Member<SourceListDirective> manifest_src_;
324   Member<SourceListDirective> object_src_;
325   Member<SourceListDirective> prefetch_src_;
326   Member<SourceListDirective> script_src_;
327   Member<SourceListDirective> script_src_attr_;
328   Member<SourceListDirective> script_src_elem_;
329   Member<SourceListDirective> style_src_;
330   Member<SourceListDirective> style_src_attr_;
331   Member<SourceListDirective> style_src_elem_;
332   Member<SourceListDirective> worker_src_;
333   Member<SourceListDirective> navigate_to_;
334   Member<StringListDirective> trusted_types_;
335   Member<RequireTrustedTypesForDirective> require_trusted_types_for_;
336 
337   // If a "report-to" directive is used:
338   // - |report_endpoints_| is a list of token parsed from the "report-to"
339   //   directive's value, and
340   // - |use_reporting_api_| is true.
341   // Otherwise,
342   // - |report_endpoints_| is a list of uri-reference parsed from a
343   //   "report-uri" directive's value if any, and
344   // - |use_reporting_api_| is false.
345   Vector<String> report_endpoints_;
346   bool use_reporting_api_;
347 
348   String eval_disabled_error_message_;
349 
350   DISALLOW_COPY_AND_ASSIGN(CSPDirectiveList);
351 };
352 
353 }  // namespace blink
354 
355 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_CSP_DIRECTIVE_LIST_H_
356