OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/common/extensions/csp_validator.h" | 5 #include "chrome/common/extensions/csp_validator.h" |
6 | 6 |
7 #include "base/string_split.h" | 7 #include "base/string_split.h" |
8 #include "base/string_tokenizer.h" | 8 #include "base/string_tokenizer.h" |
9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
10 | 10 |
(...skipping 17 matching lines...) Expand all Loading... |
28 : directive_name(name) | 28 : directive_name(name) |
29 , seen_in_policy(false) | 29 , seen_in_policy(false) |
30 , is_secure(false) { | 30 , is_secure(false) { |
31 } | 31 } |
32 | 32 |
33 const char* directive_name; | 33 const char* directive_name; |
34 bool seen_in_policy; | 34 bool seen_in_policy; |
35 bool is_secure; | 35 bool is_secure; |
36 }; | 36 }; |
37 | 37 |
38 bool HasOnlySecureTokens(StringTokenizer& tokenizer, Extension::Type type) { | 38 bool HasOnlySecureTokens(StringTokenizer& tokenizer, Manifest::Type type) { |
39 while (tokenizer.GetNext()) { | 39 while (tokenizer.GetNext()) { |
40 std::string source = tokenizer.token(); | 40 std::string source = tokenizer.token(); |
41 StringToLowerASCII(&source); | 41 StringToLowerASCII(&source); |
42 | 42 |
43 // Don't alow whitelisting of all hosts. This boils down to: | 43 // Don't alow whitelisting of all hosts. This boils down to: |
44 // 1. Maximum of 2 '*' characters. | 44 // 1. Maximum of 2 '*' characters. |
45 // 2. Each '*' is either followed by a '.' or preceded by a ':' | 45 // 2. Each '*' is either followed by a '.' or preceded by a ':' |
46 int wildcards = 0; | 46 int wildcards = 0; |
47 size_t length = source.length(); | 47 size_t length = source.length(); |
48 for (size_t i = 0; i < length; ++i) { | 48 for (size_t i = 0; i < length; ++i) { |
(...skipping 19 matching lines...) Expand all Loading... |
68 StartsWithASCII(source, "http://127.0.0.1:", false) || | 68 StartsWithASCII(source, "http://127.0.0.1:", false) || |
69 StartsWithASCII(source, "http://localhost:", false) || | 69 StartsWithASCII(source, "http://localhost:", false) || |
70 StartsWithASCII(source, "https://", true) || | 70 StartsWithASCII(source, "https://", true) || |
71 StartsWithASCII(source, "chrome://", true) || | 71 StartsWithASCII(source, "chrome://", true) || |
72 StartsWithASCII(source, "chrome-extension://", true) || | 72 StartsWithASCII(source, "chrome-extension://", true) || |
73 StartsWithASCII(source, "chrome-extension-resource:", true)) { | 73 StartsWithASCII(source, "chrome-extension-resource:", true)) { |
74 continue; | 74 continue; |
75 } | 75 } |
76 | 76 |
77 // crbug.com/146487 | 77 // crbug.com/146487 |
78 if (type == Extension::TYPE_EXTENSION || | 78 if (type == Manifest::TYPE_EXTENSION || |
79 type == Extension::TYPE_LEGACY_PACKAGED_APP) { | 79 type == Manifest::TYPE_LEGACY_PACKAGED_APP) { |
80 if (source == "'unsafe-eval'") | 80 if (source == "'unsafe-eval'") |
81 continue; | 81 continue; |
82 } | 82 } |
83 | 83 |
84 return false; | 84 return false; |
85 } | 85 } |
86 | 86 |
87 return true; // Empty values default to 'none', which is secure. | 87 return true; // Empty values default to 'none', which is secure. |
88 } | 88 } |
89 | 89 |
90 // Returns true if |directive_name| matches |status.directive_name|. | 90 // Returns true if |directive_name| matches |status.directive_name|. |
91 bool UpdateStatus(const std::string& directive_name, | 91 bool UpdateStatus(const std::string& directive_name, |
92 StringTokenizer& tokenizer, | 92 StringTokenizer& tokenizer, |
93 DirectiveStatus* status, | 93 DirectiveStatus* status, |
94 Extension::Type type) { | 94 Manifest::Type type) { |
95 if (status->seen_in_policy) | 95 if (status->seen_in_policy) |
96 return false; | 96 return false; |
97 if (directive_name != status->directive_name) | 97 if (directive_name != status->directive_name) |
98 return false; | 98 return false; |
99 status->seen_in_policy = true; | 99 status->seen_in_policy = true; |
100 status->is_secure = HasOnlySecureTokens(tokenizer, type); | 100 status->is_secure = HasOnlySecureTokens(tokenizer, type); |
101 return true; | 101 return true; |
102 } | 102 } |
103 | 103 |
104 } // namespace | 104 } // namespace |
105 | 105 |
106 bool ContentSecurityPolicyIsLegal(const std::string& policy) { | 106 bool ContentSecurityPolicyIsLegal(const std::string& policy) { |
107 // We block these characters to prevent HTTP header injection when | 107 // We block these characters to prevent HTTP header injection when |
108 // representing the content security policy as an HTTP header. | 108 // representing the content security policy as an HTTP header. |
109 const char kBadChars[] = {',', '\r', '\n', '\0'}; | 109 const char kBadChars[] = {',', '\r', '\n', '\0'}; |
110 | 110 |
111 return policy.find_first_of(kBadChars, 0, arraysize(kBadChars)) == | 111 return policy.find_first_of(kBadChars, 0, arraysize(kBadChars)) == |
112 std::string::npos; | 112 std::string::npos; |
113 } | 113 } |
114 | 114 |
115 bool ContentSecurityPolicyIsSecure(const std::string& policy, | 115 bool ContentSecurityPolicyIsSecure(const std::string& policy, |
116 Extension::Type type) { | 116 Manifest::Type type) { |
117 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. | 117 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. |
118 std::vector<std::string> directives; | 118 std::vector<std::string> directives; |
119 base::SplitString(policy, ';', &directives); | 119 base::SplitString(policy, ';', &directives); |
120 | 120 |
121 DirectiveStatus default_src_status(kDefaultSrc); | 121 DirectiveStatus default_src_status(kDefaultSrc); |
122 DirectiveStatus script_src_status(kScriptSrc); | 122 DirectiveStatus script_src_status(kScriptSrc); |
123 DirectiveStatus object_src_status(kObjectSrc); | 123 DirectiveStatus object_src_status(kObjectSrc); |
124 | 124 |
125 for (size_t i = 0; i < directives.size(); ++i) { | 125 for (size_t i = 0; i < directives.size(); ++i) { |
126 std::string& input = directives[i]; | 126 std::string& input = directives[i]; |
(...skipping 21 matching lines...) Expand all Loading... |
148 if (default_src_status.seen_in_policy && !default_src_status.is_secure) { | 148 if (default_src_status.seen_in_policy && !default_src_status.is_secure) { |
149 return script_src_status.seen_in_policy && | 149 return script_src_status.seen_in_policy && |
150 object_src_status.seen_in_policy; | 150 object_src_status.seen_in_policy; |
151 } | 151 } |
152 | 152 |
153 return default_src_status.seen_in_policy || | 153 return default_src_status.seen_in_policy || |
154 (script_src_status.seen_in_policy && object_src_status.seen_in_policy); | 154 (script_src_status.seen_in_policy && object_src_status.seen_in_policy); |
155 } | 155 } |
156 | 156 |
157 bool ContentSecurityPolicyIsSandboxed( | 157 bool ContentSecurityPolicyIsSandboxed( |
158 const std::string& policy, Extension::Type type) { | 158 const std::string& policy, Manifest::Type type) { |
159 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. | 159 // See http://www.w3.org/TR/CSP/#parse-a-csp-policy for parsing algorithm. |
160 std::vector<std::string> directives; | 160 std::vector<std::string> directives; |
161 base::SplitString(policy, ';', &directives); | 161 base::SplitString(policy, ';', &directives); |
162 | 162 |
163 bool seen_sandbox = false; | 163 bool seen_sandbox = false; |
164 | 164 |
165 for (size_t i = 0; i < directives.size(); ++i) { | 165 for (size_t i = 0; i < directives.size(); ++i) { |
166 std::string& input = directives[i]; | 166 std::string& input = directives[i]; |
167 StringTokenizer tokenizer(input, " \t\r\n"); | 167 StringTokenizer tokenizer(input, " \t\r\n"); |
168 if (!tokenizer.GetNext()) | 168 if (!tokenizer.GetNext()) |
169 continue; | 169 continue; |
170 | 170 |
171 std::string directive_name = tokenizer.token(); | 171 std::string directive_name = tokenizer.token(); |
172 StringToLowerASCII(&directive_name); | 172 StringToLowerASCII(&directive_name); |
173 | 173 |
174 if (directive_name != kSandboxDirectiveName) | 174 if (directive_name != kSandboxDirectiveName) |
175 continue; | 175 continue; |
176 | 176 |
177 seen_sandbox = true; | 177 seen_sandbox = true; |
178 | 178 |
179 while (tokenizer.GetNext()) { | 179 while (tokenizer.GetNext()) { |
180 std::string token = tokenizer.token(); | 180 std::string token = tokenizer.token(); |
181 StringToLowerASCII(&token); | 181 StringToLowerASCII(&token); |
182 | 182 |
183 // The same origin token negates the sandboxing. | 183 // The same origin token negates the sandboxing. |
184 if (token == kAllowSameOriginToken) | 184 if (token == kAllowSameOriginToken) |
185 return false; | 185 return false; |
186 | 186 |
187 // Platform apps don't allow navigation. | 187 // Platform apps don't allow navigation. |
188 if (type == Extension::TYPE_PLATFORM_APP) { | 188 if (type == Manifest::TYPE_PLATFORM_APP) { |
189 if (token == kAllowTopNavigation) | 189 if (token == kAllowTopNavigation) |
190 return false; | 190 return false; |
191 } | 191 } |
192 } | 192 } |
193 } | 193 } |
194 | 194 |
195 return seen_sandbox; | 195 return seen_sandbox; |
196 } | 196 } |
197 | 197 |
198 } // csp_validator | 198 } // csp_validator |
199 | 199 |
200 } // extensions | 200 } // extensions |
OLD | NEW |