Bug 783049 - CSP : use existing/old parser for X-Content-Security-Policy header, new/CSP 1.0 spec compliant parser for Content-Security-Policy header - Part 2 (r=bz)

This commit is contained in:
Ian Melven
2013-01-09 10:57:04 -08:00
parent f389255c0f
commit 4788e23f28
4 changed files with 91 additions and 15 deletions

View File

@@ -2288,18 +2288,51 @@ nsDocument::InitCSP(nsIChannel* aChannel)
} }
nsAutoCString tCspHeaderValue, tCspROHeaderValue; nsAutoCString tCspHeaderValue, tCspROHeaderValue;
nsAutoCString tCspOldHeaderValue, tCspOldROHeaderValue;
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (httpChannel) { if (httpChannel) {
httpChannel->GetResponseHeader( httpChannel->GetResponseHeader(
NS_LITERAL_CSTRING("x-content-security-policy"), NS_LITERAL_CSTRING("x-content-security-policy"),
tCspHeaderValue); tCspOldHeaderValue);
httpChannel->GetResponseHeader( httpChannel->GetResponseHeader(
NS_LITERAL_CSTRING("x-content-security-policy-report-only"), NS_LITERAL_CSTRING("x-content-security-policy-report-only"),
tCspOldROHeaderValue);
httpChannel->GetResponseHeader(
NS_LITERAL_CSTRING("content-security-policy"),
tCspHeaderValue);
httpChannel->GetResponseHeader(
NS_LITERAL_CSTRING("content-security-policy-report-only"),
tCspROHeaderValue); tCspROHeaderValue);
} }
NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue); NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue);
NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue); NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue);
NS_ConvertASCIItoUTF16 cspOldHeaderValue(tCspOldHeaderValue);
NS_ConvertASCIItoUTF16 cspOldROHeaderValue(tCspOldROHeaderValue);
// Until we want to turn on our CSP 1.0 spec compliant support
// only use the 1.0 spec compliant headers if a pref to do so
// is set (this lets us land CSP 1.0 support with tests without
// having to turn it on before it's ready). When we turn on
// CSP 1.0 in the release, we should remove this pref check.
// This pref will never be set by default, it should only
// be created/set by the CSP tests.
if (!cspHeaderValue.IsEmpty() || !cspROHeaderValue.IsEmpty()) {
bool specCompliantEnabled =
Preferences::GetBool("security.csp.speccompliant");
// If spec compliant pref isn't set, pretend we never got
// these headers.
if (!specCompliantEnabled) {
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
("Got spec compliant CSP headers but pref was not set"));
cspHeaderValue.Truncate();
cspROHeaderValue.Truncate();
}
}
// ----- Figure out if we need to apply an app default CSP // ----- Figure out if we need to apply an app default CSP
bool applyAppDefaultCSP = false; bool applyAppDefaultCSP = false;
@@ -2333,10 +2366,12 @@ nsDocument::InitCSP(nsIChannel* aChannel)
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Failed to get app status from principal")); PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Failed to get app status from principal"));
#endif #endif
// If there's no CSP to apply go ahead and return early // If there's no CSP to apply, go ahead and return early
if (!applyAppDefaultCSP && if (!applyAppDefaultCSP &&
cspHeaderValue.IsEmpty() && cspHeaderValue.IsEmpty() &&
cspROHeaderValue.IsEmpty()) { cspROHeaderValue.IsEmpty() &&
cspOldHeaderValue.IsEmpty() &&
cspOldROHeaderValue.IsEmpty()) {
#ifdef PR_LOGGING #ifdef PR_LOGGING
nsCOMPtr<nsIURI> chanURI; nsCOMPtr<nsIURI> chanURI;
aChannel->GetURI(getter_AddRefs(chanURI)); aChannel->GetURI(getter_AddRefs(chanURI));
@@ -2383,34 +2418,63 @@ nsDocument::InitCSP(nsIChannel* aChannel)
} }
if (appCSP) if (appCSP)
csp->RefinePolicy(appCSP, chanURI); csp->RefinePolicy(appCSP, chanURI, true);
}
// While we are supporting both CSP 1.0 and the x- headers, the 1.0 headers
// take priority. If any spec-compliant headers are present, the x- headers
// are ignored, and the spec compliant parser is used.
bool cspSpecCompliant = (!cspHeaderValue.IsEmpty() || !cspROHeaderValue.IsEmpty());
// If the old header is present, warn that it will be deprecated.
if (!cspOldHeaderValue.IsEmpty() || !cspOldROHeaderValue.IsEmpty()) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
"CSP", this,
nsContentUtils::eDOM_PROPERTIES,
"OldCSPHeaderDeprecated");
// Also, if the new headers AND the old headers were present, warn
// that the old headers will be ignored.
if (cspSpecCompliant) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
"CSP", this,
nsContentUtils::eDOM_PROPERTIES,
"BothCSPHeadersPresent");
}
} }
// ----- if there's a full-strength CSP header, apply it. // ----- if there's a full-strength CSP header, apply it.
if (!cspHeaderValue.IsEmpty()) { bool applyCSPFromHeader =
(( cspSpecCompliant && !cspHeaderValue.IsEmpty()) ||
(!cspSpecCompliant && !cspOldHeaderValue.IsEmpty()));
if (applyCSPFromHeader) {
// Need to tokenize the header value since multiple headers could be // Need to tokenize the header value since multiple headers could be
// concatenated into one comma-separated list of policies. // concatenated into one comma-separated list of policies.
// See RFC2616 section 4.2 (last paragraph) // See RFC2616 section 4.2 (last paragraph)
nsCharSeparatedTokenizer tokenizer(cspHeaderValue, ','); nsCharSeparatedTokenizer tokenizer(cspSpecCompliant ?
cspHeaderValue :
cspOldHeaderValue, ',');
while (tokenizer.hasMoreTokens()) { while (tokenizer.hasMoreTokens()) {
const nsSubstring& policy = tokenizer.nextToken(); const nsSubstring& policy = tokenizer.nextToken();
csp->RefinePolicy(policy, chanURI); csp->RefinePolicy(policy, chanURI, cspSpecCompliant);
#ifdef PR_LOGGING #ifdef PR_LOGGING
{ {
PR_LOG(gCspPRLog, PR_LOG_DEBUG, PR_LOG(gCspPRLog, PR_LOG_DEBUG,
("CSP refined with policy: \"%s\"", ("CSP refined with policy: \"%s\"",
NS_ConvertUTF16toUTF8(policy).get())); NS_ConvertUTF16toUTF8(policy).get()));
} }
#endif #endif
} }
} }
// ----- if there's a report-only CSP header, apply it // ----- if there's a report-only CSP header, apply it
if (!cspROHeaderValue.IsEmpty()) { if (( cspSpecCompliant && !cspROHeaderValue.IsEmpty()) ||
(!cspSpecCompliant && !cspOldROHeaderValue.IsEmpty())) {
// post a warning and skip report-only CSP when both read only and regular // post a warning and skip report-only CSP when both read only and regular
// CSP policies are present since CSP only allows one policy and it can't // CSP policies are present since CSP only allows one policy and it can't
// be partially report-only. // be partially report-only.
if (applyAppDefaultCSP || !cspHeaderValue.IsEmpty()) { if (applyAppDefaultCSP || applyCSPFromHeader) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
"CSP", this, "CSP", this,
nsContentUtils::eDOM_PROPERTIES, nsContentUtils::eDOM_PROPERTIES,
@@ -2427,10 +2491,12 @@ nsDocument::InitCSP(nsIChannel* aChannel)
// Need to tokenize the header value since multiple headers could be // Need to tokenize the header value since multiple headers could be
// concatenated into one comma-separated list of policies. // concatenated into one comma-separated list of policies.
// See RFC2616 section 4.2 (last paragraph) // See RFC2616 section 4.2 (last paragraph)
nsCharSeparatedTokenizer tokenizer(cspROHeaderValue, ','); nsCharSeparatedTokenizer tokenizer(cspSpecCompliant ?
cspROHeaderValue :
cspOldROHeaderValue, ',');
while (tokenizer.hasMoreTokens()) { while (tokenizer.hasMoreTokens()) {
const nsSubstring& policy = tokenizer.nextToken(); const nsSubstring& policy = tokenizer.nextToken();
csp->RefinePolicy(policy, chanURI); csp->RefinePolicy(policy, chanURI, cspSpecCompliant);
#ifdef PR_LOGGING #ifdef PR_LOGGING
{ {
PR_LOG(gCspPRLog, PR_LOG_DEBUG, PR_LOG(gCspPRLog, PR_LOG_DEBUG,

View File

@@ -1139,8 +1139,10 @@ GK_ATOM(withParam, "with-param")
GK_ATOM(wizard, "wizard") GK_ATOM(wizard, "wizard")
GK_ATOM(wrap, "wrap") GK_ATOM(wrap, "wrap")
GK_ATOM(headerDNSPrefetchControl,"x-dns-prefetch-control") GK_ATOM(headerDNSPrefetchControl,"x-dns-prefetch-control")
GK_ATOM(headerCSP, "x-content-security-policy") GK_ATOM(headerOldCSP, "x-content-security-policy")
GK_ATOM(headerCSPReportOnly, "x-content-security-policy-report-only") GK_ATOM(headerOldCSPReportOnly, "x-content-security-policy-report-only")
GK_ATOM(headerCSP, "content-security-policy")
GK_ATOM(headerCSPReportOnly, "content-security-policy-report-only")
GK_ATOM(headerXFO, "x-frame-options") GK_ATOM(headerXFO, "x-frame-options")
GK_ATOM(x_western, "x-western") GK_ATOM(x_western, "x-western")
GK_ATOM(xml, "xml") GK_ATOM(xml, "xml")

View File

@@ -120,3 +120,7 @@ PluginHangUIWaitButton=Continue
PluginHangUIStopButton=Stop plugin PluginHangUIStopButton=Stop plugin
# LOCALIZATION NOTE: Do not translate "mozHidden", "mozVisibilityState", "hidden", or "visibilityState" # LOCALIZATION NOTE: Do not translate "mozHidden", "mozVisibilityState", "hidden", or "visibilityState"
PrefixedVisibilityApiWarning='mozHidden' and 'mozVisibilityState' are deprecated. Please use the unprefixed 'hidden' and 'visibilityState' instead. PrefixedVisibilityApiWarning='mozHidden' and 'mozVisibilityState' are deprecated. Please use the unprefixed 'hidden' and 'visibilityState' instead.
# LOCALIZATION NOTE: Do not translate "X-Content-Security-Policy", "X-Content-Security-Policy-Report-Only", "Content-Security-Policy" or "Content-Security-Policy-Report-Only"
OldCSPHeaderDeprecated=The X-Content-Security-Policy and X-Content-Security-Report-Only headers will be deprecated in the future. Please use the Content-Security-Policy and Content-Security-Report-Only headers with CSP spec compliant syntax instead.
# LOCALIZATION NOTE: Do not translate "X-Content-Security-Policy" or "Content-Security-Policy"
BothCSPHeadersPresent=This site specified both an X-Content-Security-Policy/Report-Only header and a Content-Security-Policy/Report-Only header. The X-ContentSecurityPolicy/ReportOnly header(s) will be ignored.

View File

@@ -636,6 +636,10 @@ nsViewSourceChannel::GetResponseHeader(const nsACString & aHeader,
nsCaseInsensitiveCStringComparator()) && nsCaseInsensitiveCStringComparator()) &&
!aHeader.Equals(NS_LITERAL_CSTRING("X-Content-Security-Policy-Report-Only"), !aHeader.Equals(NS_LITERAL_CSTRING("X-Content-Security-Policy-Report-Only"),
nsCaseInsensitiveCStringComparator()) && nsCaseInsensitiveCStringComparator()) &&
!aHeader.Equals(NS_LITERAL_CSTRING("Content-Security-Policy"),
nsCaseInsensitiveCStringComparator()) &&
!aHeader.Equals(NS_LITERAL_CSTRING("Content-Security-Policy-Report-Only"),
nsCaseInsensitiveCStringComparator()) &&
!aHeader.Equals(NS_LITERAL_CSTRING("X-Frame-Options"), !aHeader.Equals(NS_LITERAL_CSTRING("X-Frame-Options"),
nsCaseInsensitiveCStringComparator())) { nsCaseInsensitiveCStringComparator())) {
aValue.Truncate(); aValue.Truncate();