Bug 780978 - remove makeExplicit() from CSPUtils.jsm. (r=imelven)

This commit is contained in:
Sid Stamm 2013-06-21 16:43:13 -07:00
parent f59f7834c5
commit 6910532ccd
3 changed files with 127 additions and 102 deletions

View File

@ -472,12 +472,13 @@ CSPRep.fromString = function(aStr, self, docRequest, csp) {
} // end directive: loop
// TODO : clean this up using patch in bug 780978
// if makeExplicit fails for any reason, default to default-src 'none'. This
// includes the case where "default-src" is not present.
if (aCSPR.makeExplicit())
return aCSPR;
return CSPRep.fromString("default-src 'none'", selfUri);
// the X-Content-Security-Policy syntax requires an allow or default-src
// directive to be present.
if (!aCSPR._directives[SD.DEFAULT_SRC]) {
cspWarn(aCSPR, CSPLocalizer.getStr("allowOrDefaultSrcRequired"));
return CSPRep.fromString("default-src 'none'", selfUri);
}
return aCSPR;
};
/**
@ -690,12 +691,7 @@ CSPRep.fromStringSpecCompliant = function(aStr, self, docRequest, csp) {
} // end directive: loop
// TODO : clean this up using patch in bug 780978
// if makeExplicit fails for any reason, default to default-src 'none'. This
// includes the case where "default-src" is not present.
if (aCSPR.makeExplicit())
return aCSPR;
return CSPRep.fromStringSpecCompliant("default-src 'none'", self);
return aCSPR;
};
CSPRep.prototype = {
@ -763,21 +759,53 @@ CSPRep.prototype = {
if (aURI instanceof Ci.nsIURI && aURI.scheme === "about")
return true;
// make sure the context is valid
// make sure the right directive set is used
let DIRS = this._specCompliant ? CSPRep.SRC_DIRECTIVES_NEW : CSPRep.SRC_DIRECTIVES_OLD;
let contextIsSrcDir = false;
for (var i in DIRS) {
if (DIRS[i] === aContext) {
return this._directives[aContext].permits(aURI);
// for catching calls with invalid contexts (below)
contextIsSrcDir = true;
if (this._directives.hasOwnProperty(aContext)) {
return this._directives[aContext].permits(aURI);
}
//found matching dir, can stop looking
break;
}
}
return false;
// frame-ancestors is a special case; it doesn't fall back to default-src.
if (aContext === DIRS.FRAME_ANCESTORS)
return true;
// All directives that don't fall back to default-src should have an escape
// hatch above (like frame-ancestors).
if (!contextIsSrcDir) {
// if this code runs, there's probably something calling permits() that
// shouldn't be calling permits().
CSPdebug("permits called with invalid load type: " + aContext);
return false;
}
// no directives specifically matched, fall back to default-src.
// (default-src may not be present for CSP 1.0-compliant policies, and
// indicates no relevant directives were present and the load should be
// permitted).
if (this._directives.hasOwnProperty(DIRS.DEFAULT_SRC)) {
return this._directives[DIRS.DEFAULT_SRC].permits(aURI);
}
// no relevant directives present -- this means for CSP 1.0 that the load
// should be permitted (and for the old CSP, to block it).
return this._specCompliant;
},
/**
* Intersects with another CSPRep, deciding the subset policy
* that should be enforced, and returning a new instance.
* This assumes that either both CSPReps are specCompliant or they are both
* not.
* @param aCSPRep
* a CSPRep instance to use as "other" CSP
* @returns
@ -790,12 +818,71 @@ CSPRep.prototype = {
let DIRS = aCSPRep._specCompliant ? CSPRep.SRC_DIRECTIVES_NEW :
CSPRep.SRC_DIRECTIVES_OLD;
// one or more of the two CSPReps may not have any given directive. In
// these cases, we need to pick "all" or "none" based on the type of CSPRep
// (spec compliant or not).
let thisHasDefault = this._directives.hasOwnProperty(DIRS.DEFAULT_SRC),
thatHasDefault = aCSPRep._directives.hasOwnProperty(DIRS.DEFAULT_SRC);
for (var dir in DIRS) {
var dirv = DIRS[dir];
if (this._directives.hasOwnProperty(dirv))
newRep._directives[dirv] = this._directives[dirv].intersectWith(aCSPRep._directives[dirv]);
else
newRep._directives[dirv] = aCSPRep._directives[dirv];
let dirv = DIRS[dir];
let thisHasDir = this._directives.hasOwnProperty(dirv),
thatHasDir = aCSPRep._directives.hasOwnProperty(dirv);
// if both specific src directives are absent, skip this (new policy will
// rely on default-src)
if (!thisHasDir && !thatHasDir) {
continue;
}
// frame-ancestors is a special case; it doesn't fall back to
// default-src, so only add it to newRep if one or both of the policies
// have it.
if (dirv === DIRS.FRAME_ANCESTORS) {
if (thisHasDir && thatHasDir) {
// both have frame-ancestors, intersect them.
newRep._directives[dirv] =
aCSPRep._directives[dirv].intersectWith(this._directives[dirv]);
} else if (thisHasDir || thatHasDir) {
// one or the other has frame-ancestors, copy it.
newRep._directives[dirv] =
( thisHasDir ? this : aCSPRep )._directives[dirv].clone();
}
}
else if (aCSPRep._specCompliant) {
// CSP 1.0 doesn't require default-src, so an intersection only makes
// sense if there is a default-src or both policies have the directive.
if (!thisHasDir && !thisHasDefault) {
// only aCSPRep has a relevant directive
newRep._directives[dirv] = aCSPRep._directives[dirv].clone();
}
else if (!thatHasDir && !thatHasDefault) {
// only "this" has a relevant directive
newRep._directives[dirv] = this._directives[dirv].clone();
}
else {
// both policies have a relevant directive (may be default-src)
var isect1 = thisHasDir ?
this._directives[dirv] :
this._directives[DIRS.DEFAULT_SRC];
var isect2 = thatHasDir ?
aCSPRep._directives[dirv] :
aCSPRep._directives[DIRS.DEFAULT_SRC];
newRep._directives[dirv] = isect1.intersectWith(isect2);
}
}
else {
// pre-1.0 CSP requires a default-src, so we can assume it's here
// (since the parser created one).
var isect1 = thisHasDir ?
this._directives[dirv] :
this._directives[DIRS.DEFAULT_SRC];
var isect2 = thatHasDir ?
aCSPRep._directives[dirv] :
aCSPRep._directives[DIRS.DEFAULT_SRC];
newRep._directives[dirv] = isect1.intersectWith(isect2);
}
}
// REPORT_URI
@ -828,55 +915,6 @@ CSPRep.prototype = {
return newRep;
},
/**
* Copies default source list to each unspecified directive.
* @returns
* true if the makeExplicit succeeds
* false if it fails (for some weird reason)
*/
makeExplicit:
function cspsd_makeExplicit() {
let SD = this._specCompliant ? CSPRep.SRC_DIRECTIVES_NEW : CSPRep.SRC_DIRECTIVES_OLD;
// It's ok for a 1.0 spec compliant policy to not have a default source,
// in this case it should use default-src *
// However, our original CSP implementation required a default src
// or an allow directive.
if (!this._directives[SD.DEFAULT_SRC]) {
if(!this._specCompliant) {
this.warn(CSPLocalizer.getStr("allowOrDefaultSrcRequired"));
return false;
}
// bug 780978 will remove these lines and needs to make sure that
// CSPRep.permits() enforces this logic: prefixed headers default to
// "disallowed" and unprefixed headers default to "allowed" when
// neither specific -src nor default-src directive is provided.
this._directives[SD.DEFAULT_SRC]
= CSPSourceList.fromString("*", this, this._self, true);
this._directives[SD.DEFAULT_SRC]._isImplicit = true;
}
var defaultSrcDir = this._directives[SD.DEFAULT_SRC];
for (var dir in SD) {
var dirv = SD[dir];
if (dirv === SD.DEFAULT_SRC) continue;
if (!this._directives[dirv]) {
// implicit directive, make explicit.
// All but frame-ancestors directive inherit from 'allow' (bug 555068)
if (dirv === SD.FRAME_ANCESTORS)
this._directives[dirv] = CSPSourceList.fromString("*",this);
else
this._directives[dirv] = defaultSrcDir.clone();
this._directives[dirv]._isImplicit = true;
}
}
this._isInitialized = true;
return true;
},
/**
* Returns true if "eval" is enabled through the "eval" keyword.
*/
@ -942,10 +980,6 @@ this.CSPSourceList = function CSPSourceList() {
this._sources = [];
this._permitAllSources = false;
// Set to true when this list is created using "makeExplicit()"
// It's useful to know this when reporting the directive that was violated.
this._isImplicit = false;
// When this is true, the source list contains 'unsafe-inline'.
this._allowUnsafeInline = false;
@ -1175,9 +1209,6 @@ CSPSourceList.prototype = {
newCSPSrcList._sources = isrcs;
}
// if either was explicit, so is this.
newCSPSrcList._isImplicit = this._isImplicit && that._isImplicit;
if ((!newCSPSrcList._CSPRep) && that._CSPRep) {
newCSPSrcList._CSPRep = that._CSPRep;
}

View File

@ -558,10 +558,24 @@ ContentSecurityPolicy.prototype = {
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();
let directive = "unknown directive",
violatedPolicy = "unknown policy";
// The policy might not explicitly declare each source directive (so
// the cspContext may be implicit). If so, we have to report
// violations as appropriate: specific or the default-src directive.
if (this._policy._directives.hasOwnProperty(cspContext)) {
directive = this._policy._directives[cspContext];
violatedPolicy = cspContext + ' ' + directive.toString();
} else if (this._policy._directives.hasOwnProperty("default-src")) {
directive = this._policy._directives["default-src"];
violatedPolicy = "default-src " + directive.toString();
} else {
violatedPolicy = "unknown directive";
CSPdebug('ERROR in blocking content: ' +
'CSP is not sure which part of the policy caused this block');
}
this._asyncReportViolation(aContentLocation, aOriginalUri, violatedPolicy);
} catch(e) {
CSPdebug('---------------- ERROR: ' + e);

View File

@ -372,15 +372,6 @@ test(
// "DEFAULT_SRC directive is missing when specified in fromString"
do_check_has_key(cspr._directives, SD.DEFAULT_SRC);
// ... and check that the other directives were auto-filled with the
// DEFAULT_SRC one.
cspr_allowval = cspr._directives[SD.DEFAULT_SRC];
for(var d in SD) {
//"Missing key " + d
do_check_has_key(cspr._directives, SD[d]);
//"Implicit directive " + d + " has non-allow value."
do_check_eq(cspr._directives[SD[d]].toString(), cspr_allowval.toString());
}
});
@ -394,24 +385,13 @@ test(
// "DEFAULT_SRC directive is missing when specified in fromString"
do_check_has_key(cspr._directives, SD.DEFAULT_SRC);
// check that the other directives were auto-filled with the
// DEFAULT_SRC one.
cspr_default_val = cspr._directives[SD.DEFAULT_SRC];
for (var d in SD) {
do_check_has_key(cspr._directives, SD[d]);
// "Implicit directive " + d + " has non-default-src value."
do_check_eq(cspr._directives[SD[d]].toString(), cspr_default_val.toString());
}
// check that |allow *| and |default-src *| are parsed equivalently and
// result in the same set of explicit policy directives
cspr = CSPRep.fromString("default-src *", URI("http://self.com:80"));
cspr_allow = CSPRep.fromString("allow *", URI("http://self.com:80"));
for (var d in SD) {
do_check_equivalent(cspr._directives[SD[d]],
cspr_allow._directives[SD[d]]);
}
do_check_equivalent(cspr._directives['default-src'],
cspr_allow._directives['default-src']);
});