| 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 |