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