Bug 965273 - CSP: Fix serialization and deserialization and add support for the {} characters on the host name. r=sstamm

This commit is contained in:
Antonio M. Amaya 2014-01-30 22:22:21 +01:00
Родитель 409cb7fe8e
Коммит fe9ff58e54
3 изменённых файлов: 73 добавлений и 25 удалений

Просмотреть файл

@ -45,7 +45,16 @@ const R_GETSCHEME = new RegExp ("^" + R_SCHEME.source + "(?=\\:)", 'i');
const R_SCHEMESRC = new RegExp ("^" + R_SCHEME.source + "\\:$", 'i');
// host-char = ALPHA / DIGIT / "-"
const R_HOSTCHAR = new RegExp ("[a-zA-Z0-9\\-]", 'i');
// For the app: protocol, we need to add {} to the valid character set
const HOSTCHAR = "{}a-zA-Z0-9\\-";
const R_HOSTCHAR = new RegExp ("[" + HOSTCHAR + "]", 'i');
// Complementary character set of HOSTCHAR (characters that can't appear)
const R_COMP_HCHAR = new RegExp ("[^" + HOSTCHAR + "]", "i");
// Invalid character set for host strings (which can include dots and star)
const R_INV_HCHAR = new RegExp ("[^" + HOSTCHAR + "\\.\\*]", 'i');
// host = "*" / [ "*." ] 1*host-char *( "." 1*host-char )
const R_HOST = new RegExp ("\\*|(((\\*\\.)?" + R_HOSTCHAR.source +
@ -284,10 +293,14 @@ CSPRep.ALLOW_DIRECTIVE = "allow";
* while the policy-uri is asynchronously fetched
* @param csp (optional)
* the CSP object to update once the policy has been fetched
* @param enforceSelfChecks (optional)
* if present, and "true", will check to be sure "self" has the
* appropriate values to inherit when they are omitted from the source.
* @returns
* an instance of CSPRep
*/
CSPRep.fromString = function(aStr, self, reportOnly, docRequest, csp) {
CSPRep.fromString = function(aStr, self, reportOnly, docRequest, csp,
enforceSelfChecks) {
var SD = CSPRep.SRC_DIRECTIVES_OLD;
var UD = CSPRep.URI_DIRECTIVES;
var aCSPR = new CSPRep();
@ -361,7 +374,8 @@ CSPRep.fromString = function(aStr, self, reportOnly, docRequest, csp) {
CSPdebug("Skipping duplicate directive: \"" + dir + "\"");
continue directive;
}
var dv = CSPSourceList.fromString(dirvalue, aCSPR, selfUri, true);
var dv = CSPSourceList.fromString(dirvalue, aCSPR, selfUri,
enforceSelfChecks);
if (dv) {
aCSPR._directives[SD.DEFAULT_SRC] = dv;
continue directive;
@ -372,7 +386,8 @@ CSPRep.fromString = function(aStr, self, reportOnly, docRequest, csp) {
for each(var sdi in SD) {
if (dirname === sdi) {
// process dirs, and enforce that 'self' is defined.
var dv = CSPSourceList.fromString(dirvalue, aCSPR, selfUri, true);
var dv = CSPSourceList.fromString(dirvalue, aCSPR, selfUri,
enforceSelfChecks);
if (dv) {
aCSPR._directives[sdi] = dv;
continue directive;
@ -526,12 +541,16 @@ CSPRep.fromString = function(aStr, self, reportOnly, docRequest, csp) {
* while the policy-uri is asynchronously fetched
* @param csp (optional)
* the CSP object to update once the policy has been fetched
* @param enforceSelfChecks (optional)
* if present, and "true", will check to be sure "self" has the
* appropriate values to inherit when they are omitted from the source.
* @returns
* an instance of CSPRep
*/
// When we deprecate our original CSP implementation, we rename this to
// CSPRep.fromString and remove the existing CSPRep.fromString above.
CSPRep.fromStringSpecCompliant = function(aStr, self, reportOnly, docRequest, csp) {
CSPRep.fromStringSpecCompliant = function(aStr, self, reportOnly, docRequest, csp,
enforceSelfChecks) {
var SD = CSPRep.SRC_DIRECTIVES_NEW;
var UD = CSPRep.URI_DIRECTIVES;
var aCSPR = new CSPRep(true);
@ -607,7 +626,8 @@ CSPRep.fromStringSpecCompliant = function(aStr, self, reportOnly, docRequest, cs
for each(var sdi in SD) {
if (dirname === sdi) {
// process dirs, and enforce that 'self' is defined.
var dv = CSPSourceList.fromString(dirvalue, aCSPR, self, true);
var dv = CSPSourceList.fromString(dirvalue, aCSPR, self,
enforceSelfChecks);
if (dv) {
// Check for unsafe-inline in style-src
if (sdi === "style-src" && dv._allowUnsafeInline) {
@ -1321,6 +1341,18 @@ CSPSource.fromString = function(aStr, aCSPRep, self, enforceSelfChecks) {
self = CSPSource.create(self, aCSPRep, undefined, false);
}
// check for 'unsafe-inline' (case insensitive)
if (aStr.toLowerCase() === "'unsafe-inline'"){
sObj._allowUnsafeInline = true;
return sObj;
}
// check for 'unsafe-eval' (case insensitive)
if (aStr.toLowerCase() === "'unsafe-eval'"){
sObj._allowUnsafeEval = true;
return sObj;
}
// Check for scheme-source match - this only matches if the source
// string is just a scheme with no host.
if (R_SCHEMESRC.test(aStr)) {
@ -1409,18 +1441,6 @@ CSPSource.fromString = function(aStr, aCSPRep, self, enforceSelfChecks) {
return sObj;
}
// check for 'unsafe-inline' (case insensitive)
if (aStr.toLowerCase() === "'unsafe-inline'"){
sObj._allowUnsafeInline = true;
return sObj;
}
// check for 'unsafe-eval' (case insensitive)
if (aStr.toLowerCase() === "'unsafe-eval'"){
sObj._allowUnsafeEval = true;
return sObj;
}
cspError(aCSPRep, CSPLocalizer.getFormatStr("couldntParseInvalidSource",
[aStr]));
return null;
@ -1490,10 +1510,10 @@ CSPSource.prototype = {
return this._self.toString();
if (this._allowUnsafeInline)
return "unsafe-inline";
return "'unsafe-inline'";
if (this._allowUnsafeEval)
return "unsafe-eval";
return "'unsafe-eval'";
var s = "";
if (this.scheme)
@ -1607,7 +1627,7 @@ CSPHost.fromString = function(aStr) {
if (!aStr) return null;
// host string must be LDH with dots and stars.
var invalidChar = aStr.match(/[^a-zA-Z0-9\-\.\*]/);
var invalidChar = aStr.match(R_INV_HCHAR);
if (invalidChar) {
CSPdebug("Invalid character '" + invalidChar + "' in host " + aStr);
return null;
@ -1628,7 +1648,7 @@ CSPHost.fromString = function(aStr) {
return null;
}
}
else if (seg.match(/[^a-zA-Z0-9\-]/)) {
else if (seg.match(R_COMP_HCHAR)) {
// Non-wildcard segment must be LDH string
CSPdebug("Invalid segment '" + seg + "' in host value");
return null;

Просмотреть файл

@ -411,6 +411,18 @@ ContentSecurityPolicy.prototype = {
*/
appendPolicy:
function csp_appendPolicy(aPolicy, selfURI, aReportOnly, aSpecCompliant) {
return this._appendPolicyInternal(aPolicy, selfURI, aReportOnly,
aSpecCompliant, true);
},
/**
* Adds a new policy to our list of policies for this CSP context.
* Only to be called from this module (not exported)
* @returns the count of policies.
*/
_appendPolicyInternal:
function csp_appendPolicy(aPolicy, selfURI, aReportOnly, aSpecCompliant,
aEnforceSelfChecks) {
#ifndef MOZ_B2G
CSPdebug("APPENDING POLICY: " + aPolicy);
CSPdebug(" SELF: " + (selfURI ? selfURI.asciiSpec : " null"));
@ -443,13 +455,15 @@ ContentSecurityPolicy.prototype = {
selfURI,
aReportOnly,
this._weakDocRequest.get(),
this);
this,
aEnforceSelfChecks);
} else {
newpolicy = CSPRep.fromString(aPolicy,
selfURI,
aReportOnly,
this._weakDocRequest.get(),
this);
this,
aEnforceSelfChecks);
}
newpolicy._specCompliant = !!aSpecCompliant;
@ -950,7 +964,8 @@ ContentSecurityPolicy.prototype = {
let specCompliant = aStream.readBoolean();
// don't need self info because when the policy is turned back into a
// string, 'self' is replaced with the explicit source expression.
this.appendPolicy(polStr, null, reportOnly, specCompliant);
this._appendPolicyInternal(polStr, null, reportOnly, specCompliant,
false);
}
// NOTE: the document instance that's deserializing this object (via its

Просмотреть файл

@ -114,8 +114,12 @@ test(
h = CSPHost.fromString("foo-bar.com");
do_check_neq(null, h); // "dashes in hosts should work"
h = CSPHost.fromString("foo!bar.com");
do_check_eq(null, h); // "special chars in hosts should fail"
h = CSPHost.fromString("{app-url-is-uid}");
do_check_neq(null, h); // "Packaged apps URLs failed"
});
test(
@ -177,6 +181,9 @@ test(
//Port parsing should work for all schemes
do_check_neq(null, CSPSource.create("data:"));
do_check_neq(null, CSPSource.create("javascript:"));
//"app:// URLs should work, including the {} characters.");
do_check_neq(null, CSPSource.fromString("{app-host-is-uid}", undefined, "app://{app-host-is-uid}"));
});
test(
@ -218,6 +225,12 @@ test(
//"nothing else should be allowed"
do_check_false(src.permits("https://foobar.com"));
src = CSPSource.create("{app-host-is-uid}", undefined, "app://{app-host-is-uid}");
//"src should inherit and require 'app' scheme"
do_check_false(src.permits("https://{app-host-is-uid}"));
//"src should inherit scheme 'app'"
do_check_true(src.permits("app://{app-host-is-uid}"));
});
///////////////////// Test the source list //////////////////////