author | Tanvi Vyas <tvyas@mozilla.com> |
Tue, 20 Nov 2012 20:28:34 -0500 | |
changeset 113853 | 0f76932d28c58881dd87455b031b71e90770c7b1 |
parent 113852 | 0b37a6293086382db3ad3e95e0cb4b8d3380c471 |
child 113854 | dfa9f6c4c60820b8f7e86b5a4a505119bef228fc |
push id | 23891 |
push user | emorley@mozilla.com |
push date | Wed, 21 Nov 2012 15:30:36 +0000 |
treeherder | mozilla-central@905492e644e3 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | sstamm, bz |
bugs | 802905 |
milestone | 20.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
|
--- a/content/base/public/nsContentPolicyUtils.h +++ b/content/base/public/nsContentPolicyUtils.h @@ -102,16 +102,17 @@ NS_CP_ContentTypeName(uint32_t contentTy CASE_RETURN( TYPE_XBL ); CASE_RETURN( TYPE_PING ); CASE_RETURN( TYPE_XMLHTTPREQUEST ); CASE_RETURN( TYPE_OBJECT_SUBREQUEST ); CASE_RETURN( TYPE_DTD ); CASE_RETURN( TYPE_FONT ); CASE_RETURN( TYPE_MEDIA ); CASE_RETURN( TYPE_WEBSOCKET ); + CASE_RETURN( TYPE_CSP_REPORT ); default: return "<Unknown Type>"; } } #endif // defined(PR_LOGGING) #undef CASE_RETURN
--- a/content/base/public/nsIContentPolicy.idl +++ b/content/base/public/nsIContentPolicy.idl @@ -6,116 +6,149 @@ #include "nsISupports.idl" #include "nsIPrincipal.idl" interface nsIURI; interface nsIDOMNode; /** + * The type of nsIContentPolicy::TYPE_* + */ +typedef unsigned long nsContentPolicyType; + +/** * Interface for content policy mechanism. Implementations of this * interface can be used to control loading of various types of out-of-line * content, or processing of certain types of in-line content. * * WARNING: do not block the caller from shouldLoad or shouldProcess (e.g., * by launching a dialog to prompt the user for something). */ -[scriptable,uuid(e590e74f-bac7-4876-8c58-54dde92befb2)] +[scriptable,uuid(e48e3024-f302-4a16-b8b6-2034d3a4b279)] interface nsIContentPolicy : nsISupports { - const unsigned long TYPE_OTHER = 1; + /** + * Gecko/Firefox developers: Do not use TYPE_OTHER under any circumstances. + * + * Extension developers: Whenever it is reasonable, use one of the existing + * content types. If none of the existing content types are right for + * something you are doing, file a bug in the Core/DOM component that + * includes a patch that adds your new content type to the end of the list of + * TYPE_* constants here. But, don't start using your new content type until + * your patch has been accepted, because it will be uncertain what exact + * value and name your new content type will have; in that interim period, + * use TYPE_OTHER. In your patch, document your new content type in the style + * of the existing ones. In the bug you file, provide a more detailed + * description of the new type of content you want Gecko to support, so that + * the existing implementations of nsIContentPolicy can be properly modified + * to deal with that new type of content. + * + * Implementations of nsIContentPolicy should treat this the same way they + * treat unknown types, because existing users of TYPE_OTHER may be converted + * to use new content types. + */ + const nsContentPolicyType TYPE_OTHER = 1; /** * Indicates an executable script (such as JavaScript). */ - const unsigned long TYPE_SCRIPT = 2; + const nsContentPolicyType TYPE_SCRIPT = 2; /** * Indicates an image (e.g., IMG elements). */ - const unsigned long TYPE_IMAGE = 3; + const nsContentPolicyType TYPE_IMAGE = 3; /** * Indicates a stylesheet (e.g., STYLE elements). */ - const unsigned long TYPE_STYLESHEET = 4; + const nsContentPolicyType TYPE_STYLESHEET = 4; /** * Indicates a generic object (plugin-handled content typically falls under * this category). */ - const unsigned long TYPE_OBJECT = 5; + const nsContentPolicyType TYPE_OBJECT = 5; /** * Indicates a document at the top-level (i.e., in a browser). */ - const unsigned long TYPE_DOCUMENT = 6; + const nsContentPolicyType TYPE_DOCUMENT = 6; /** * Indicates a document contained within another document (e.g., IFRAMEs, * FRAMES, and OBJECTs). */ - const unsigned long TYPE_SUBDOCUMENT = 7; + const nsContentPolicyType TYPE_SUBDOCUMENT = 7; /** * Indicates a timed refresh. * * shouldLoad will never get this, because it does not represent content * to be loaded (the actual load triggered by the refresh will go through * shouldLoad as expected). * * shouldProcess will get this for, e.g., META Refresh elements and HTTP * Refresh headers. */ - const unsigned long TYPE_REFRESH = 8; + const nsContentPolicyType TYPE_REFRESH = 8; /** * Indicates an XBL binding request, triggered either by -moz-binding CSS * property or Document.addBinding method. */ - const unsigned long TYPE_XBL = 9; + const nsContentPolicyType TYPE_XBL = 9; /** * Indicates a ping triggered by a click on <A PING="..."> element. */ - const unsigned long TYPE_PING = 10; + const nsContentPolicyType TYPE_PING = 10; /** * Indicates an XMLHttpRequest. Also used for document.load and for EventSource. */ - const unsigned long TYPE_XMLHTTPREQUEST = 11; - const unsigned long TYPE_DATAREQUEST = 11; // alias + const nsContentPolicyType TYPE_XMLHTTPREQUEST = 11; + const nsContentPolicyType TYPE_DATAREQUEST = 11; // alias /** * Indicates a request by a plugin. */ - const unsigned long TYPE_OBJECT_SUBREQUEST = 12; + const nsContentPolicyType TYPE_OBJECT_SUBREQUEST = 12; /** * Indicates a DTD loaded by an XML document. */ - const unsigned long TYPE_DTD = 13; + const nsContentPolicyType TYPE_DTD = 13; /** * Indicates a font loaded via @font-face rule. */ - const unsigned long TYPE_FONT = 14; + const nsContentPolicyType TYPE_FONT = 14; /** * Indicates a video or audio load. */ - const unsigned long TYPE_MEDIA = 15; + const nsContentPolicyType TYPE_MEDIA = 15; /** * Indicates a WebSocket load. */ - const unsigned long TYPE_WEBSOCKET = 16; + const nsContentPolicyType TYPE_WEBSOCKET = 16; - /* Please update nsContentBlocker when adding new content types. */ + /** + * Indicates a Content Security Policy report. + */ + const nsContentPolicyType TYPE_CSP_REPORT = 17; + + /* When adding new content types, please update nsContentBlocker, + * NS_CP_ContentTypeName, contentScurityPolicy.js, all nsIContentPolicy + * implementations, and other things that are not listed here that are + * related to nsIContentPolicy. */ ////////////////////////////////////////////////////////////////////// /** * Returned from shouldLoad or shouldProcess if the load or process request * is rejected based on details of the request. */ const short REJECT_REQUEST = -1; @@ -130,17 +163,17 @@ interface nsIContentPolicy : nsISupports const short REJECT_TYPE = -2; /** * Returned from shouldLoad or shouldProcess if the load/process is rejected * based on the server it is hosted on or requested from (aContentLocation or * aRequestOrigin), e.g., if you block an IMAGE because it is served from * goatse.cx (even if you don't necessarily block other types from that * server/domain). - * + * * NOTE that it is not meant to stop future requests for this server--only the * current request. */ const short REJECT_SERVER = -3; /** * Returned from shouldLoad or shouldProcess if the load/process is rejected * based on some other criteria. Mozilla callers will handle this like @@ -208,17 +241,17 @@ interface nsIContentPolicy : nsISupports * 5) [JavaScript implementations only] Access properties of any sort on any * object without using XPCNativeWrapper (either explicitly or * implicitly). Due to various DOM0 things, this leads to item 4. * If you do any of these things in your shouldLoad implementation, expect * unpredictable behavior, possibly including crashes, content not showing * up, content showing up doubled, etc. If you need to do any of the things * above, do them off timeout or event. */ - short shouldLoad(in unsigned long aContentType, + short shouldLoad(in nsContentPolicyType aContentType, in nsIURI aContentLocation, in nsIURI aRequestOrigin, in nsISupports aContext, in ACString aMimeTypeGuess, in nsISupports aExtra, [optional] in nsIPrincipal aRequestPrincipal); /** @@ -251,17 +284,17 @@ interface nsIContentPolicy : nsISupports * callers to pass extra data to callees. * * @return ACCEPT or REJECT_* * * @note shouldProcess can be called while the DOM and layout of the document * involved is in an inconsistent state. See the note on shouldLoad to see * what this means for implementors of this method. */ - short shouldProcess(in unsigned long aContentType, + short shouldProcess(in nsContentPolicyType aContentType, in nsIURI aContentLocation, in nsIURI aRequestOrigin, in nsISupports aContext, in ACString aMimeType, in nsISupports aExtra, [optional] in nsIPrincipal aRequestPrincipal); };
--- a/content/base/src/contentSecurityPolicy.js +++ b/content/base/src/contentSecurityPolicy.js @@ -32,16 +32,18 @@ function ContentSecurityPolicy() { this._reportOnlyMode = false; this._policy = CSPRep.fromString("default-src *"); // default options "wide open" since this policy will be intersected soon this._policy._allowInlineScripts = true; this._policy._allowEval = true; this._request = ""; + this._requestOrigin = ""; + this._requestPrincipal = ""; this._referrer = ""; this._docRequest = null; CSPdebug("CSP POLICY INITED TO 'default-src *'"); } /* * Set up mappings from nsIContentPolicy content types to CSP directives. */ @@ -68,16 +70,18 @@ function ContentSecurityPolicy() { csp._MAPPINGS[cp.TYPE_OBJECT] = cspr_sd.OBJECT_SRC; csp._MAPPINGS[cp.TYPE_OBJECT_SUBREQUEST] = cspr_sd.OBJECT_SRC; csp._MAPPINGS[cp.TYPE_SUBDOCUMENT] = cspr_sd.FRAME_SRC; csp._MAPPINGS[cp.TYPE_MEDIA] = cspr_sd.MEDIA_SRC; csp._MAPPINGS[cp.TYPE_FONT] = cspr_sd.FONT_SRC; csp._MAPPINGS[cp.TYPE_XMLHTTPREQUEST] = cspr_sd.XHR_SRC; csp._MAPPINGS[cp.TYPE_WEBSOCKET] = cspr_sd.XHR_SRC; + /* CSP cannot block CSP reports */ + csp._MAPPINGS[cp.TYPE_CSP_REPORT] = null; /* These must go through the catch-all */ csp._MAPPINGS[cp.TYPE_XBL] = cspr_sd.DEFAULT_SRC; csp._MAPPINGS[cp.TYPE_PING] = cspr_sd.DEFAULT_SRC; csp._MAPPINGS[cp.TYPE_DTD] = cspr_sd.DEFAULT_SRC; } ContentSecurityPolicy.prototype = { @@ -164,16 +168,21 @@ ContentSecurityPolicy.prototype = { // Save the docRequest for fetching a policy-uri this._docRequest = aChannel; // save the document URI (minus <fragment>) and referrer for reporting let uri = aChannel.URI.cloneIgnoringRef(); uri.userPass = ''; this._request = uri.asciiSpec; + this._requestOrigin = uri; + + //store a reference to the principal, that can later be used in shouldLoad + this._requestPrincipal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]. + getService(Components.interfaces.nsIScriptSecurityManager).getChannelPrincipal(aChannel); if (aChannel.referrer) { let referrer = aChannel.referrer.cloneIgnoringRef(); referrer.userPass = ''; this._referrer = referrer.asciiSpec; } }, @@ -197,26 +206,26 @@ ContentSecurityPolicy.prototype = { selfURI = selfURI.innermostURI; } // stay uninitialized until policy merging is done this._isInitialized = false; // If there is a policy-uri, fetch the policy, then re-call this function. // (1) parse and create a CSPRep object - // Note that we pass the full URI since when it's parsed as 'self' to construct a - // CSPSource only the scheme, host, and port are kept. + // Note that we pass the full URI since when it's parsed as 'self' to construct a + // CSPSource only the scheme, host, and port are kept. var newpolicy = CSPRep.fromString(aPolicy, selfURI, this._docRequest, this); // (2) Intersect the currently installed CSPRep object with the new one var intersect = this._policy.intersectWith(newpolicy); - + // (3) Save the result this._policy = intersect; this._isInitialized = true; }, /** * Generates and sends a violation report to the specified report URIs. */ @@ -320,18 +329,19 @@ ContentSecurityPolicy.prototype = { chan.requestMethod = "POST"; } catch(e) {} // throws only if chan is not an nsIHttpChannel. // check with the content policy service to see if we're allowed to // send this request. try { var contentPolicy = Cc["@mozilla.org/layout/content-policy;1"] .getService(Ci.nsIContentPolicy); - if (contentPolicy.shouldLoad(Ci.nsIContentPolicy.TYPE_OTHER, - chan.URI, null, null, null, null) + if (contentPolicy.shouldLoad(Ci.nsIContentPolicy.TYPE_CSP_REPORT, + chan.URI, this._requestOrigin, + null, null, null, this._requestPrincipal) != Ci.nsIContentPolicy.ACCEPT) { continue; // skip unauthorized URIs } } catch(e) { continue; // refuse to load if we can't do a security check. } //send data (and set up error notifications) @@ -373,17 +383,17 @@ ContentSecurityPolicy.prototype = { if (it.currentURI) { if (it.currentURI.scheme === "chrome") { break; } let ancestor = it.currentURI; CSPdebug(" found frame ancestor " + ancestor.asciiSpec); ancestors.push(ancestor); } - } + } // scan the discovered ancestors let cspContext = CSPRep.SRC_DIRECTIVES.FRAME_ANCESTORS; for (let i in ancestors) { let ancestor = ancestors[i].prePath; if (!this._policy.permits(ancestor, cspContext)) { // report the frame-ancestor violation let directive = this._policy._directives[cspContext]; @@ -401,21 +411,21 @@ ContentSecurityPolicy.prototype = { }, /** * Delegate method called by the service when sub-elements of the protected * document are being loaded. Given a bit of information about the request, * decides whether or not the policy is satisfied. */ shouldLoad: - function csp_shouldLoad(aContentType, - aContentLocation, - aRequestOrigin, - aContext, - aMimeTypeGuess, + function csp_shouldLoad(aContentType, + aContentLocation, + aRequestOrigin, + aContext, + aMimeTypeGuess, aOriginalUri) { // don't filter chrome stuff if (aContentLocation.scheme === 'chrome' || aContentLocation.scheme === 'resource') { return Ci.nsIContentPolicy.ACCEPT; } @@ -425,40 +435,40 @@ ContentSecurityPolicy.prototype = { var cspContext = ContentSecurityPolicy._MAPPINGS[aContentType]; // if the mapping is null, there's no policy, let it through. if (!cspContext) { return Ci.nsIContentPolicy.ACCEPT; } // otherwise, honor the translation - // var source = aContentLocation.scheme + "://" + aContentLocation.hostPort; + // var source = aContentLocation.scheme + "://" + aContentLocation.hostPort; var res = this._policy.permits(aContentLocation, cspContext) - ? Ci.nsIContentPolicy.ACCEPT + ? Ci.nsIContentPolicy.ACCEPT : Ci.nsIContentPolicy.REJECT_SERVER; // frame-ancestors is taken care of early on (as this document is loaded) // If the result is *NOT* ACCEPT, then send report - if (res != Ci.nsIContentPolicy.ACCEPT) { + if (res != Ci.nsIContentPolicy.ACCEPT) { CSPdebug("blocking request for " + aContentLocation.asciiSpec); try { let directive = this._policy._directives[cspContext]; let violatedPolicy = (directive._isImplicit ? 'default-src' : cspContext) + ' ' + directive.toString(); this._asyncReportViolation(aContentLocation, aOriginalUri, violatedPolicy); } catch(e) { CSPdebug('---------------- ERROR: ' + e); } } return (this._reportOnlyMode ? Ci.nsIContentPolicy.ACCEPT : res); }, - + shouldProcess: function csp_shouldProcess(aContentType, aContentLocation, aRequestOrigin, aContext, aMimeType, aExtra) { // frame-ancestors check is done outside the ContentPolicy
--- a/extensions/permissions/nsContentBlocker.cpp +++ b/extensions/permissions/nsContentBlocker.cpp @@ -31,17 +31,18 @@ static const char *kTypeString[] = {"oth "refresh", "xbl", "ping", "xmlhttprequest", "objectsubrequest", "dtd", "font", "media", - "websocket"}; + "websocket" + "csp_report"}; #define NUMBER_OF_TYPES NS_ARRAY_LENGTH(kTypeString) uint8_t nsContentBlocker::mBehaviorPref[NUMBER_OF_TYPES]; NS_IMPL_ISUPPORTS3(nsContentBlocker, nsIContentPolicy, nsIObserver, nsSupportsWeakReference)