Bug 663570 - MetaCSP Part 1: CSP parser changes (r=sicking)

This commit is contained in:
Christoph Kerschbaumer 2015-11-14 19:27:59 -08:00
parent 60ea185133
commit f830e615e5
8 changed files with 56 additions and 17 deletions

View File

@ -2615,7 +2615,7 @@ AppendCSPFromHeader(nsIContentSecurityPolicy* csp,
nsCharSeparatedTokenizer tokenizer(aHeaderValue, ',');
while (tokenizer.hasMoreTokens()) {
const nsSubstring& policy = tokenizer.nextToken();
rv = csp->AppendPolicy(policy, aReportOnly);
rv = csp->AppendPolicy(policy, aReportOnly, false);
NS_ENSURE_SUCCESS(rv, rv);
{
MOZ_LOG(gCspPRLog, LogLevel::Debug,
@ -2768,12 +2768,12 @@ nsDocument::InitCSP(nsIChannel* aChannel)
// ----- if the doc is an app and we want a default CSP, apply it.
if (applyAppDefaultCSP) {
csp->AppendPolicy(appDefaultCSP, false);
csp->AppendPolicy(appDefaultCSP, false, false);
}
// ----- if the doc is an app and specifies a CSP in its manifest, apply it.
if (applyAppManifestCSP) {
csp->AppendPolicy(appManifestCSP, false);
csp->AppendPolicy(appManifestCSP, false, false);
}
// ----- if the doc is part of Loop, apply the loop CSP
@ -2783,7 +2783,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
NS_ASSERTION(loopCSP, "Missing loop.CSP preference");
// If the pref has been removed, we continue without setting a CSP
if (loopCSP) {
csp->AppendPolicy(loopCSP, false);
csp->AppendPolicy(loopCSP, false, false);
}
}

View File

@ -21,7 +21,7 @@ interface nsIURI;
typedef unsigned short CSPDirective;
[scriptable, builtinclass, uuid(b9a029c3-9484-4bf7-826d-0c6b545790bc)]
[scriptable, builtinclass, uuid(b3c4c0ae-bd5e-4cad-87e0-8d210dbb3f9f)]
interface nsIContentSecurityPolicy : nsISerializable
{
/**
@ -90,12 +90,17 @@ interface nsIContentSecurityPolicy : nsISerializable
/**
* Parse and install a CSP policy.
* @param aPolicy
* String representation of the policy (e.g., header value)
* String representation of the policy
* (e.g., header value, meta content)
* @param reportOnly
* Should this policy affect content, script and style processing or
* just send reports if it is violated?
* @param deliveredViaMetaTag
* Indicates whether the policy was delivered via the meta tag.
*/
void appendPolicy(in AString policyString, in boolean reportOnly);
void appendPolicy(in AString policyString,
in boolean reportOnly,
in boolean deliveredViaMetaTag);
/*
* Whether this policy allows inline script or style.

View File

@ -32,6 +32,9 @@ ignoringUnknownOption = Ignoring unknown option %1$S
# LOCALIZATION NOTE (ignoringDuplicateSrc):
# %1$S defines the duplicate src
ignoringDuplicateSrc = Ignoring duplicate source %1$S
# LOCALIZATION NOTE (ignoringSrcFromMetaCSP):
# %1$S defines the ignored src
ignoringSrcFromMetaCSP = Ignoring source '%1$S' (Not supported when delivered via meta element).
# LOCALIZATION NOTE (ignoringSrcWithinScriptSrc):
# %1$S is the ignored src
# script-src is a directive name and should not be localized

View File

@ -342,14 +342,17 @@ nsCSPContext::GetReferrerPolicy(uint32_t* outPolicy, bool* outIsSet)
NS_IMETHODIMP
nsCSPContext::AppendPolicy(const nsAString& aPolicyString,
bool aReportOnly)
bool aReportOnly,
bool aDeliveredViaMetaTag)
{
CSPCONTEXTLOG(("nsCSPContext::AppendPolicy: %s",
NS_ConvertUTF16toUTF8(aPolicyString).get()));
// Use the mSelfURI from setRequestContext, see bug 991474
NS_ASSERTION(mSelfURI, "mSelfURI required for AppendPolicy, but not set");
nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(aPolicyString, mSelfURI, aReportOnly, this);
nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(aPolicyString, mSelfURI,
aReportOnly, this,
aDeliveredViaMetaTag);
if (policy) {
mPolicies.AppendElement(policy);
// reset cache since effective policy changes
@ -1353,10 +1356,15 @@ nsCSPContext::Read(nsIObjectInputStream* aStream)
rv = aStream->ReadBoolean(&reportOnly);
NS_ENSURE_SUCCESS(rv, rv);
// @param deliveredViaMetaTag:
// when parsing the CSP policy string initially we already remove directives
// that should not be processed when delivered via the meta tag. Such directives
// will not be present at this point anymore.
nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(policyString,
mSelfURI,
reportOnly,
this);
this,
false);
if (policy) {
mPolicies.AppendElement(policy);
}

View File

@ -122,7 +122,8 @@ nsCSPTokenizer::tokenizeCSPPolicy(const nsAString &aPolicyString,
nsCSPParser::nsCSPParser(cspTokens& aTokens,
nsIURI* aSelfURI,
nsCSPContext* aCSPContext)
nsCSPContext* aCSPContext,
bool aDeliveredViaMetaTag)
: mHasHashOrNonce(false)
, mUnsafeInlineKeywordSrc(nullptr)
, mChildSrc(nullptr)
@ -130,6 +131,7 @@ nsCSPParser::nsCSPParser(cspTokens& aTokens,
, mTokens(aTokens)
, mSelfURI(aSelfURI)
, mCSPContext(aCSPContext)
, mDeliveredViaMetaTag(aDeliveredViaMetaTag)
{
CSPPARSERLOG(("nsCSPParser::nsCSPParser"));
}
@ -991,6 +993,20 @@ nsCSPParser::directiveName()
return nullptr;
}
// CSP delivered via meta tag should ignore the following directives:
// report-uri, frame-ancestors, and sandbox, see:
// http://www.w3.org/TR/CSP11/#delivery-html-meta-element
if (mDeliveredViaMetaTag &&
((CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::REPORT_URI_DIRECTIVE)) ||
(CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE)))) {
// log to the console to indicate that meta CSP is ignoring the directive
const char16_t* params[] = { mCurToken.get() };
logWarningErrorToConsole(nsIScriptError::warningFlag,
"ignoringSrcFromMetaCSP",
params, ArrayLength(params));
return nullptr;
}
// special case handling for upgrade-insecure-requests
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)) {
return new nsUpgradeInsecureDirective(CSP_StringToCSPDirective(mCurToken));
@ -1116,7 +1132,8 @@ nsCSPPolicy*
nsCSPParser::parseContentSecurityPolicy(const nsAString& aPolicyString,
nsIURI *aSelfURI,
bool aReportOnly,
nsCSPContext* aCSPContext)
nsCSPContext* aCSPContext,
bool aDeliveredViaMetaTag)
{
if (CSPPARSERLOGENABLED()) {
CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, policy: %s",
@ -1126,6 +1143,8 @@ nsCSPParser::parseContentSecurityPolicy(const nsAString& aPolicyString,
CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, selfURI: %s", spec.get()));
CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, reportOnly: %s",
(aReportOnly ? "true" : "false")));
CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, deliveredViaMetaTag: %s",
(aDeliveredViaMetaTag ? "true" : "false")));
}
NS_ASSERTION(aSelfURI, "Can not parseContentSecurityPolicy without aSelfURI");
@ -1138,7 +1157,7 @@ nsCSPParser::parseContentSecurityPolicy(const nsAString& aPolicyString,
nsTArray< nsTArray<nsString> > tokens;
nsCSPTokenizer::tokenizeCSPPolicy(aPolicyString, tokens);
nsCSPParser parser(tokens, aSelfURI, aCSPContext);
nsCSPParser parser(tokens, aSelfURI, aCSPContext, aDeliveredViaMetaTag);
// Start the parser to generate a new CSPPolicy using the generated tokens.
nsCSPPolicy* policy = parser.policy();

View File

@ -100,12 +100,15 @@ class nsCSPParser {
static nsCSPPolicy* parseContentSecurityPolicy(const nsAString &aPolicyString,
nsIURI *aSelfURI,
bool aReportOnly,
nsCSPContext* aCSPContext);
nsCSPContext* aCSPContext,
bool aDeliveredViaMetaTag);
private:
nsCSPParser(cspTokens& aTokens,
nsIURI* aSelfURI,
nsCSPContext* aCSPContext);
nsCSPContext* aCSPContext,
bool aDeliveredViaMetaTag);
~nsCSPParser();
@ -246,6 +249,7 @@ class nsCSPParser {
nsIURI* mSelfURI;
nsCSPPolicy* mPolicy;
nsCSPContext* mCSPContext; // used for console logging
bool mDeliveredViaMetaTag;
};
#endif /* nsCSPParser_h___ */

View File

@ -117,7 +117,7 @@ nsresult runTest(uint32_t aExpectedPolicyCount, // this should be 0 for policies
// append a policy
nsString policyStr;
policyStr.AssignASCII(aPolicy);
rv = csp->AppendPolicy(policyStr, false);
rv = csp->AppendPolicy(policyStr, false, false);
NS_ENSURE_SUCCESS(rv, rv);
// when executing fuzzy tests we do not care about the actual output

View File

@ -84,7 +84,7 @@ function makeTest(id, expectedJSON, useReportOnlyPolicy, callback) {
// Load up the policy
// set as report-only if that's the case
csp.appendPolicy(policy, useReportOnlyPolicy);
csp.appendPolicy(policy, useReportOnlyPolicy, false);
// prime the report server
var handler = makeReportHandler("/test" + id, "Test " + id, expectedJSON);