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
Родитель 21cfd6687a
Коммит 9b5cf4aea2
4 изменённых файлов: 91 добавлений и 15 удалений

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

@ -2288,18 +2288,51 @@ nsDocument::InitCSP(nsIChannel* aChannel)
}
nsAutoCString tCspHeaderValue, tCspROHeaderValue;
nsAutoCString tCspOldHeaderValue, tCspOldROHeaderValue;
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (httpChannel) {
httpChannel->GetResponseHeader(
NS_LITERAL_CSTRING("x-content-security-policy"),
tCspHeaderValue);
tCspOldHeaderValue);
httpChannel->GetResponseHeader(
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);
}
NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue);
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
bool applyAppDefaultCSP = false;
@ -2333,10 +2366,12 @@ nsDocument::InitCSP(nsIChannel* aChannel)
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Failed to get app status from principal"));
#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 &&
cspHeaderValue.IsEmpty() &&
cspROHeaderValue.IsEmpty()) {
cspROHeaderValue.IsEmpty() &&
cspOldHeaderValue.IsEmpty() &&
cspOldROHeaderValue.IsEmpty()) {
#ifdef PR_LOGGING
nsCOMPtr<nsIURI> chanURI;
aChannel->GetURI(getter_AddRefs(chanURI));
@ -2383,34 +2418,63 @@ nsDocument::InitCSP(nsIChannel* aChannel)
}
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 (!cspHeaderValue.IsEmpty()) {
bool applyCSPFromHeader =
(( cspSpecCompliant && !cspHeaderValue.IsEmpty()) ||
(!cspSpecCompliant && !cspOldHeaderValue.IsEmpty()));
if (applyCSPFromHeader) {
// Need to tokenize the header value since multiple headers could be
// concatenated into one comma-separated list of policies.
// See RFC2616 section 4.2 (last paragraph)
nsCharSeparatedTokenizer tokenizer(cspHeaderValue, ',');
nsCharSeparatedTokenizer tokenizer(cspSpecCompliant ?
cspHeaderValue :
cspOldHeaderValue, ',');
while (tokenizer.hasMoreTokens()) {
const nsSubstring& policy = tokenizer.nextToken();
csp->RefinePolicy(policy, chanURI);
csp->RefinePolicy(policy, chanURI, cspSpecCompliant);
#ifdef PR_LOGGING
{
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
("CSP refined with policy: \"%s\"",
NS_ConvertUTF16toUTF8(policy).get()));
("CSP refined with policy: \"%s\"",
NS_ConvertUTF16toUTF8(policy).get()));
}
#endif
}
}
// ----- 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
// CSP policies are present since CSP only allows one policy and it can't
// be partially report-only.
if (applyAppDefaultCSP || !cspHeaderValue.IsEmpty()) {
if (applyAppDefaultCSP || applyCSPFromHeader) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
"CSP", this,
nsContentUtils::eDOM_PROPERTIES,
@ -2427,10 +2491,12 @@ nsDocument::InitCSP(nsIChannel* aChannel)
// Need to tokenize the header value since multiple headers could be
// concatenated into one comma-separated list of policies.
// See RFC2616 section 4.2 (last paragraph)
nsCharSeparatedTokenizer tokenizer(cspROHeaderValue, ',');
nsCharSeparatedTokenizer tokenizer(cspSpecCompliant ?
cspROHeaderValue :
cspOldROHeaderValue, ',');
while (tokenizer.hasMoreTokens()) {
const nsSubstring& policy = tokenizer.nextToken();
csp->RefinePolicy(policy, chanURI);
csp->RefinePolicy(policy, chanURI, cspSpecCompliant);
#ifdef PR_LOGGING
{
PR_LOG(gCspPRLog, PR_LOG_DEBUG,

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

@ -1139,8 +1139,10 @@ GK_ATOM(withParam, "with-param")
GK_ATOM(wizard, "wizard")
GK_ATOM(wrap, "wrap")
GK_ATOM(headerDNSPrefetchControl,"x-dns-prefetch-control")
GK_ATOM(headerCSP, "x-content-security-policy")
GK_ATOM(headerCSPReportOnly, "x-content-security-policy-report-only")
GK_ATOM(headerOldCSP, "x-content-security-policy")
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(x_western, "x-western")
GK_ATOM(xml, "xml")

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

@ -120,3 +120,7 @@ PluginHangUIWaitButton=Continue
PluginHangUIStopButton=Stop plugin
# LOCALIZATION NOTE: Do not translate "mozHidden", "mozVisibilityState", "hidden", or "visibilityState"
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.

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

@ -636,6 +636,10 @@ nsViewSourceChannel::GetResponseHeader(const nsACString & aHeader,
nsCaseInsensitiveCStringComparator()) &&
!aHeader.Equals(NS_LITERAL_CSTRING("X-Content-Security-Policy-Report-Only"),
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"),
nsCaseInsensitiveCStringComparator())) {
aValue.Truncate();