OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2008 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 "chrome/browser/renderer_host/renderer_security_policy.h" | |
6 | |
7 #include "base/file_path.h" | |
8 #include "base/logging.h" | |
9 #include "base/stl_util-inl.h" | |
10 #include "base/string_util.h" | |
11 #include "chrome/common/url_constants.h" | |
12 #include "googleurl/src/gurl.h" | |
13 #include "net/url_request/url_request.h" | |
14 | |
15 // The SecurityState class is used to maintain per-renderer security state | |
16 // information. | |
17 class RendererSecurityPolicy::SecurityState { | |
18 public: | |
19 SecurityState() : has_dom_ui_bindings_(false) { } | |
20 ~SecurityState() { | |
21 scheme_policy_.clear(); | |
22 } | |
23 | |
24 // Grant permission to request URLs with the specified scheme. | |
25 void GrantScheme(const std::string& scheme) { | |
26 scheme_policy_[scheme] = true; | |
27 } | |
28 | |
29 // Revoke permission to request URLs with the specified scheme. | |
30 void RevokeScheme(const std::string& scheme) { | |
31 scheme_policy_[scheme] = false; | |
32 } | |
33 | |
34 // Grant permission to upload the specified file to the web. | |
35 void GrantUploadFile(const FilePath& file) { | |
36 uploadable_files_.insert(file); | |
37 } | |
38 | |
39 void GrantDOMUIBindings() { | |
40 has_dom_ui_bindings_ = true; | |
41 } | |
42 | |
43 // Determine whether permission has been granted to request url. | |
44 // Schemes that have not been granted default to being denied. | |
45 bool CanRequestURL(const GURL& url) { | |
46 SchemeMap::const_iterator judgment(scheme_policy_.find(url.scheme())); | |
47 | |
48 if (judgment == scheme_policy_.end()) | |
49 return false; // Unmentioned schemes are disallowed. | |
50 | |
51 return judgment->second; | |
52 } | |
53 | |
54 // Determine whether permission has been granted to upload file. | |
55 // Files that have not been granted default to being denied. | |
56 bool CanUploadFile(const FilePath& file) { | |
57 return uploadable_files_.find(file) != uploadable_files_.end(); | |
58 } | |
59 | |
60 bool has_dom_ui_bindings() const { return has_dom_ui_bindings_; } | |
61 | |
62 private: | |
63 typedef std::map<std::string, bool> SchemeMap; | |
64 typedef std::set<FilePath> FileSet; | |
65 | |
66 // Maps URL schemes to whether permission has been granted or revoked: | |
67 // |true| means the scheme has been granted. | |
68 // |false| means the scheme has been revoked. | |
69 // If a scheme is not present in the map, then it has never been granted | |
70 // or revoked. | |
71 SchemeMap scheme_policy_; | |
72 | |
73 // The set of files the renderer is permited to upload to the web. | |
74 FileSet uploadable_files_; | |
75 | |
76 bool has_dom_ui_bindings_; | |
77 | |
78 DISALLOW_COPY_AND_ASSIGN(SecurityState); | |
79 }; | |
80 | |
81 RendererSecurityPolicy::RendererSecurityPolicy() { | |
82 // We know about these schemes and believe them to be safe. | |
83 RegisterWebSafeScheme(chrome::kHttpScheme); | |
84 RegisterWebSafeScheme(chrome::kHttpsScheme); | |
85 RegisterWebSafeScheme(chrome::kFtpScheme); | |
86 RegisterWebSafeScheme(chrome::kDataScheme); | |
87 RegisterWebSafeScheme("feed"); | |
88 RegisterWebSafeScheme("chrome-extension"); | |
89 | |
90 // We know about the following psuedo schemes and treat them specially. | |
91 RegisterPseudoScheme(chrome::kAboutScheme); | |
92 RegisterPseudoScheme(chrome::kJavaScriptScheme); | |
93 RegisterPseudoScheme(chrome::kViewSourceScheme); | |
94 } | |
95 | |
96 RendererSecurityPolicy::~RendererSecurityPolicy() { | |
97 web_safe_schemes_.clear(); | |
98 pseudo_schemes_.clear(); | |
99 STLDeleteContainerPairSecondPointers(security_state_.begin(), | |
100 security_state_.end()); | |
101 security_state_.clear(); | |
102 } | |
103 | |
104 // static | |
105 RendererSecurityPolicy* RendererSecurityPolicy::GetInstance() { | |
106 return Singleton<RendererSecurityPolicy>::get(); | |
107 } | |
108 | |
109 void RendererSecurityPolicy::Add(int renderer_id) { | |
110 AutoLock lock(lock_); | |
111 if (security_state_.count(renderer_id) != 0) { | |
112 NOTREACHED() << "Add renderers at most once."; | |
113 return; | |
114 } | |
115 | |
116 security_state_[renderer_id] = new SecurityState(); | |
117 } | |
118 | |
119 void RendererSecurityPolicy::Remove(int renderer_id) { | |
120 AutoLock lock(lock_); | |
121 if (security_state_.count(renderer_id) != 1) { | |
122 NOTREACHED() << "Remove renderers at most once."; | |
123 return; | |
124 } | |
125 | |
126 delete security_state_[renderer_id]; | |
127 security_state_.erase(renderer_id); | |
128 } | |
129 | |
130 void RendererSecurityPolicy::RegisterWebSafeScheme(const std::string& scheme) { | |
131 AutoLock lock(lock_); | |
132 DCHECK(web_safe_schemes_.count(scheme) == 0) << "Add schemes at most once."; | |
133 DCHECK(pseudo_schemes_.count(scheme) == 0) << "Web-safe implies not psuedo."; | |
134 | |
135 web_safe_schemes_.insert(scheme); | |
136 } | |
137 | |
138 bool RendererSecurityPolicy::IsWebSafeScheme(const std::string& scheme) { | |
139 AutoLock lock(lock_); | |
140 | |
141 return (web_safe_schemes_.find(scheme) != web_safe_schemes_.end()); | |
142 } | |
143 | |
144 void RendererSecurityPolicy::RegisterPseudoScheme(const std::string& scheme) { | |
145 AutoLock lock(lock_); | |
146 DCHECK(pseudo_schemes_.count(scheme) == 0) << "Add schemes at most once."; | |
147 DCHECK(web_safe_schemes_.count(scheme) == 0) << | |
148 "Psuedo implies not web-safe."; | |
149 | |
150 pseudo_schemes_.insert(scheme); | |
151 } | |
152 | |
153 bool RendererSecurityPolicy::IsPseudoScheme(const std::string& scheme) { | |
154 AutoLock lock(lock_); | |
155 | |
156 return (pseudo_schemes_.find(scheme) != pseudo_schemes_.end()); | |
157 } | |
158 | |
159 void RendererSecurityPolicy::GrantRequestURL(int renderer_id, const GURL& url) { | |
160 | |
161 if (!url.is_valid()) | |
162 return; // Can't grant the capability to request invalid URLs. | |
163 | |
164 if (IsWebSafeScheme(url.scheme())) | |
165 return; // The scheme has already been white-listed for every renderer. | |
166 | |
167 if (IsPseudoScheme(url.scheme())) { | |
168 // The view-source scheme is a special case of a pseudo URL that eventually | |
169 // results in requesting its embedded URL. | |
170 if (url.SchemeIs(chrome::kViewSourceScheme)) { | |
171 // URLs with the view-source scheme typically look like: | |
172 // view-source:http://www.google.com/a | |
173 // In order to request these URLs, the renderer needs to be able to | |
174 // request the embedded URL. | |
175 GrantRequestURL(renderer_id, GURL(url.path())); | |
176 } | |
177 | |
178 return; // Can't grant the capability to request pseudo schemes. | |
179 } | |
180 | |
181 { | |
182 AutoLock lock(lock_); | |
183 SecurityStateMap::iterator state = security_state_.find(renderer_id); | |
184 if (state == security_state_.end()) | |
185 return; | |
186 | |
187 // If the renderer has been commanded to request a scheme, then we grant | |
188 // it the capability to request URLs of that scheme. | |
189 state->second->GrantScheme(url.scheme()); | |
190 } | |
191 } | |
192 | |
193 void RendererSecurityPolicy::GrantUploadFile(int renderer_id, | |
194 const FilePath& file) { | |
195 AutoLock lock(lock_); | |
196 | |
197 SecurityStateMap::iterator state = security_state_.find(renderer_id); | |
198 if (state == security_state_.end()) | |
199 return; | |
200 | |
201 state->second->GrantUploadFile(file); | |
202 } | |
203 | |
204 void RendererSecurityPolicy::GrantInspectElement(int renderer_id) { | |
205 AutoLock lock(lock_); | |
206 | |
207 SecurityStateMap::iterator state = security_state_.find(renderer_id); | |
208 if (state == security_state_.end()) | |
209 return; | |
210 | |
211 // The inspector is served from a chrome: URL. In order to run the | |
212 // inspector, the renderer needs to be able to load chrome: URLs. | |
213 state->second->GrantScheme(chrome::kChromeUIScheme); | |
214 } | |
215 | |
216 void RendererSecurityPolicy::GrantDOMUIBindings(int renderer_id) { | |
217 AutoLock lock(lock_); | |
218 | |
219 SecurityStateMap::iterator state = security_state_.find(renderer_id); | |
220 if (state == security_state_.end()) | |
221 return; | |
222 | |
223 state->second->GrantDOMUIBindings(); | |
224 | |
225 // DOM UI bindings need the ability to request chrome: URLs. | |
226 state->second->GrantScheme(chrome::kChromeUIScheme); | |
227 | |
228 // DOM UI pages can contain links to file:// URLs. | |
229 state->second->GrantScheme(chrome::kFileScheme); | |
230 } | |
231 | |
232 bool RendererSecurityPolicy::CanRequestURL(int renderer_id, const GURL& url) { | |
233 if (!url.is_valid()) | |
234 return false; // Can't request invalid URLs. | |
235 | |
236 if (IsWebSafeScheme(url.scheme())) | |
237 return true; // The scheme has been white-listed for every renderer. | |
238 | |
239 if (IsPseudoScheme(url.scheme())) { | |
240 // There are a number of special cases for pseudo schemes. | |
241 | |
242 if (url.SchemeIs(chrome::kViewSourceScheme)) { | |
243 // A view-source URL is allowed if the renderer is permitted to request | |
244 // the embedded URL. | |
245 return CanRequestURL(renderer_id, GURL(url.path())); | |
246 } | |
247 | |
248 if (LowerCaseEqualsASCII(url.spec(), chrome::kAboutBlankURL)) | |
249 return true; // Every renderer can request <about:blank>. | |
250 | |
251 // URLs like <about:memory> and <about:crash> shouldn't be requestable by | |
252 // any renderer. Also, this case covers <javascript:...>, which should be | |
253 // handled internally by the renderer and not kicked up to the browser. | |
254 return false; | |
255 } | |
256 | |
257 if (!URLRequest::IsHandledURL(url)) | |
258 return true; // This URL request is destined for ShellExecute. | |
259 | |
260 { | |
261 AutoLock lock(lock_); | |
262 | |
263 SecurityStateMap::iterator state = security_state_.find(renderer_id); | |
264 if (state == security_state_.end()) | |
265 return false; | |
266 | |
267 // Otherwise, we consult the renderer's security state to see if it is | |
268 // allowed to request the URL. | |
269 return state->second->CanRequestURL(url); | |
270 } | |
271 } | |
272 | |
273 bool RendererSecurityPolicy::CanUploadFile(int renderer_id, | |
274 const FilePath& file) { | |
275 AutoLock lock(lock_); | |
276 | |
277 SecurityStateMap::iterator state = security_state_.find(renderer_id); | |
278 if (state == security_state_.end()) | |
279 return false; | |
280 | |
281 return state->second->CanUploadFile(file); | |
282 } | |
283 | |
284 bool RendererSecurityPolicy::HasDOMUIBindings(int renderer_id) { | |
285 AutoLock lock(lock_); | |
286 | |
287 SecurityStateMap::iterator state = security_state_.find(renderer_id); | |
288 if (state == security_state_.end()) | |
289 return false; | |
290 | |
291 return state->second->has_dom_ui_bindings(); | |
292 } | |
OLD | NEW |