Bug 1346774: move subjectToCSP into static helper function r?ckerschb draft
authorFrederik Braun <fbraun+gh@mozilla.com>
Mon, 27 Mar 2017 14:34:07 +0200
changeset 559677 ccc6986cd646524d766286978b1b218f829ad57d
parent 559608 731639fccc709a4dd95fed7e9dda88efb2227906
child 559678 95028f8c9942b9a3f5523715c19160a7a33bfb04
push id53163
push userbmo:fbraun@mozilla.com
push dateMon, 10 Apr 2017 11:09:42 +0000
reviewersckerschb
bugs1346774
milestone55.0a1
Bug 1346774: move subjectToCSP into static helper function r?ckerschb MozReview-Commit-ID: 7paR4pLnJXD
dom/security/nsCSPService.cpp
dom/security/nsCSPService.h
dom/security/nsCSPUtils.cpp
dom/security/nsCSPUtils.h
--- a/dom/security/nsCSPService.cpp
+++ b/dom/security/nsCSPService.cpp
@@ -7,16 +7,17 @@
 #include "mozilla/Logging.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIURI.h"
 #include "nsIPrincipal.h"
 #include "nsIObserver.h"
 #include "nsIContent.h"
 #include "nsCSPService.h"
+#include "nsCSPUtils.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsError.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "mozilla/Preferences.h"
 #include "nsIScriptError.h"
 #include "nsContentUtils.h"
 #include "nsContentPolicyUtils.h"
@@ -35,75 +36,16 @@ CSPService::CSPService()
 
 CSPService::~CSPService()
 {
   mAppStatusCache.Clear();
 }
 
 NS_IMPL_ISUPPORTS(CSPService, nsIContentPolicy, nsIChannelEventSink)
 
-// Helper function to identify protocols and content types not subject to CSP.
-bool
-subjectToCSP(nsIURI* aURI, nsContentPolicyType aContentType) {
-  // 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) {
-    return false;
-  }
-
-  // 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 into
-  // the category underneath and also "javascript:" which is not
-  // subject to CSP content loading rules.
-  rv = aURI->SchemeIs("about", &match);
-  if (NS_SUCCEEDED(rv) && match) {
-    return false;
-  }
-  rv = aURI->SchemeIs("javascript", &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:
-  // 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;
-  }
-  // 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,
@@ -122,18 +64,18 @@ CSPService::ShouldLoad(uint32_t aContent
 
   // 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 or if the protocol
   // or type 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, aContentType)) {
+  // that are whitelistet in CSP_IsRequestSubjectToCSP()
+  if (!sCSPEnabled || !CSP_IsRequestSubjectToCSP(aContentLocation, aContentType)) {
     return NS_OK;
   }
 
   // query the principal of the document; if no document is passed, then
   // fall back to using the requestPrincipal (e.g. service workers do not
   // pass a document).
   nsCOMPtr<nsINode> node(do_QueryInterface(aRequestContext));
   nsCOMPtr<nsIPrincipal> principal = node ? node->NodePrincipal()
@@ -254,19 +196,19 @@ CSPService::AsyncOnChannelRedirect(nsICh
   if (!loadInfo) {
     return NS_OK;
   }
 
   // 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()
+  // that are whitelistet in CSP_IsRequestSubjectToCSP()
   nsContentPolicyType policyType = loadInfo->InternalContentPolicyType();
-  if (!sCSPEnabled || !subjectToCSP(newUri, policyType)) {
+  if (!sCSPEnabled || !CSP_IsRequestSubjectToCSP(newUri, policyType)) {
     return NS_OK;
   }
 
   /* Since redirecting channels don't call into nsIContentPolicy, we call our
    * Content Policy implementation directly when redirects occur using the
    * information set in the LoadInfo when channels are created.
    *
    * We check if the CSP permits this host for this type of load, if not,
--- a/dom/security/nsCSPService.h
+++ b/dom/security/nsCSPService.h
@@ -6,16 +6,18 @@
 
 #ifndef nsCSPService_h___
 #define nsCSPService_h___
 
 #include "nsXPCOM.h"
 #include "nsIContentPolicy.h"
 #include "nsIChannel.h"
 #include "nsIChannelEventSink.h"
+#include "nsNetUtil.h"
+#include "nsIProtocolHandler.h"
 #include "nsDataHashtable.h"
 
 #define CSPSERVICE_CONTRACTID "@mozilla.org/cspservice;1"
 #define CSPSERVICE_CID \
   { 0x8d2f40b2, 0x4875, 0x4c95, \
     { 0x97, 0xd9, 0x3f, 0x7d, 0xca, 0x2c, 0xb4, 0x60 } }
 class CSPService : public nsIContentPolicy,
                    public nsIChannelEventSink
@@ -30,9 +32,10 @@ public:
 
 protected:
   virtual ~CSPService();
 
 private:
   // Maps origins to app status.
   nsDataHashtable<nsCStringHashKey, uint16_t> mAppStatusCache;
 };
+
 #endif /* nsCSPService_h___ */
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -25,16 +25,75 @@ GetCspUtilsLog()
 {
   static mozilla::LazyLogModule gCspUtilsPRLog("CSPUtils");
   return gCspUtilsPRLog;
 }
 
 #define CSPUTILSLOG(args) MOZ_LOG(GetCspUtilsLog(), mozilla::LogLevel::Debug, args)
 #define CSPUTILSLOGENABLED() MOZ_LOG_TEST(GetCspUtilsLog(), mozilla::LogLevel::Debug)
 
+// Helper function to identify protocols and content types not subject to CSP.
+bool
+CSP_IsRequestSubjectToCSP(nsIURI* aURI, nsContentPolicyType aContentType) {
+  // 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) {
+    return false;
+  }
+
+  // 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 into
+  // the category underneath and also "javascript:" which is not
+  // subject to CSP content loading rules.
+  rv = aURI->SchemeIs("about", &match);
+  if (NS_SUCCEEDED(rv) && match) {
+    return false;
+  }
+  rv = aURI->SchemeIs("javascript", &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:
+  // 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;
+  }
+  // all other protocols are subject To CSP.
+  return true;
+}
+
 void
 CSP_PercentDecodeStr(const nsAString& aEncStr, nsAString& outDecStr)
 {
   outDecStr.Truncate();
 
   // helper function that should not be visible outside this methods scope
   struct local {
     static inline char16_t convertHexDig(char16_t aHexDig) {
--- a/dom/security/nsCSPUtils.h
+++ b/dom/security/nsCSPUtils.h
@@ -6,16 +6,18 @@
 
 #ifndef nsCSPUtils_h___
 #define nsCSPUtils_h___
 
 #include "nsCOMPtr.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIURI.h"
+#include "nsNetUtil.h"
+#include "nsIProtocolHandler.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/Logging.h"
 
 namespace mozilla {
 namespace dom {
   struct CSP;
@@ -111,16 +113,21 @@ inline CSPDirective CSP_StringToCSPDirec
     if (lowerDir.EqualsASCII(CSPStrDirectives[i])) {
       return static_cast<CSPDirective>(i);
     }
   }
   NS_ASSERTION(false, "Can not convert unknown Directive to Integer");
   return nsIContentSecurityPolicy::NO_DIRECTIVE;
 }
 
+// Helper function to identify protocols and content types not subject to CSP.
+bool
+CSP_IsRequestSubjectToCSP(nsIURI* aURI, nsContentPolicyType aContentType);
+
+
 // Please add any new enum items not only to CSPKeyword, but also add
 // a string version for every enum >> using the same index << to
 // CSPStrKeywords underneath.
 enum CSPKeyword {
   CSP_SELF = 0,
   CSP_UNSAFE_INLINE,
   CSP_UNSAFE_EVAL,
   CSP_NONE,