Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 "core/loader/BaseFetchContext.h" | 5 #include "core/loader/BaseFetchContext.h" |
| 6 | 6 |
| 7 #include "core/dom/ExecutionContext.h" | |
| 8 #include "core/frame/ContentSettingsClient.h" | |
| 9 #include "core/frame/Settings.h" | |
| 7 #include "core/frame/csp/ContentSecurityPolicy.h" | 10 #include "core/frame/csp/ContentSecurityPolicy.h" |
| 8 #include "core/inspector/ConsoleMessage.h" | 11 #include "core/inspector/ConsoleMessage.h" |
| 12 #include "core/loader/SubresourceFilter.h" | |
| 13 #include "core/loader/private/FrameClientHintsPreferencesContext.h" | |
| 14 #include "platform/exported/WrappedResourceRequest.h" | |
| 15 #include "platform/loader/fetch/FetchInitiatorTypeNames.h" | |
| 16 #include "platform/loader/fetch/Resource.h" | |
| 17 #include "platform/loader/fetch/ResourceLoadPriority.h" | |
| 18 #include "platform/loader/fetch/ResourceLoadingLog.h" | |
| 19 #include "platform/weborigin/SchemeRegistry.h" | |
| 9 #include "platform/weborigin/SecurityPolicy.h" | 20 #include "platform/weborigin/SecurityPolicy.h" |
| 10 | 21 |
| 11 namespace blink { | 22 namespace blink { |
| 12 | 23 |
| 13 BaseFetchContext::BaseFetchContext(ExecutionContext* context) | 24 BaseFetchContext::BaseFetchContext(ExecutionContext* context) |
| 14 : execution_context_(context) {} | 25 : execution_context_(context) {} |
| 15 | 26 |
| 16 void BaseFetchContext::AddAdditionalRequestHeaders(ResourceRequest& request, | 27 void BaseFetchContext::AddAdditionalRequestHeaders(ResourceRequest& request, |
| 17 FetchResourceType type) { | 28 FetchResourceType type) { |
| 18 bool is_main_resource = type == kFetchMainResource; | 29 bool is_main_resource = type == kFetchMainResource; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 36 if (execution_context_) { | 47 if (execution_context_) { |
| 37 request.SetExternalRequestStateFromRequestorAddressSpace( | 48 request.SetExternalRequestStateFromRequestorAddressSpace( |
| 38 execution_context_->GetSecurityContext().AddressSpace()); | 49 execution_context_->GetSecurityContext().AddressSpace()); |
| 39 } | 50 } |
| 40 } | 51 } |
| 41 | 52 |
| 42 SecurityOrigin* BaseFetchContext::GetSecurityOrigin() const { | 53 SecurityOrigin* BaseFetchContext::GetSecurityOrigin() const { |
| 43 return execution_context_ ? execution_context_->GetSecurityOrigin() : nullptr; | 54 return execution_context_ ? execution_context_->GetSecurityOrigin() : nullptr; |
| 44 } | 55 } |
| 45 | 56 |
| 57 ResourceRequestBlockedReason BaseFetchContext::CanRequest( | |
| 58 Resource::Type type, | |
| 59 const ResourceRequest& resource_request, | |
| 60 const KURL& url, | |
| 61 const ResourceLoaderOptions& options, | |
| 62 SecurityViolationReportingPolicy reporting_policy, | |
| 63 FetchParameters::OriginRestriction origin_restriction) const { | |
| 64 ResourceRequestBlockedReason blocked_reason = CanRequestInternal( | |
| 65 type, resource_request, url, options, reporting_policy, | |
| 66 origin_restriction, resource_request.GetRedirectStatus()); | |
| 67 if (blocked_reason != ResourceRequestBlockedReason::kNone && | |
| 68 reporting_policy == SecurityViolationReportingPolicy::kReport) { | |
| 69 DispatchDidBlockRequest(resource_request, options.initiator_info, | |
| 70 blocked_reason); | |
| 71 } | |
| 72 return blocked_reason; | |
| 73 } | |
| 74 | |
| 75 ResourceRequestBlockedReason BaseFetchContext::AllowResponse( | |
| 76 Resource::Type type, | |
| 77 const ResourceRequest& resource_request, | |
| 78 const KURL& url, | |
| 79 const ResourceLoaderOptions& options) const { | |
| 80 ResourceRequestBlockedReason blocked_reason = | |
| 81 CanRequestInternal(type, resource_request, url, options, | |
| 82 SecurityViolationReportingPolicy::kReport, | |
| 83 FetchParameters::kUseDefaultOriginRestrictionForType, | |
| 84 RedirectStatus::kFollowedRedirect); | |
| 85 | |
| 86 if (blocked_reason != ResourceRequestBlockedReason::kNone) { | |
| 87 DispatchDidBlockRequest(resource_request, options.initiator_info, | |
| 88 blocked_reason); | |
| 89 } | |
| 90 return blocked_reason; | |
| 91 } | |
| 92 | |
| 46 void BaseFetchContext::PrintAccessDeniedMessage(const KURL& url) const { | 93 void BaseFetchContext::PrintAccessDeniedMessage(const KURL& url) const { |
| 47 if (url.IsNull()) | 94 if (url.IsNull()) |
| 48 return; | 95 return; |
| 49 | 96 |
| 50 DCHECK(execution_context_); | 97 DCHECK(execution_context_); |
| 51 String message; | 98 String message; |
| 52 if (execution_context_->Url().IsNull()) { | 99 if (execution_context_->Url().IsNull()) { |
| 53 message = "Unsafe attempt to load URL " + url.ElidedString() + '.'; | 100 message = "Unsafe attempt to load URL " + url.ElidedString() + '.'; |
| 54 } else if (url.IsLocalFile() || execution_context_->Url().IsLocalFile()) { | 101 } else if (url.IsLocalFile() || execution_context_->Url().IsLocalFile()) { |
| 55 message = "Unsafe attempt to load URL " + url.ElidedString() + | 102 message = "Unsafe attempt to load URL " + url.ElidedString() + |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 71 ResourceRequest& request) { | 118 ResourceRequest& request) { |
| 72 if (!execution_context_) | 119 if (!execution_context_) |
| 73 return; | 120 return; |
| 74 | 121 |
| 75 const ContentSecurityPolicy* csp = | 122 const ContentSecurityPolicy* csp = |
| 76 execution_context_->GetContentSecurityPolicy(); | 123 execution_context_->GetContentSecurityPolicy(); |
| 77 if (csp->ShouldSendCSPHeader(type)) | 124 if (csp->ShouldSendCSPHeader(type)) |
| 78 request.AddHTTPHeaderField("CSP", "active"); | 125 request.AddHTTPHeaderField("CSP", "active"); |
| 79 } | 126 } |
| 80 | 127 |
| 128 ResourceRequestBlockedReason BaseFetchContext::CanRequestInternal( | |
| 129 Resource::Type type, | |
| 130 const ResourceRequest& resource_request, | |
| 131 const KURL& url, | |
| 132 const ResourceLoaderOptions& options, | |
| 133 SecurityViolationReportingPolicy reporting_policy, | |
| 134 FetchParameters::OriginRestriction origin_restriction, | |
| 135 ResourceRequest::RedirectStatus redirect_status) const { | |
| 136 if (ShouldBlockRequestByInspector(resource_request)) | |
| 137 return ResourceRequestBlockedReason::kInspector; | |
| 138 | |
| 139 SecurityOrigin* security_origin = options.security_origin.Get(); | |
| 140 if (!security_origin && execution_context_) | |
| 141 security_origin = execution_context_->GetSecurityOrigin(); | |
| 142 | |
| 143 if (origin_restriction != FetchParameters::kNoOriginRestriction && | |
| 144 security_origin && !security_origin->CanDisplay(url)) { | |
| 145 if (reporting_policy == SecurityViolationReportingPolicy::kReport) | |
| 146 ReportLocalLoadFailed(url); | |
| 147 RESOURCE_LOADING_DVLOG(1) << "ResourceFetcher::requestResource URL was not " | |
| 148 "allowed by SecurityOrigin::CanDisplay"; | |
| 149 return ResourceRequestBlockedReason::kOther; | |
| 150 } | |
| 151 | |
| 152 // Some types of resources can be loaded only from the same origin. Other | |
| 153 // types of resources, like Images, Scripts, and CSS, can be loaded from | |
| 154 // any URL. | |
| 155 switch (type) { | |
| 156 case Resource::kMainResource: | |
| 157 case Resource::kImage: | |
| 158 case Resource::kCSSStyleSheet: | |
| 159 case Resource::kScript: | |
| 160 case Resource::kFont: | |
| 161 case Resource::kRaw: | |
| 162 case Resource::kLinkPrefetch: | |
| 163 case Resource::kTextTrack: | |
| 164 case Resource::kImportResource: | |
| 165 case Resource::kMedia: | |
| 166 case Resource::kManifest: | |
| 167 case Resource::kMock: | |
| 168 // By default these types of resources can be loaded from any origin. | |
| 169 // FIXME: Are we sure about Resource::kFont? | |
| 170 if (origin_restriction == FetchParameters::kRestrictToSameOrigin && | |
| 171 !security_origin->CanRequest(url)) { | |
| 172 PrintAccessDeniedMessage(url); | |
| 173 return ResourceRequestBlockedReason::kOrigin; | |
| 174 } | |
| 175 break; | |
| 176 case Resource::kXSLStyleSheet: | |
| 177 DCHECK(RuntimeEnabledFeatures::xsltEnabled()); | |
| 178 case Resource::kSVGDocument: | |
| 179 if (!security_origin->CanRequest(url)) { | |
| 180 PrintAccessDeniedMessage(url); | |
| 181 return ResourceRequestBlockedReason::kOrigin; | |
| 182 } | |
| 183 break; | |
| 184 } | |
| 185 | |
| 186 // FIXME: Convert this to check the isolated world's Content Security Policy | |
| 187 // once webkit.org/b/104520 is solved. | |
| 188 bool should_bypass_main_world_csp = | |
| 189 ShouldBypassMainWorldCSP() || options.content_security_policy_option == | |
| 190 kDoNotCheckContentSecurityPolicy; | |
| 191 | |
| 192 if (execution_context_) { | |
| 193 DCHECK(execution_context_->GetContentSecurityPolicy()); | |
| 194 if (!should_bypass_main_world_csp && | |
| 195 !execution_context_->GetContentSecurityPolicy()->AllowRequest( | |
| 196 resource_request.GetRequestContext(), url, | |
| 197 options.content_security_policy_nonce, options.integrity_metadata, | |
| 198 options.parser_disposition, redirect_status, reporting_policy)) | |
| 199 return ResourceRequestBlockedReason::CSP; | |
| 200 } | |
| 201 | |
| 202 if (type == Resource::kScript || type == Resource::kImportResource) { | |
| 203 if (!GetContentSettingsClient()->AllowScriptFromSource( | |
|
horo
2017/04/20 06:00:48
nit: We should check GetContentSettingsClient()
kinuko
2017/04/21 09:45:27
Done.
| |
| 204 !GetSettings() || GetSettings()->GetScriptEnabled(), url)) { | |
| 205 GetContentSettingsClient()->DidNotAllowScript(); | |
| 206 // TODO(estark): Use a different ResourceRequestBlockedReason here, since | |
| 207 // this check has nothing to do with CSP. https://crbug.com/600795 | |
| 208 return ResourceRequestBlockedReason::CSP; | |
| 209 } | |
| 210 } | |
| 211 | |
| 212 // SVG Images have unique security rules that prevent all subresource requests | |
| 213 // except for data urls. | |
| 214 if (type != Resource::kMainResource && IsSVGImageChromeClient() && | |
| 215 !url.ProtocolIsData()) | |
| 216 return ResourceRequestBlockedReason::kOrigin; | |
| 217 | |
| 218 // Measure the number of legacy URL schemes ('ftp://') and the number of | |
| 219 // embedded-credential ('http://user:password@...') resources embedded as | |
| 220 // subresources. | |
| 221 if (resource_request.GetFrameType() != WebURLRequest::kFrameTypeTopLevel) { | |
| 222 if (GetMainResourceSecurityContext() && | |
| 223 SchemeRegistry::ShouldTreatURLSchemeAsLegacy(url.Protocol()) && | |
| 224 !SchemeRegistry::ShouldTreatURLSchemeAsLegacy( | |
| 225 GetMainResourceSecurityContext() | |
| 226 ->GetSecurityOrigin() | |
| 227 ->Protocol())) { | |
| 228 CountDeprecation(UseCounter::kLegacyProtocolEmbeddedAsSubresource); | |
| 229 | |
| 230 // TODO(mkwst): Enabled by default in M59. Drop the runtime-enabled check | |
| 231 // in M60: https://www.chromestatus.com/feature/5709390967472128 | |
| 232 if (RuntimeEnabledFeatures::blockLegacySubresourcesEnabled()) | |
| 233 return ResourceRequestBlockedReason::kOrigin; | |
| 234 } | |
| 235 | |
| 236 if ((!url.User().IsEmpty() || !url.Pass().IsEmpty()) && | |
| 237 resource_request.GetRequestContext() != | |
| 238 WebURLRequest::kRequestContextXMLHttpRequest) { | |
| 239 CountDeprecation( | |
| 240 UseCounter::kRequestedSubresourceWithEmbeddedCredentials); | |
| 241 // TODO(mkwst): Remove the runtime-enabled check in M59: | |
| 242 // https://www.chromestatus.com/feature/5669008342777856 | |
| 243 if (RuntimeEnabledFeatures::blockCredentialedSubresourcesEnabled()) | |
| 244 return ResourceRequestBlockedReason::kOrigin; | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 // Check for mixed content. We do this second-to-last so that when folks block | |
| 249 // mixed content with a CSP policy, they don't get a warning. They'll still | |
| 250 // get a warning in the console about CSP blocking the load. | |
| 251 if (ShouldBlockFetchByMixedContentCheck(resource_request, url, | |
| 252 reporting_policy)) | |
| 253 return ResourceRequestBlockedReason::kMixedContent; | |
| 254 | |
| 255 if (url.WhitespaceRemoved()) { | |
| 256 CountDeprecation(UseCounter::kCanRequestURLHTTPContainingNewline); | |
| 257 if (url.ProtocolIsInHTTPFamily()) { | |
| 258 if (RuntimeEnabledFeatures::restrictCanRequestURLCharacterSetEnabled()) | |
| 259 return ResourceRequestBlockedReason::kOther; | |
| 260 } else { | |
| 261 CountUsage(UseCounter::kCanRequestURLNonHTTPContainingNewline); | |
| 262 } | |
| 263 } | |
| 264 | |
| 265 // Let the client have the final say into whether or not the load should | |
| 266 // proceed. | |
| 267 if (GetSubresourceFilter() && type != Resource::kMainResource && | |
| 268 type != Resource::kImportResource) { | |
| 269 if (!GetSubresourceFilter()->AllowLoad( | |
| 270 url, resource_request.GetRequestContext(), reporting_policy)) { | |
| 271 return ResourceRequestBlockedReason::kSubresourceFilter; | |
| 272 } | |
| 273 } | |
| 274 | |
| 275 return ResourceRequestBlockedReason::kNone; | |
| 276 } | |
| 277 | |
| 81 DEFINE_TRACE(BaseFetchContext) { | 278 DEFINE_TRACE(BaseFetchContext) { |
| 82 visitor->Trace(execution_context_); | 279 visitor->Trace(execution_context_); |
| 83 FetchContext::Trace(visitor); | 280 FetchContext::Trace(visitor); |
| 84 } | 281 } |
| 85 | 282 |
| 86 } // namespace blink | 283 } // namespace blink |
| OLD | NEW |