1 // Copyright 2013 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 #include <stddef.h>
6
7 #include "base/strings/string_split.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "extensions/common/csp_validator.h"
12 #include "extensions/common/error_utils.h"
13 #include "extensions/common/install_warning.h"
14 #include "extensions/common/manifest_constants.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 using extensions::csp_validator::ContentSecurityPolicyIsLegal;
18 using extensions::csp_validator::GetEffectiveSandoxedPageCSP;
19 using extensions::csp_validator::SanitizeContentSecurityPolicy;
20 using extensions::csp_validator::ContentSecurityPolicyIsSandboxed;
21 using extensions::csp_validator::OPTIONS_NONE;
22 using extensions::csp_validator::OPTIONS_ALLOW_UNSAFE_EVAL;
23 using extensions::csp_validator::OPTIONS_ALLOW_INSECURE_OBJECT_SRC;
24 using extensions::ErrorUtils;
25 using extensions::InstallWarning;
26 using extensions::Manifest;
27
28 namespace {
29
InsecureValueWarning(const std::string & directive,const std::string & value,const std::string & manifest_key=extensions::manifest_keys::kContentSecurityPolicy)30 std::string InsecureValueWarning(
31 const std::string& directive,
32 const std::string& value,
33 const std::string& manifest_key =
34 extensions::manifest_keys::kContentSecurityPolicy) {
35 return ErrorUtils::FormatErrorMessage(
36 extensions::manifest_errors::kInvalidCSPInsecureValueIgnored,
37 manifest_key, value, directive);
38 }
39
MissingSecureSrcWarning(const std::string & manifest_key,const std::string & directive)40 std::string MissingSecureSrcWarning(const std::string& manifest_key,
41 const std::string& directive) {
42 return ErrorUtils::FormatErrorMessage(
43 extensions::manifest_errors::kInvalidCSPMissingSecureSrc, manifest_key,
44 directive);
45 }
46
CSPEquals(const std::string & csp1,const std::string & csp2)47 bool CSPEquals(const std::string& csp1, const std::string& csp2) {
48 std::vector<std::string> csp1_parts = base::SplitString(
49 csp1, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
50 std::sort(csp1_parts.begin(), csp1_parts.end());
51 std::vector<std::string> csp2_parts = base::SplitString(
52 csp2, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
53 std::sort(csp2_parts.begin(), csp2_parts.end());
54 return csp1_parts == csp2_parts;
55 }
56
57 struct SanitizedCSPResult {
58 std::string csp;
59 std::vector<InstallWarning> warnings;
60 };
61
SanitizeCSP(const std::string & policy,int options)62 SanitizedCSPResult SanitizeCSP(const std::string& policy, int options) {
63 SanitizedCSPResult result;
64 result.csp = SanitizeContentSecurityPolicy(
65 policy, extensions::manifest_keys::kContentSecurityPolicy, options,
66 &result.warnings);
67 return result;
68 }
69
SanitizeSandboxPageCSP(const std::string & policy)70 SanitizedCSPResult SanitizeSandboxPageCSP(const std::string& policy) {
71 SanitizedCSPResult result;
72 result.csp = GetEffectiveSandoxedPageCSP(
73 policy, extensions::manifest_keys::kSandboxedPagesCSP, &result.warnings);
74 return result;
75 }
76
CheckCSP(const SanitizedCSPResult & actual,const std::string & expected_csp,const std::vector<std::string> & expected_warnings)77 testing::AssertionResult CheckCSP(
78 const SanitizedCSPResult& actual,
79 const std::string& expected_csp,
80 const std::vector<std::string>& expected_warnings) {
81 if (!CSPEquals(expected_csp, actual.csp)) {
82 return testing::AssertionFailure()
83 << "SanitizeContentSecurityPolicy returned an unexpected CSP.\n"
84 << "Expected CSP: " << expected_csp << "\n"
85 << " Actual CSP: " << actual.csp;
86 }
87
88 if (expected_warnings.size() != actual.warnings.size()) {
89 testing::Message msg;
90 msg << "Expected " << expected_warnings.size() << " warnings, but got "
91 << actual.warnings.size();
92 for (size_t i = 0; i < actual.warnings.size(); ++i)
93 msg << "\nWarning " << i << " " << actual.warnings[i].message;
94 return testing::AssertionFailure() << msg;
95 }
96
97 for (size_t i = 0; i < expected_warnings.size(); ++i) {
98 if (expected_warnings[i] != actual.warnings[i].message)
99 return testing::AssertionFailure()
100 << "Unexpected warning from SanitizeContentSecurityPolicy.\n"
101 << "Expected warning[" << i << "]: " << expected_warnings[i]
102 << " Actual warning[" << i << "]: " << actual.warnings[i].message;
103 }
104 return testing::AssertionSuccess();
105 }
106
CheckCSP(const SanitizedCSPResult & actual)107 testing::AssertionResult CheckCSP(const SanitizedCSPResult& actual) {
108 return CheckCSP(actual, actual.csp, std::vector<std::string>());
109 }
110
CheckCSP(const SanitizedCSPResult & actual,const std::string & expected_csp)111 testing::AssertionResult CheckCSP(const SanitizedCSPResult& actual,
112 const std::string& expected_csp) {
113 std::vector<std::string> expected_warnings;
114 return CheckCSP(actual, expected_csp, expected_warnings);
115 }
116
CheckCSP(const SanitizedCSPResult & actual,const std::string & expected_csp,const std::string & warning1)117 testing::AssertionResult CheckCSP(const SanitizedCSPResult& actual,
118 const std::string& expected_csp,
119 const std::string& warning1) {
120 std::vector<std::string> expected_warnings(1, warning1);
121 return CheckCSP(actual, expected_csp, expected_warnings);
122 }
123
CheckCSP(const SanitizedCSPResult & actual,const std::string & expected_csp,const std::string & warning1,const std::string & warning2)124 testing::AssertionResult CheckCSP(const SanitizedCSPResult& actual,
125 const std::string& expected_csp,
126 const std::string& warning1,
127 const std::string& warning2) {
128 std::vector<std::string> expected_warnings(1, warning1);
129 expected_warnings.push_back(warning2);
130 return CheckCSP(actual, expected_csp, expected_warnings);
131 }
132
CheckCSP(const SanitizedCSPResult & actual,const std::string & expected_csp,const std::string & warning1,const std::string & warning2,const std::string & warning3)133 testing::AssertionResult CheckCSP(const SanitizedCSPResult& actual,
134 const std::string& expected_csp,
135 const std::string& warning1,
136 const std::string& warning2,
137 const std::string& warning3) {
138 std::vector<std::string> expected_warnings(1, warning1);
139 expected_warnings.push_back(warning2);
140 expected_warnings.push_back(warning3);
141 return CheckCSP(actual, expected_csp, expected_warnings);
142 }
143
144 } // namespace
145
TEST(ExtensionCSPValidator,IsLegal)146 TEST(ExtensionCSPValidator, IsLegal) {
147 EXPECT_TRUE(ContentSecurityPolicyIsLegal("foo"));
148 EXPECT_TRUE(ContentSecurityPolicyIsLegal(
149 "default-src 'self'; script-src http://www.google.com"));
150 EXPECT_FALSE(ContentSecurityPolicyIsLegal(
151 "default-src 'self';\nscript-src http://www.google.com"));
152 EXPECT_FALSE(ContentSecurityPolicyIsLegal(
153 "default-src 'self';\rscript-src http://www.google.com"));
154 EXPECT_FALSE(ContentSecurityPolicyIsLegal(
155 "default-src 'self';,script-src http://www.google.com"));
156 }
157
TEST(ExtensionCSPValidator,IsSecure)158 TEST(ExtensionCSPValidator, IsSecure) {
159 auto missing_secure_src_warning = [](const std::string& directive) {
160 return MissingSecureSrcWarning(
161 extensions::manifest_keys::kContentSecurityPolicy, directive);
162 };
163
164 EXPECT_TRUE(CheckCSP(SanitizeCSP(std::string(), OPTIONS_ALLOW_UNSAFE_EVAL),
165 "script-src 'self'; object-src 'self';",
166 missing_secure_src_warning("script-src"),
167 missing_secure_src_warning("object-src")));
168 EXPECT_TRUE(CheckCSP(
169 SanitizeCSP("img-src https://google.com", OPTIONS_ALLOW_UNSAFE_EVAL),
170 "img-src https://google.com; script-src 'self'; object-src 'self';",
171 missing_secure_src_warning("script-src"),
172 missing_secure_src_warning("object-src")));
173 EXPECT_TRUE(CheckCSP(SanitizeCSP("script-src a b", OPTIONS_ALLOW_UNSAFE_EVAL),
174 "script-src; object-src 'self';",
175 InsecureValueWarning("script-src", "a"),
176 InsecureValueWarning("script-src", "b"),
177 missing_secure_src_warning("object-src")));
178
179 EXPECT_TRUE(CheckCSP(SanitizeCSP("default-src *", OPTIONS_ALLOW_UNSAFE_EVAL),
180 "default-src;",
181 InsecureValueWarning("default-src", "*")));
182 EXPECT_TRUE(CheckCSP(SanitizeCSP(
183 "default-src 'self';", OPTIONS_ALLOW_UNSAFE_EVAL)));
184 EXPECT_TRUE(CheckCSP(SanitizeCSP(
185 "default-src 'none';", OPTIONS_ALLOW_UNSAFE_EVAL)));
186 EXPECT_TRUE(
187 CheckCSP(SanitizeCSP("default-src 'self' ftp://google.com",
188 OPTIONS_ALLOW_UNSAFE_EVAL),
189 "default-src 'self';",
190 InsecureValueWarning("default-src", "ftp://google.com")));
191 EXPECT_TRUE(CheckCSP(SanitizeCSP(
192 "default-src 'self' https://google.com;", OPTIONS_ALLOW_UNSAFE_EVAL)));
193
194 EXPECT_TRUE(CheckCSP(SanitizeCSP("default-src *; default-src 'self'",
195 OPTIONS_ALLOW_UNSAFE_EVAL),
196 "default-src; default-src 'self';",
197 InsecureValueWarning("default-src", "*")));
198 EXPECT_TRUE(CheckCSP(SanitizeCSP(
199 "default-src 'self'; default-src *;", OPTIONS_ALLOW_UNSAFE_EVAL),
200 "default-src 'self'; default-src;"));
201 EXPECT_TRUE(CheckCSP(
202 SanitizeCSP(
203 "default-src 'self'; default-src *; script-src *; script-src 'self'",
204 OPTIONS_ALLOW_UNSAFE_EVAL),
205 "default-src 'self'; default-src; script-src; script-src 'self';",
206 InsecureValueWarning("script-src", "*")));
207 EXPECT_TRUE(CheckCSP(SanitizeCSP(
208 "default-src 'self'; default-src *; script-src 'self'; script-src *;",
209 OPTIONS_ALLOW_UNSAFE_EVAL),
210 "default-src 'self'; default-src; script-src 'self'; script-src;"));
211 EXPECT_TRUE(CheckCSP(SanitizeCSP("default-src *; script-src 'self'",
212 OPTIONS_ALLOW_UNSAFE_EVAL),
213 "default-src; script-src 'self';",
214 InsecureValueWarning("default-src", "*")));
215 EXPECT_TRUE(
216 CheckCSP(SanitizeCSP("default-src *; script-src 'self'; img-src 'self'",
217 OPTIONS_ALLOW_UNSAFE_EVAL),
218 "default-src; script-src 'self'; img-src 'self';",
219 InsecureValueWarning("default-src", "*")));
220 EXPECT_TRUE(CheckCSP(SanitizeCSP(
221 "default-src *; script-src 'self'; object-src 'self';",
222 OPTIONS_ALLOW_UNSAFE_EVAL),
223 "default-src; script-src 'self'; object-src 'self';"));
224 EXPECT_TRUE(CheckCSP(SanitizeCSP(
225 "script-src 'self'; object-src 'self';", OPTIONS_ALLOW_UNSAFE_EVAL)));
226 EXPECT_TRUE(CheckCSP(SanitizeCSP(
227 "default-src 'unsafe-eval';", OPTIONS_ALLOW_UNSAFE_EVAL)));
228
229 EXPECT_TRUE(CheckCSP(SanitizeCSP("default-src 'unsafe-eval'", OPTIONS_NONE),
230 "default-src;",
231 InsecureValueWarning("default-src", "'unsafe-eval'")));
232 EXPECT_TRUE(CheckCSP(
233 SanitizeCSP("default-src 'unsafe-inline'", OPTIONS_ALLOW_UNSAFE_EVAL),
234 "default-src;", InsecureValueWarning("default-src", "'unsafe-inline'")));
235 EXPECT_TRUE(CheckCSP(SanitizeCSP("default-src 'unsafe-inline' 'none'",
236 OPTIONS_ALLOW_UNSAFE_EVAL),
237 "default-src 'none';",
238 InsecureValueWarning("default-src", "'unsafe-inline'")));
239 EXPECT_TRUE(
240 CheckCSP(SanitizeCSP("default-src 'self' http://google.com",
241 OPTIONS_ALLOW_UNSAFE_EVAL),
242 "default-src 'self';",
243 InsecureValueWarning("default-src", "http://google.com")));
244 EXPECT_TRUE(CheckCSP(SanitizeCSP(
245 "default-src 'self' https://google.com;", OPTIONS_ALLOW_UNSAFE_EVAL)));
246 EXPECT_TRUE(CheckCSP(SanitizeCSP(
247 "default-src 'self' chrome://resources;", OPTIONS_ALLOW_UNSAFE_EVAL)));
248 EXPECT_TRUE(CheckCSP(SanitizeCSP(
249 "default-src 'self' chrome-extension://aabbcc;",
250 OPTIONS_ALLOW_UNSAFE_EVAL)));
251 EXPECT_TRUE(
252 CheckCSP(SanitizeCSP("default-src 'self';", OPTIONS_ALLOW_UNSAFE_EVAL)));
253 EXPECT_TRUE(CheckCSP(
254 SanitizeCSP("default-src 'self' https:", OPTIONS_ALLOW_UNSAFE_EVAL),
255 "default-src 'self';", InsecureValueWarning("default-src", "https:")));
256 EXPECT_TRUE(CheckCSP(
257 SanitizeCSP("default-src 'self' http:", OPTIONS_ALLOW_UNSAFE_EVAL),
258 "default-src 'self';", InsecureValueWarning("default-src", "http:")));
259 EXPECT_TRUE(CheckCSP(
260 SanitizeCSP("default-src 'self' google.com", OPTIONS_ALLOW_UNSAFE_EVAL),
261 "default-src 'self';",
262 InsecureValueWarning("default-src", "google.com")));
263
264 EXPECT_TRUE(CheckCSP(
265 SanitizeCSP("default-src 'self' *", OPTIONS_ALLOW_UNSAFE_EVAL),
266 "default-src 'self';", InsecureValueWarning("default-src", "*")));
267 EXPECT_TRUE(CheckCSP(
268 SanitizeCSP("default-src 'self' *:*", OPTIONS_ALLOW_UNSAFE_EVAL),
269 "default-src 'self';", InsecureValueWarning("default-src", "*:*")));
270 EXPECT_TRUE(CheckCSP(
271 SanitizeCSP("default-src 'self' *:*/", OPTIONS_ALLOW_UNSAFE_EVAL),
272 "default-src 'self';", InsecureValueWarning("default-src", "*:*/")));
273 EXPECT_TRUE(CheckCSP(
274 SanitizeCSP("default-src 'self' *:*/path", OPTIONS_ALLOW_UNSAFE_EVAL),
275 "default-src 'self';", InsecureValueWarning("default-src", "*:*/path")));
276 EXPECT_TRUE(CheckCSP(
277 SanitizeCSP("default-src 'self' https://", OPTIONS_ALLOW_UNSAFE_EVAL),
278 "default-src 'self';", InsecureValueWarning("default-src", "https://")));
279 EXPECT_TRUE(CheckCSP(
280 SanitizeCSP("default-src 'self' https://*:*", OPTIONS_ALLOW_UNSAFE_EVAL),
281 "default-src 'self';",
282 InsecureValueWarning("default-src", "https://*:*")));
283 EXPECT_TRUE(CheckCSP(
284 SanitizeCSP("default-src 'self' https://*:*/", OPTIONS_ALLOW_UNSAFE_EVAL),
285 "default-src 'self';",
286 InsecureValueWarning("default-src", "https://*:*/")));
287 EXPECT_TRUE(
288 CheckCSP(SanitizeCSP("default-src 'self' https://*:*/path",
289 OPTIONS_ALLOW_UNSAFE_EVAL),
290 "default-src 'self';",
291 InsecureValueWarning("default-src", "https://*:*/path")));
292 EXPECT_TRUE(CheckCSP(SanitizeCSP("default-src 'self' https://*.com",
293 OPTIONS_ALLOW_UNSAFE_EVAL),
294 "default-src 'self';",
295 InsecureValueWarning("default-src", "https://*.com")));
296 EXPECT_TRUE(
297 CheckCSP(SanitizeCSP("default-src 'self' https://*.*.google.com/",
298 OPTIONS_ALLOW_UNSAFE_EVAL),
299 "default-src 'self';",
300 InsecureValueWarning("default-src", "https://*.*.google.com/")));
301 EXPECT_TRUE(CheckCSP(
302 SanitizeCSP("default-src 'self' https://*.*.google.com:*/",
303 OPTIONS_ALLOW_UNSAFE_EVAL),
304 "default-src 'self';",
305 InsecureValueWarning("default-src", "https://*.*.google.com:*/")));
306 EXPECT_TRUE(CheckCSP(
307 SanitizeCSP("default-src 'self' https://www.*.google.com/",
308 OPTIONS_ALLOW_UNSAFE_EVAL),
309 "default-src 'self';",
310 InsecureValueWarning("default-src", "https://www.*.google.com/")));
311 EXPECT_TRUE(CheckCSP(
312 SanitizeCSP("default-src 'self' https://www.*.google.com:*/",
313 OPTIONS_ALLOW_UNSAFE_EVAL),
314 "default-src 'self';",
315 InsecureValueWarning("default-src", "https://www.*.google.com:*/")));
316 EXPECT_TRUE(CheckCSP(
317 SanitizeCSP("default-src 'self' chrome://*", OPTIONS_ALLOW_UNSAFE_EVAL),
318 "default-src 'self';",
319 InsecureValueWarning("default-src", "chrome://*")));
320 EXPECT_TRUE(
321 CheckCSP(SanitizeCSP("default-src 'self' chrome-extension://*",
322 OPTIONS_ALLOW_UNSAFE_EVAL),
323 "default-src 'self';",
324 InsecureValueWarning("default-src", "chrome-extension://*")));
325 EXPECT_TRUE(
326 CheckCSP(SanitizeCSP("default-src 'self' chrome-extension://",
327 OPTIONS_ALLOW_UNSAFE_EVAL),
328 "default-src 'self';",
329 InsecureValueWarning("default-src", "chrome-extension://")));
330
331 EXPECT_TRUE(CheckCSP(SanitizeCSP(
332 "default-src 'self' https://*.google.com;", OPTIONS_ALLOW_UNSAFE_EVAL)));
333 EXPECT_TRUE(CheckCSP(SanitizeCSP(
334 "default-src 'self' https://*.google.com:1;",
335 OPTIONS_ALLOW_UNSAFE_EVAL)));
336 EXPECT_TRUE(CheckCSP(SanitizeCSP(
337 "default-src 'self' https://*.google.com:*;",
338 OPTIONS_ALLOW_UNSAFE_EVAL)));
339 EXPECT_TRUE(CheckCSP(SanitizeCSP(
340 "default-src 'self' https://*.google.com:1/;",
341 OPTIONS_ALLOW_UNSAFE_EVAL)));
342 EXPECT_TRUE(CheckCSP(SanitizeCSP(
343 "default-src 'self' https://*.google.com:*/;",
344 OPTIONS_ALLOW_UNSAFE_EVAL)));
345
346 EXPECT_TRUE(CheckCSP(SanitizeCSP(
347 "default-src 'self' http://127.0.0.1;", OPTIONS_ALLOW_UNSAFE_EVAL)));
348 EXPECT_TRUE(CheckCSP(SanitizeCSP(
349 "default-src 'self' http://localhost;", OPTIONS_ALLOW_UNSAFE_EVAL)));
350 EXPECT_TRUE(CheckCSP(SanitizeCSP("default-src 'self' http://lOcAlHoSt;",
351 OPTIONS_ALLOW_UNSAFE_EVAL),
352 "default-src 'self' http://lOcAlHoSt;"));
353 EXPECT_TRUE(CheckCSP(SanitizeCSP(
354 "default-src 'self' http://127.0.0.1:9999;", OPTIONS_ALLOW_UNSAFE_EVAL)));
355 EXPECT_TRUE(CheckCSP(SanitizeCSP(
356 "default-src 'self' http://localhost:8888;", OPTIONS_ALLOW_UNSAFE_EVAL)));
357 EXPECT_TRUE(CheckCSP(
358 SanitizeCSP("default-src 'self' http://127.0.0.1.example.com",
359 OPTIONS_ALLOW_UNSAFE_EVAL),
360 "default-src 'self';",
361 InsecureValueWarning("default-src", "http://127.0.0.1.example.com")));
362 EXPECT_TRUE(CheckCSP(
363 SanitizeCSP("default-src 'self' http://localhost.example.com",
364 OPTIONS_ALLOW_UNSAFE_EVAL),
365 "default-src 'self';",
366 InsecureValueWarning("default-src", "http://localhost.example.com")));
367
368 EXPECT_TRUE(CheckCSP(SanitizeCSP(
369 "default-src 'self' blob:;", OPTIONS_ALLOW_UNSAFE_EVAL)));
370 EXPECT_TRUE(CheckCSP(
371 SanitizeCSP("default-src 'self' blob:http://example.com/XXX",
372 OPTIONS_ALLOW_UNSAFE_EVAL),
373 "default-src 'self';",
374 InsecureValueWarning("default-src", "blob:http://example.com/XXX")));
375 EXPECT_TRUE(CheckCSP(SanitizeCSP(
376 "default-src 'self' filesystem:;", OPTIONS_ALLOW_UNSAFE_EVAL)));
377 EXPECT_TRUE(CheckCSP(
378 SanitizeCSP("default-src 'self' filesystem:http://example.com/XX",
379 OPTIONS_ALLOW_UNSAFE_EVAL),
380 "default-src 'self';",
381 InsecureValueWarning("default-src", "filesystem:http://example.com/XX")));
382
383 EXPECT_TRUE(CheckCSP(SanitizeCSP(
384 "default-src 'self' https://*.googleapis.com;",
385 OPTIONS_ALLOW_UNSAFE_EVAL)));
386 EXPECT_TRUE(CheckCSP(SanitizeCSP(
387 "default-src 'self' https://x.googleapis.com;",
388 OPTIONS_ALLOW_UNSAFE_EVAL)));
389
390 EXPECT_TRUE(
391 CheckCSP(SanitizeCSP("script-src 'self'; object-src *", OPTIONS_NONE),
392 "script-src 'self'; object-src;",
393 InsecureValueWarning("object-src", "*")));
394 EXPECT_TRUE(CheckCSP(SanitizeCSP("script-src 'self'; object-src *",
395 OPTIONS_ALLOW_INSECURE_OBJECT_SRC),
396 "script-src 'self'; object-src;",
397 InsecureValueWarning("object-src", "*")));
398 EXPECT_TRUE(CheckCSP(SanitizeCSP(
399 "script-src 'self'; object-src *; plugin-types application/pdf;",
400 OPTIONS_ALLOW_INSECURE_OBJECT_SRC)));
401 EXPECT_TRUE(CheckCSP(SanitizeCSP("script-src 'self'; object-src *; "
402 "plugin-types application/x-shockwave-flash",
403 OPTIONS_ALLOW_INSECURE_OBJECT_SRC),
404 "script-src 'self'; object-src; "
405 "plugin-types application/x-shockwave-flash;",
406 InsecureValueWarning("object-src", "*")));
407 EXPECT_TRUE(CheckCSP(
408 SanitizeCSP("script-src 'self'; object-src *; "
409 "plugin-types application/x-shockwave-flash application/pdf;",
410 OPTIONS_ALLOW_INSECURE_OBJECT_SRC),
411 "script-src 'self'; object-src; "
412 "plugin-types application/x-shockwave-flash application/pdf;",
413 InsecureValueWarning("object-src", "*")));
414 EXPECT_TRUE(CheckCSP(SanitizeCSP(
415 "script-src 'self'; object-src http://www.example.com; "
416 "plugin-types application/pdf;",
417 OPTIONS_ALLOW_INSECURE_OBJECT_SRC)));
418 EXPECT_TRUE(CheckCSP(SanitizeCSP(
419 "object-src http://www.example.com blob:; script-src 'self'; "
420 "plugin-types application/pdf;",
421 OPTIONS_ALLOW_INSECURE_OBJECT_SRC)));
422 EXPECT_TRUE(CheckCSP(SanitizeCSP(
423 "script-src 'self'; object-src http://*.example.com; "
424 "plugin-types application/pdf;",
425 OPTIONS_ALLOW_INSECURE_OBJECT_SRC)));
426 EXPECT_TRUE(CheckCSP(
427 SanitizeCSP("script-src *; object-src *; plugin-types application/pdf;",
428 OPTIONS_ALLOW_INSECURE_OBJECT_SRC),
429 "script-src; object-src *; plugin-types application/pdf;",
430 InsecureValueWarning("script-src", "*")));
431
432 EXPECT_TRUE(CheckCSP(SanitizeCSP(
433 "default-src; script-src"
434 " 'sha256-hndjYvzUzy2Ykuad81Cwsl1FOXX/qYs/aDVyUyNZwBw='"
435 " 'sha384-bSVm1i3sjPBRM4TwZtYTDjk9JxZMExYHWbFmP1SxDhJH4ue0Wu9OPOkY5hcqRcS"
436 "t'"
437 " 'sha512-440MmBLtj9Kp5Bqloogn9BqGDylY8vFsv5/zXL1zH2fJVssCoskRig4gyM+9Kqw"
438 "vCSapSz5CVoUGHQcxv43UQg==';",
439 OPTIONS_NONE)));
440
441 // Reject non-standard algorithms, even if they are still supported by Blink.
442 EXPECT_TRUE(CheckCSP(
443 SanitizeCSP(
444 "default-src; script-src 'sha1-eYyYGmKWdhpUewohaXk9o8IaLSw=';",
445 OPTIONS_NONE),
446 "default-src; script-src;",
447 InsecureValueWarning("script-src",
448 "'sha1-eYyYGmKWdhpUewohaXk9o8IaLSw='")));
449
450 EXPECT_TRUE(CheckCSP(
451 SanitizeCSP("default-src; script-src "
452 "'sha256-hndjYvzUzy2Ykuad81Cwsl1FOXX/qYs/aDVyUyNZ"
453 "wBw= sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng=';",
454 OPTIONS_NONE),
455 "default-src; script-src;",
456 InsecureValueWarning(
457 "script-src", "'sha256-hndjYvzUzy2Ykuad81Cwsl1FOXX/qYs/aDVyUyNZwBw="),
458 InsecureValueWarning(
459 "script-src",
460 "sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng='")));
461 }
462
TEST(ExtensionCSPValidator,IsSandboxed)463 TEST(ExtensionCSPValidator, IsSandboxed) {
464 EXPECT_FALSE(ContentSecurityPolicyIsSandboxed(std::string(),
465 Manifest::TYPE_EXTENSION));
466 EXPECT_FALSE(ContentSecurityPolicyIsSandboxed("img-src https://google.com",
467 Manifest::TYPE_EXTENSION));
468
469 // Sandbox directive is required.
470 EXPECT_TRUE(ContentSecurityPolicyIsSandboxed(
471 "sandbox", Manifest::TYPE_EXTENSION));
472
473 // Additional sandbox tokens are OK.
474 EXPECT_TRUE(ContentSecurityPolicyIsSandboxed(
475 "sandbox allow-scripts", Manifest::TYPE_EXTENSION));
476 // Except for allow-same-origin.
477 EXPECT_FALSE(ContentSecurityPolicyIsSandboxed(
478 "sandbox allow-same-origin", Manifest::TYPE_EXTENSION));
479
480 // Additional directives are OK.
481 EXPECT_TRUE(ContentSecurityPolicyIsSandboxed(
482 "sandbox; img-src https://google.com", Manifest::TYPE_EXTENSION));
483
484 // Extensions allow navigation, platform apps don't.
485 EXPECT_TRUE(ContentSecurityPolicyIsSandboxed(
486 "sandbox allow-top-navigation", Manifest::TYPE_EXTENSION));
487 EXPECT_FALSE(ContentSecurityPolicyIsSandboxed(
488 "sandbox allow-top-navigation", Manifest::TYPE_PLATFORM_APP));
489
490 // Popups are OK.
491 EXPECT_TRUE(ContentSecurityPolicyIsSandboxed(
492 "sandbox allow-popups", Manifest::TYPE_EXTENSION));
493 EXPECT_TRUE(ContentSecurityPolicyIsSandboxed(
494 "sandbox allow-popups", Manifest::TYPE_PLATFORM_APP));
495 }
496
TEST(ExtensionCSPValidator,EffectiveSandboxedPageCSP)497 TEST(ExtensionCSPValidator, EffectiveSandboxedPageCSP) {
498 auto insecure_value_warning = [](const std::string& directive,
499 const std::string& value) {
500 return InsecureValueWarning(directive, value,
501 extensions::manifest_keys::kSandboxedPagesCSP);
502 };
503
504 EXPECT_TRUE(CheckCSP(
505 SanitizeSandboxPageCSP(""),
506 "child-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval';"));
507 EXPECT_TRUE(CheckCSP(
508 SanitizeSandboxPageCSP("child-src http://www.google.com"),
509 "child-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval';",
510 insecure_value_warning("child-src", "http://www.google.com")));
511 EXPECT_TRUE(CheckCSP(
512 SanitizeSandboxPageCSP("child-src *"),
513 "child-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval';",
514 insecure_value_warning("child-src", "*")));
515 EXPECT_TRUE(CheckCSP(
516 SanitizeSandboxPageCSP("child-src 'none'"),
517 "child-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval';"));
518
519 // Directive values of 'none' and 'self' are preserved.
520 EXPECT_TRUE(
521 CheckCSP(SanitizeSandboxPageCSP("script-src 'none'; frame-src 'self';"),
522 "frame-src 'self'; script-src 'none';"));
523 EXPECT_TRUE(CheckCSP(
524 SanitizeSandboxPageCSP(
525 "script-src 'none'; frame-src 'self' http://www.google.com;"),
526 "frame-src 'self'; script-src 'none';",
527 insecure_value_warning("frame-src", "http://www.google.com")));
528
529 // script-src will add 'unsafe-inline' and 'unsafe-eval' only if script-src is
530 // not specified.
531 EXPECT_TRUE(CheckCSP(SanitizeSandboxPageCSP("script-src 'self'"),
532 "script-src 'self'; child-src 'self'"));
533 EXPECT_TRUE(
534 CheckCSP(SanitizeSandboxPageCSP(
535 "script-src 'self' 'unsafe-inline'; child-src 'self';"),
536 "child-src 'self'; script-src 'self' 'unsafe-inline';"));
537 EXPECT_TRUE(
538 CheckCSP(SanitizeSandboxPageCSP(
539 "script-src 'self' 'unsafe-eval'; child-src 'self';"),
540 "child-src 'self'; script-src 'self' 'unsafe-eval';"));
541
542 // child-src and frame-src are handled correctly.
543 EXPECT_TRUE(CheckCSP(
544 SanitizeSandboxPageCSP(
545 "script-src 'none'; frame-src 'self' http://www.google.com;"),
546 "frame-src 'self'; script-src 'none';",
547 insecure_value_warning("frame-src", "http://www.google.com")));
548 EXPECT_TRUE(CheckCSP(
549 SanitizeSandboxPageCSP(
550 "script-src 'none'; child-src 'self' http://www.google.com;"),
551 "child-src 'self'; script-src 'none';",
552 insecure_value_warning("child-src", "http://www.google.com")));
553
554 // Multiple insecure values.
555 EXPECT_TRUE(CheckCSP(
556 SanitizeSandboxPageCSP(
557 "script-src 'none'; child-src http://bar.com 'self' http://foo.com;"),
558 "child-src 'self'; script-src 'none';",
559 insecure_value_warning("child-src", "http://bar.com"),
560 insecure_value_warning("child-src", "http://foo.com")));
561 }
562
563 namespace extensions {
564 namespace csp_validator {
565
PrintTo(const CSPParser::Directive & directive,::std::ostream * os)566 void PrintTo(const CSPParser::Directive& directive, ::std::ostream* os) {
567 *os << base::StringPrintf(
568 "[[%s] [%s] [%s]]", directive.directive_string.as_string().c_str(),
569 directive.directive_name.c_str(),
570 base::JoinString(directive.directive_values, ",").c_str());
571 }
572
573 } // namespace csp_validator
574 } // namespace extensions
575
TEST(ExtensionCSPValidator,ParseCSP)576 TEST(ExtensionCSPValidator, ParseCSP) {
577 using CSPParser = extensions::csp_validator::CSPParser;
578 using DirectiveList = CSPParser::DirectiveList;
579
580 struct TestCase {
581 TestCase(const char* policy, DirectiveList expected_directives)
582 : policy(policy), expected_directives(std::move(expected_directives)) {}
583 const char* policy;
584 DirectiveList expected_directives;
585 };
586
587 std::vector<TestCase> cases;
588
589 cases.emplace_back(" \n \r \t ", DirectiveList());
590 cases.emplace_back(" ; \n ;\r \t ;;", DirectiveList());
591
592 const char* policy = R"( deFAULt-src 'self' ;
593 img-src * ; media-src media1.com MEDIA2.com;
594 img-src 'self';
595 )";
596 DirectiveList expected_directives;
597 expected_directives.emplace_back("deFAULt-src 'self'", "default-src",
598 std::vector<base::StringPiece>({"'self'"}));
599 expected_directives.emplace_back("img-src *", "img-src",
600 std::vector<base::StringPiece>({"*"}));
601 expected_directives.emplace_back(
602 "media-src media1.com MEDIA2.com", "media-src",
603 std::vector<base::StringPiece>({"media1.com", "MEDIA2.com"}));
604 expected_directives.emplace_back("img-src 'self'", "img-src",
605 std::vector<base::StringPiece>({"'self'"}));
606 cases.emplace_back(policy, std::move(expected_directives));
607
608 for (const auto& test_case : cases) {
609 SCOPED_TRACE(test_case.policy);
610
611 CSPParser parser(test_case.policy);
612
613 // Cheat and compare serialized versions of the directives.
614 EXPECT_EQ(::testing::PrintToString(parser.directives()),
615 ::testing::PrintToString(test_case.expected_directives));
616 }
617 }
618
TEST(ExtensionCSPValidator,DoesCSPDisallowRemoteCode)619 TEST(ExtensionCSPValidator, DoesCSPDisallowRemoteCode) {
620 const char* kManifestKey = "dummy_key";
621 auto insecure_value_error = [kManifestKey](const std::string& directive,
622 const std::string& value) {
623 return ErrorUtils::FormatErrorMessage(
624 extensions::manifest_errors::kInvalidCSPInsecureValueError,
625 kManifestKey, value, directive);
626 };
627
628 auto missing_secure_src_error = [kManifestKey](const std::string& directive) {
629 return MissingSecureSrcWarning(kManifestKey, directive);
630 };
631
632 struct {
633 const char* policy;
634 std::string expected_error; // Empty if no error expected.
635 } test_cases[] = {
636 {"frame-src google.com; default-src yahoo.com; script-src 'self'; "
637 "worker-src; object-src http://localhost:80 'none'",
638 ""},
639 {"worker-src http://localhost google.com; script-src; object-src 'self'",
640 insecure_value_error("worker-src", "google.com")},
641 {"script-src; worker-src 'self';",
642 missing_secure_src_error("object-src")},
643 // Duplicate directives are ignored.
644 {"script-src; worker-src 'self'; default-src 'self'; script-src "
645 "google.com",
646 ""},
647 // "object-src" falls back to "default-src".
648 {"script-src; worker-src 'self'; default-src google.com",
649 insecure_value_error("object-src", "google.com")},
650 // "worker-src" falls back to "script-src".
651 {"script-src 'self'; object-src 'none'; default-src google.com", ""},
652 {"script-src 'unsafe-eval'; worker-src; default-src;",
653 insecure_value_error("script-src", "'unsafe-eval'")}};
654
655 for (const auto& test_case : test_cases) {
656 SCOPED_TRACE(test_case.policy);
657 base::string16 error;
658 bool result = extensions::csp_validator::DoesCSPDisallowRemoteCode(
659 test_case.policy, kManifestKey, &error);
660 EXPECT_EQ(test_case.expected_error.empty(), result);
661 EXPECT_EQ(base::ASCIIToUTF16(test_case.expected_error), error);
662 }
663 }
664