Skip to content

Commit a318c5d

Browse files
author
Andrew R. Whalley
committed
[M68 Merge] Fixed CSP directive value parsing accepted character range
[email protected] (cherry picked from commit 5b8466d) Bug: 845961 Change-Id: Ifc9609058cd7cbd268785db46534e3ed09da6ce3 Reviewed-on: https://chromium-review.googlesource.com/1071510 Commit-Queue: Andy Paicu <[email protected]> Reviewed-by: Mike West <[email protected]> Cr-Original-Commit-Position: refs/heads/master@{#561834} Reviewed-on: https://chromium-review.googlesource.com/1080929 Reviewed-by: Andrew Whalley <[email protected]> Cr-Commit-Position: refs/branch-heads/3440@{#62} Cr-Branched-From: 010ddcf-refs/heads/master@{#561733}
1 parent 33cf620 commit a318c5d

File tree

5 files changed

+186
-1
lines changed

5 files changed

+186
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Embedded Enforcement: Sec-Required-CSP header.</title>
5+
<script src="/resources/testharness.js"></script>
6+
<script src="/resources/testharnessreport.js"></script>
7+
<script src="support/testharness-helper.sub.js"></script>
8+
</head>
9+
<body>
10+
<script>
11+
var tests = [
12+
// CRLF characters
13+
{ "name": "\\r\\n character after directive name",
14+
"csp": "script-src\r\n'unsafe-inline'",
15+
"expected": null },
16+
{ "name": "\\r\\n character in directive value",
17+
"csp": "script-src 'unsafe-inline'\r\n'unsafe-eval'",
18+
"expected": null },
19+
{ "name": "\\n character after directive name",
20+
"csp": "script-src\n'unsafe-inline'",
21+
"expected": null },
22+
{ "name": "\\n character in directive value",
23+
"csp": "script-src 'unsafe-inline'\n'unsafe-eval'",
24+
"expected": null },
25+
{ "name": "\\r character after directive name",
26+
"csp": "script-src\r'unsafe-inline'",
27+
"expected": null },
28+
{ "name": "\\r character in directive value",
29+
"csp": "script-src 'unsafe-inline'\r'unsafe-eval'",
30+
"expected": null },
31+
32+
// HTML encoded CRLF characters
33+
{ "name": "%0D%0A character after directive name",
34+
"csp": "script-src%0D%0A'unsafe-inline'",
35+
"expected": null },
36+
{ "name": "%0D%0A character in directive value",
37+
"csp": "script-src 'unsafe-inline'%0D%0A'unsafe-eval'",
38+
"expected": null },
39+
{ "name": "%0A character after directive name",
40+
"csp": "script-src%0A'unsafe-inline'",
41+
"expected": null },
42+
{ "name": "%0A character in directive value",
43+
"csp": "script-src 'unsafe-inline'%0A'unsafe-eval'",
44+
"expected": null },
45+
{ "name": "%0D character after directive name",
46+
"csp": "script-src%0D'unsafe-inline'",
47+
"expected": null },
48+
{ "name": "%0D character in directive value",
49+
"csp": "script-src 'unsafe-inline'%0D'unsafe-eval'",
50+
"expected": null },
51+
52+
// Attempt HTTP Header injection
53+
{ "name": "Attempt injecting after directive name using \\r\\n",
54+
"csp": "script-src\r\nTest-Header-Injection: dummy",
55+
"expected": null },
56+
{ "name": "Attempt injecting after directive name using \\r",
57+
"csp": "script-src\rTest-Header-Injection: dummy",
58+
"expected": null },
59+
{ "name": "Attempt injecting after directive name using \\n",
60+
"csp": "script-src\nTest-Header-Injection: dummy",
61+
"expected": null },
62+
63+
{ "name": "Attempt injecting after directive value using \\r\\n",
64+
"csp": "script-src example.com\r\nTest-Header-Injection: dummy",
65+
"expected": null },
66+
{ "name": "Attempt injecting after directive value using \\r",
67+
"csp": "script-src example.com\rTest-Header-Injection: dummy",
68+
"expected": null },
69+
{ "name": "Attempt injecting after directive value using \\n",
70+
"csp": "script-src example.com\nTest-Header-Injection: dummy",
71+
"expected": null },
72+
73+
{ "name": "Attempt injecting after semicolon using \\r\\n",
74+
"csp": "script-src example.com;\r\nTest-Header-Injection: dummy",
75+
"expected": null },
76+
{ "name": "Attempt injecting after semicolon using \\r",
77+
"csp": "script-src example.com;\rTest-Header-Injection: dummy",
78+
"expected": null },
79+
{ "name": "Attempt injecting after semicolon using \\n",
80+
"csp": "script-src example.com;\nTest-Header-Injection: dummy",
81+
"expected": null },
82+
83+
{ "name": "Attempt injecting after space between name and value using \\r\\n",
84+
"csp": "script-src \r\nTest-Header-Injection: dummy",
85+
"expected": null },
86+
{ "name": "Attempt injecting after space between name and value using \\r",
87+
"csp": "script-src \rTest-Header-Injection: dummy",
88+
"expected": null },
89+
{ "name": "Attempt injecting after space between name and value using \\n",
90+
"csp": "script-src \nTest-Header-Injection: dummy",
91+
"expected": null },
92+
93+
// Attempt HTTP Header injection using URL encoded characters
94+
{ "name": "Attempt injecting after directive name using %0D%0A",
95+
"csp": "script-src%0D%0ATest-Header-Injection: dummy",
96+
"expected": null },
97+
{ "name": "Attempt injecting after directive name using %0D",
98+
"csp": "script-src%0DTest-Header-Injection: dummy",
99+
"expected": null },
100+
{ "name": "Attempt injecting after directive name using %0A",
101+
"csp": "script-src%0ATest-Header-Injection: dummy",
102+
"expected": null },
103+
104+
{ "name": "Attempt injecting after directive value using %0D%0A",
105+
"csp": "script-src example.com%0D%0ATest-Header-Injection: dummy",
106+
"expected": null },
107+
{ "name": "Attempt injecting after directive value using %0D",
108+
"csp": "script-src example.com%0DTest-Header-Injection: dummy",
109+
"expected": null },
110+
{ "name": "Attempt injecting after directive value using %0A",
111+
"csp": "script-src example.com%0ATest-Header-Injection: dummy",
112+
"expected": null },
113+
114+
{ "name": "Attempt injecting after semicolon using %0D%0A",
115+
"csp": "script-src example.com;%0D%0ATest-Header-Injection: dummy",
116+
"expected": null },
117+
{ "name": "Attempt injecting after semicolon using %0D",
118+
"csp": "script-src example.com;%0DTest-Header-Injection: dummy",
119+
"expected": null },
120+
{ "name": "Attempt injecting after semicolon using %0A",
121+
"csp": "script-src example.com;%0ATest-Header-Injection: dummy",
122+
"expected": null },
123+
124+
{ "name": "Attempt injecting after space between name and value using %0D%0A",
125+
"csp": "script-src %0D%0ATest-Header-Injection: dummy",
126+
"expected": null },
127+
{ "name": "Attempt injecting after space between name and value using %0D",
128+
"csp": "script-src %0DTest-Header-Injection: dummy",
129+
"expected": null },
130+
{ "name": "Attempt injecting after space between name and value using %0A",
131+
"csp": "script-src %0ATest-Header-Injection: dummy",
132+
"expected": null },
133+
134+
];
135+
136+
tests.forEach(test => {
137+
async_test(t => {
138+
var url = generateURLString(Host.SAME_ORIGIN, PolicyHeader.REQUIRED_CSP);
139+
assert_required_csp(t, url, test.csp, [test.expected]);
140+
}, "Test CRLF: " + test.name);
141+
});
142+
</script>
143+
</body>
144+
</html>

third_party/WebKit/LayoutTests/external/wpt/content-security-policy/embedded-enforcement/support/echo-required-csp.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import json
22
def main(request, response):
3-
header = request.headers.get("Sec-Required-CSP");
43
message = {}
4+
5+
header = request.headers.get("Test-Header-Injection");
6+
message['test_header_injection'] = header if header else None
7+
8+
header = request.headers.get("Sec-Required-CSP");
59
message['required_csp'] = header if header else None
10+
611
second_level_iframe_code = ""
712
if "include_second_level_iframe" in request.GET:
813
if "second_level_iframe_csp" in request.GET and request.GET["second_level_iframe_csp"] <> "":

third_party/WebKit/LayoutTests/external/wpt/content-security-policy/embedded-enforcement/support/testharness-helper.sub.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ function assert_required_csp(t, url, csp, expected) {
9191
assert_unreached('Child iframes have unexpected csp:"' + e.data['required_csp'] + '"');
9292

9393
expected.splice(expected.indexOf(e.data['required_csp']), 1);
94+
95+
if (e.data['test_header_injection'] != null)
96+
assert_unreached('HTTP header injection was successful');
97+
9498
if (expected.length == 0)
9599
t.done();
96100
}));

third_party/blink/renderer/core/frame/csp/content_security_policy.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,6 +1843,10 @@ bool ContentSecurityPolicy::ShouldBypassContentSecurityPolicy(
18431843
// static
18441844
bool ContentSecurityPolicy::IsValidCSPAttr(const String& attr,
18451845
const String& context_required_csp) {
1846+
// we don't allow any newline characters in the CSP attributes
1847+
if (attr.Contains('\n') || attr.Contains('\r'))
1848+
return false;
1849+
18461850
ContentSecurityPolicy* attr_policy = ContentSecurityPolicy::Create();
18471851
attr_policy->AddPolicyFromHeaderValue(attr,
18481852
kContentSecurityPolicyHeaderTypeEnforce,

third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,34 @@ TEST_F(ContentSecurityPolicyTest, IsValidCSPAttrTest) {
13481348
"report-to relative-path/reporting;"
13491349
"base-uri http://example.com 'self'",
13501350
""));
1351+
1352+
// CRLF should not be allowed
1353+
EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1354+
"base-uri\nhttp://example.com", ""));
1355+
EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1356+
"base-uri http://example.com\nhttp://example2.com", ""));
1357+
EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1358+
"base\n-uri http://example.com", ""));
1359+
EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1360+
"\nbase-uri http://example.com", ""));
1361+
1362+
EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1363+
"base-uri\r\nhttp://example.com", ""));
1364+
EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1365+
"base-uri http://example.com\r\nhttp://example2.com", ""));
1366+
EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1367+
"base\r\n-uri http://example.com", ""));
1368+
EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1369+
"\r\nbase-uri http://example.com", ""));
1370+
1371+
EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1372+
"base-uri\rhttp://example.com", ""));
1373+
EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1374+
"base-uri http://example.com\rhttp://example2.com", ""));
1375+
EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1376+
"base\r-uri http://example.com", ""));
1377+
EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1378+
"\rbase-uri http://example.com", ""));
13511379
}
13521380

13531381
} // namespace blink

0 commit comments

Comments
 (0)