Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: content/common/content_security_policy/csp_source.cc

Issue 2792013002: Stop CSP from matching independent scheme/port upgrades (content layer) (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <sstream> 5 #include <sstream>
6 6
7 #include "base/strings/string_util.h" 7 #include "base/strings/string_util.h"
8 #include "base/strings/utf_string_conversions.h" 8 #include "base/strings/utf_string_conversions.h"
9 #include "content/common/content_security_policy/csp_context.h" 9 #include "content/common/content_security_policy/csp_context.h"
10 #include "url/url_canon.h" 10 #include "url/url_canon.h"
11 #include "url/url_util.h" 11 #include "url/url_util.h"
12 12
13 namespace content { 13 namespace content {
14 14
15 namespace { 15 namespace {
16 16
17 bool DecodePath(const base::StringPiece& path, std::string* output) { 17 bool DecodePath(const base::StringPiece& path, std::string* output) {
18 url::RawCanonOutputT<base::char16> unescaped; 18 url::RawCanonOutputT<base::char16> unescaped;
19 url::DecodeURLEscapeSequences(path.data(), path.size(), &unescaped); 19 url::DecodeURLEscapeSequences(path.data(), path.size(), &unescaped);
20 return base::UTF16ToUTF8(unescaped.data(), unescaped.length(), output); 20 return base::UTF16ToUTF8(unescaped.data(), unescaped.length(), output);
21 } 21 }
22 22
23 int DefaultPortForScheme(const std::string& scheme) { 23 int DefaultPortForScheme(const std::string& scheme) {
24 return url::DefaultPortForScheme(scheme.data(), scheme.size()); 24 return url::DefaultPortForScheme(scheme.data(), scheme.size());
25 } 25 }
26 26
27 bool SourceAllowScheme(const CSPSource& source, 27 CSPSource::SchemeMatchingResult SourceAllowScheme(const CSPSource& source,
28 const GURL& url, 28 const GURL& url,
29 CSPContext* context) { 29 CSPContext* context) {
30 if (source.scheme.empty()) 30 const std::string& source_scheme =
31 return context->ProtocolMatchesSelf(url); 31 source.scheme.empty() ? context->GetSelfScheme() : source.scheme;
32 if (source.scheme == url::kHttpScheme) 32
33 return url.SchemeIsHTTPOrHTTPS(); 33 if (source_scheme.empty()) {
34 if (source.scheme == url::kWsScheme) 34 if (context->ProtocolIsSelf(url))
35 return url.SchemeIsWSOrWSS(); 35 return CSPSource::SchemeMatchingResult::MatchingExact;
36 return url.SchemeIs(source.scheme); 36 return CSPSource::SchemeMatchingResult::NotMatching;
37 }
38
39 if (url.SchemeIs(source_scheme))
40 return CSPSource::SchemeMatchingResult::MatchingExact;
41
42 if ((source_scheme == url::kHttpScheme &&
43 url.SchemeIs(url::kHttpsScheme)) ||
arthursonzogni 2017/04/07 09:20:27 Nit: git cl format: it should fit on one line.
andypaicu 2017/04/07 11:34:24 Done. I hated the fact that the middle one does no
44 (source_scheme == url::kHttpScheme &&
45 url.SchemeIs(url::kHttpsSuboriginScheme)) ||
46 (source_scheme == url::kWsScheme &&
47 url.SchemeIs(url::kWssScheme))) {
arthursonzogni 2017/04/07 09:20:27 Nit: git cl format: it should fit on one line.
andypaicu 2017/04/07 11:34:24 Done. I hated the fact that the middle one does no
48 return CSPSource::SchemeMatchingResult::MatchingUpgrade;
49 }
50
51 if ((source_scheme == url::kHttpScheme &&
52 url.SchemeIs(url::kHttpSuboriginScheme)) ||
53 (source_scheme == url::kHttpsScheme &&
54 url.SchemeIs(url::kHttpsSuboriginScheme))) {
55 return CSPSource::SchemeMatchingResult::MatchingExact;
56 }
57
58 return CSPSource::SchemeMatchingResult::NotMatching;
37 } 59 }
38 60
39 bool SourceAllowHost(const CSPSource& source, const GURL& url) { 61 bool SourceAllowHost(const CSPSource& source, const GURL& url) {
40 if (source.is_host_wildcard) { 62 if (source.is_host_wildcard) {
41 if (source.host.empty()) 63 if (source.host.empty())
42 return true; 64 return true;
43 // TODO(arthursonzogni): Chrome used to, incorrectly, match *.x.y to x.y. 65 // TODO(arthursonzogni): Chrome used to, incorrectly, match *.x.y to x.y.
44 // The renderer version of this function count how many times it happens. 66 // The renderer version of this function count how many times it happens.
45 // It might be useful to do it outside of blink too. 67 // It might be useful to do it outside of blink too.
46 // See third_party/WebKit/Source/core/frame/csp/CSPSource.cpp 68 // See third_party/WebKit/Source/core/frame/csp/CSPSource.cpp
47 return base::EndsWith(url.host(), '.' + source.host, 69 return base::EndsWith(url.host(), '.' + source.host,
48 base::CompareCase::INSENSITIVE_ASCII); 70 base::CompareCase::INSENSITIVE_ASCII);
49 } else 71 } else
50 return url.host() == source.host; 72 return url.host() == source.host;
51 } 73 }
52 74
53 bool SourceAllowPort(const CSPSource& source, const GURL& url) { 75 CSPSource::PortMatchingResult SourceAllowPort(
76 const CSPSource& source, const GURL& url) {
arthursonzogni 2017/04/07 09:20:27 Nit: git cl format gives me: CSPSource::PortMatchi
andypaicu 2017/04/07 11:34:24 Done
54 int url_port = url.EffectiveIntPort(); 77 int url_port = url.EffectiveIntPort();
55 78
56 if (source.is_port_wildcard) 79 if (source.is_port_wildcard)
57 return true; 80 return CSPSource::PortMatchingResult::MatchingWildcard;
58 81
59 if (source.port == url::PORT_UNSPECIFIED) 82 if (source.port == url_port) {
60 return DefaultPortForScheme(url.scheme()) == url_port; 83 if (source.port == url::PORT_UNSPECIFIED)
84 return CSPSource::PortMatchingResult::MatchingWildcard;
85 return CSPSource::PortMatchingResult::MatchingExact;
86 }
61 87
62 if (source.port == url_port) 88 if (source.port == url::PORT_UNSPECIFIED) {
63 return true; 89 if (DefaultPortForScheme(url.scheme()) == url_port) {
90 return CSPSource::PortMatchingResult::MatchingWildcard;
91 }
92 return CSPSource::PortMatchingResult::NotMatching;
93 }
64 94
65 if (source.port == 80 && url_port == 443) 95 int source_port = source.port;
66 return true; 96 if (source_port == url::PORT_UNSPECIFIED)
97 source_port = DefaultPortForScheme(source.scheme);
67 98
68 return false; 99 if (source_port == 80 && url_port == 443)
100 return CSPSource::PortMatchingResult::MatchingUpgrade;
101
102 return CSPSource::PortMatchingResult::NotMatching;
69 } 103 }
70 104
71 bool SourceAllowPath(const CSPSource& source, 105 bool SourceAllowPath(const CSPSource& source,
72 const GURL& url, 106 const GURL& url,
73 bool is_redirect) { 107 bool is_redirect) {
74 if (is_redirect) 108 if (is_redirect)
75 return true; 109 return true;
76 110
77 if (source.path.empty() || url.path().empty()) 111 if (source.path.empty() || url.path().empty())
78 return true; 112 return true;
79 113
80 std::string url_path; 114 std::string url_path;
81 if (!DecodePath(url.path(), &url_path)) { 115 if (!DecodePath(url.path(), &url_path)) {
82 // TODO(arthursonzogni): try to figure out if that could happen and how to 116 // TODO(arthursonzogni): try to figure out if that could happen and how to
83 // handle it. 117 // handle it.
84 return false; 118 return false;
85 } 119 }
86 120
87 // If the path represents a directory. 121 // If the path represents a directory.
88 if (base::EndsWith(source.path, "/", base::CompareCase::SENSITIVE)) 122 if (base::EndsWith(source.path, "/", base::CompareCase::SENSITIVE))
89 return base::StartsWith(url_path, source.path, 123 return base::StartsWith(url_path, source.path,
90 base::CompareCase::SENSITIVE); 124 base::CompareCase::SENSITIVE);
91 125
92 // The path represents a file. 126 // The path represents a file.
93 return source.path == url_path; 127 return source.path == url_path;
94 } 128 }
95 129
130 bool inline requiresUpgrade(const CSPSource::PortMatchingResult result) {
131 return result == CSPSource::PortMatchingResult::MatchingUpgrade;
132 }
133 bool inline requiresUpgrade(const CSPSource::SchemeMatchingResult result) {
134 return result == CSPSource::SchemeMatchingResult::MatchingUpgrade;
135 }
136 bool inline canUpgrade(const CSPSource::PortMatchingResult result) {
137 return result == CSPSource::PortMatchingResult::MatchingUpgrade ||
138 result == CSPSource::PortMatchingResult::MatchingWildcard;
arthursonzogni 2017/04/07 09:20:27 Nit: git cl format gives me: bool inline canUpgrad
andypaicu 2017/04/07 11:34:24 Done
139 }
140 bool inline canUpgrade(const CSPSource::SchemeMatchingResult result) {
141 return result == CSPSource::SchemeMatchingResult::MatchingUpgrade;
142 }
143
96 } // namespace 144 } // namespace
97 145
98 CSPSource::CSPSource() 146 CSPSource::CSPSource()
99 : scheme(), 147 : scheme(),
100 host(), 148 host(),
101 is_host_wildcard(false), 149 is_host_wildcard(false),
102 port(url::PORT_UNSPECIFIED), 150 port(url::PORT_UNSPECIFIED),
103 is_port_wildcard(false), 151 is_port_wildcard(false),
104 path() {} 152 path() {}
105 153
(...skipping 16 matching lines...) Expand all
122 170
123 CSPSource::CSPSource(const CSPSource& source) = default; 171 CSPSource::CSPSource(const CSPSource& source) = default;
124 CSPSource::~CSPSource() = default; 172 CSPSource::~CSPSource() = default;
125 173
126 // static 174 // static
127 bool CSPSource::Allow(const CSPSource& source, 175 bool CSPSource::Allow(const CSPSource& source,
128 const GURL& url, 176 const GURL& url,
129 CSPContext* context, 177 CSPContext* context,
130 bool is_redirect) { 178 bool is_redirect) {
131 if (source.IsSchemeOnly()) 179 if (source.IsSchemeOnly())
132 return SourceAllowScheme(source, url, context); 180 return SourceAllowScheme(source, url, context) !=
181 SchemeMatchingResult::NotMatching;
arthursonzogni 2017/04/07 09:20:27 Nit: git cl format gives me: return SourceAllowSch
andypaicu 2017/04/07 11:34:24 Done
133 182
134 return SourceAllowScheme(source, url, context) && 183 PortMatchingResult portResult = SourceAllowPort(source, url);
135 SourceAllowHost(source, url) && SourceAllowPort(source, url) && 184 SchemeMatchingResult schemeResult = SourceAllowScheme(source, url, context);
185
186 if ((requiresUpgrade(schemeResult) || (requiresUpgrade(portResult))) &&
187 (!canUpgrade(schemeResult) || !canUpgrade(portResult))) {
188 return false;
189 }
arthursonzogni 2017/04/07 09:20:27 This looks clearer to me: if (requiresUpgrade(sch
190
191 return schemeResult != SchemeMatchingResult::NotMatching &&
192 SourceAllowHost(source, url) &&
193 portResult != PortMatchingResult::NotMatching &&
136 SourceAllowPath(source, url, is_redirect); 194 SourceAllowPath(source, url, is_redirect);
137 } 195 }
138 196
139 std::string CSPSource::ToString() const { 197 std::string CSPSource::ToString() const {
140 // scheme 198 // scheme
141 if (IsSchemeOnly()) 199 if (IsSchemeOnly())
142 return scheme + ":"; 200 return scheme + ":";
143 201
144 std::stringstream text; 202 std::stringstream text;
145 if (!scheme.empty()) 203 if (!scheme.empty())
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 235
178 bool CSPSource::HasHost() const { 236 bool CSPSource::HasHost() const {
179 return !host.empty() || is_host_wildcard; 237 return !host.empty() || is_host_wildcard;
180 } 238 }
181 239
182 bool CSPSource::HasPath() const { 240 bool CSPSource::HasPath() const {
183 return !path.empty(); 241 return !path.empty();
184 } 242 }
185 243
186 } // namespace content 244 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698