Bug 1021669 - Use protocol flags to whiteliste protocols not suspect to CSP (r=sstamm)
authorChristoph Kerschbaumer <mozilla@christophkerschbaumer.com>
Thu, 20 Nov 2014 14:59:53 -0800
changeset 218255 80b2348e3ab6b7a8c91733597eff20711436e4c5
parent 218254 4b2124129654f76ebdf7620ab742aff4660a75ef
child 218256 2e1da9ea1c9fd11839b180103a2a340f3abf5c2e
push id27925
push usercbook@mozilla.com
push dateWed, 03 Dec 2014 12:32:33 +0000
treeherdermozilla-central@59b7bf5d119d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstamm
bugs1021669
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1021669 - Use protocol flags to whiteliste protocols not suspect to CSP (r=sstamm)
dom/security/nsCSPService.cpp
--- a/dom/security/nsCSPService.cpp
+++ b/dom/security/nsCSPService.cpp
@@ -42,62 +42,101 @@ CSPService::CSPService()
 
 CSPService::~CSPService()
 {
   mAppStatusCache.Clear();
 }
 
 NS_IMPL_ISUPPORTS(CSPService, nsIContentPolicy, nsIChannelEventSink)
 
+// Helper function to identify protocols not subject to CSP.
+bool
+subjectToCSP(nsIURI* aURI) {
+  // The three protocols: data:, blob: and filesystem: share the same
+  // protocol flag (URI_IS_LOCAL_RESOURCE) with other protocols, like
+  // chrome:, resource:, moz-icon:, but those three protocols get
+  // special attention in CSP and are subject to CSP, hence we have
+  // to make sure those protocols are subject to CSP, see:
+  // http://www.w3.org/TR/CSP2/#source-list-guid-matching
+  bool match = false;
+  nsresult rv = aURI->SchemeIs("data", &match);
+  if (NS_SUCCEEDED(rv) && match) {
+    return true;
+  }
+  rv = aURI->SchemeIs("blob", &match);
+  if (NS_SUCCEEDED(rv) && match) {
+    return true;
+  }
+  rv = aURI->SchemeIs("filesystem", &match);
+  if (NS_SUCCEEDED(rv) && match) {
+    return true;
+  }
+  // finally we have to whitelist "about:" which does not fall in
+  // any of the two categories underneath but is not subject to CSP.
+  rv = aURI->SchemeIs("about", &match);
+  if (NS_SUCCEEDED(rv) && match) {
+    return false;
+  }
+
+  // Other protocols are not subject to CSP and can be whitelisted:
+  // * URI_IS_LOCAL_RESOURCE
+  //   e.g. chrome:, data:, blob:, resource:, moz-icon:
+  // * URI_INHERITS_SECURITY_CONTEXT
+  //   e.g. javascript:
+  //
+  // Please note that it should be possible for websites to
+  // whitelist their own protocol handlers with respect to CSP,
+  // hence we use protocol flags to accomplish that.
+  rv = NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, &match);
+  if (NS_SUCCEEDED(rv) && match) {
+    return false;
+  }
+  rv = NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, &match);
+  if (NS_SUCCEEDED(rv) && match) {
+    return false;
+  }
+  // all other protocols are subject To CSP.
+  return true;
+}
+
 /* nsIContentPolicy implementation */
 NS_IMETHODIMP
 CSPService::ShouldLoad(uint32_t aContentType,
                        nsIURI *aContentLocation,
                        nsIURI *aRequestOrigin,
                        nsISupports *aRequestContext,
                        const nsACString &aMimeTypeGuess,
                        nsISupports *aExtra,
                        nsIPrincipal *aRequestPrincipal,
                        int16_t *aDecision)
 {
-  if (!aContentLocation)
+  if (!aContentLocation) {
     return NS_ERROR_FAILURE;
+  }
 
 #ifdef PR_LOGGING
   {
     nsAutoCString location;
     aContentLocation->GetSpec(location);
     PR_LOG(gCspPRLog, PR_LOG_DEBUG,
            ("CSPService::ShouldLoad called for %s", location.get()));
   }
 #endif
 
   // default decision, CSP can revise it if there's a policy to enforce
   *aDecision = nsIContentPolicy::ACCEPT;
 
-  // No need to continue processing if CSP is disabled
-  if (!sCSPEnabled)
-    return NS_OK;
-
-  // shortcut for about: chrome: and resource: and javascript: uris since
-  // they're not subject to CSP content policy checks.
-  bool schemeMatch = false;
-  NS_ENSURE_SUCCESS(aContentLocation->SchemeIs("about", &schemeMatch), NS_OK);
-  if (schemeMatch)
+  // No need to continue processing if CSP is disabled or if the protocol
+  // is *not* subject to CSP.
+  // Please note, the correct way to opt-out of CSP using a custom
+  // protocolHandler is to set one of the nsIProtocolHandler flags
+  // that are whitelistet in subjectToCSP()
+  if (!sCSPEnabled || !subjectToCSP(aContentLocation)) {
     return NS_OK;
-  NS_ENSURE_SUCCESS(aContentLocation->SchemeIs("chrome", &schemeMatch), NS_OK);
-  if (schemeMatch)
-    return NS_OK;
-  NS_ENSURE_SUCCESS(aContentLocation->SchemeIs("resource", &schemeMatch), NS_OK);
-  if (schemeMatch)
-    return NS_OK;
-  NS_ENSURE_SUCCESS(aContentLocation->SchemeIs("javascript", &schemeMatch), NS_OK);
-  if (schemeMatch)
-    return NS_OK;
-
+  }
 
   // These content types are not subject to CSP content policy checks:
   // TYPE_CSP_REPORT -- csp can't block csp reports
   // TYPE_REFRESH    -- never passed to ShouldLoad (see nsIContentPolicy.idl)
   // TYPE_DOCUMENT   -- used for frame-ancestors
   if (aContentType == nsIContentPolicy::TYPE_CSP_REPORT ||
     aContentType == nsIContentPolicy::TYPE_REFRESH ||
     aContentType == nsIContentPolicy::TYPE_DOCUMENT) {