Bug 1026520 - CSP: Inline report sending into allows - callsite updates (r=dveditz)

This commit is contained in:
Christoph Kerschbaumer 2015-09-17 22:34:34 -07:00
parent 88205c7780
commit 6c324f760e
4 changed files with 51 additions and 235 deletions

View File

@ -436,99 +436,21 @@ CSPAllowsInlineScript(nsIScriptElement *aElement, nsIDocument *aDocument)
return true;
}
// An inline script can be allowed because all inline scripts are allowed,
// or else because it is whitelisted by a nonce-source or hash-source. This
// is a logical OR between whitelisting methods, so the allowInlineScript
// outparam can be reused for each check as long as we stop checking as soon
// as it is set to true. This also optimizes performance by avoiding the
// overhead of unnecessary checks.
bool allowInlineScript = true;
nsAutoTArray<unsigned short, 3> violations;
bool reportInlineViolation = false;
rv = csp->GetAllowsInlineScript(&reportInlineViolation, &allowInlineScript);
NS_ENSURE_SUCCESS(rv, false);
if (reportInlineViolation) {
violations.AppendElement(static_cast<unsigned short>(
nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT));
}
// query the nonce
nsCOMPtr<nsIContent> scriptContent = do_QueryInterface(aElement);
nsAutoString nonce;
if (!allowInlineScript) {
nsCOMPtr<nsIContent> scriptContent = do_QueryInterface(aElement);
bool foundNonce = scriptContent->GetAttr(kNameSpaceID_None,
nsGkAtoms::nonce, nonce);
if (foundNonce) {
bool reportNonceViolation;
rv = csp->GetAllowsNonce(nonce, nsIContentPolicy::TYPE_SCRIPT,
&reportNonceViolation, &allowInlineScript);
NS_ENSURE_SUCCESS(rv, false);
if (reportNonceViolation) {
violations.AppendElement(static_cast<unsigned short>(
nsIContentSecurityPolicy::VIOLATION_TYPE_NONCE_SCRIPT));
}
}
}
scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
if (!allowInlineScript) {
bool reportHashViolation;
nsAutoString scriptText;
aElement->GetScriptText(scriptText);
rv = csp->GetAllowsHash(scriptText, nsIContentPolicy::TYPE_SCRIPT,
&reportHashViolation, &allowInlineScript);
NS_ENSURE_SUCCESS(rv, false);
if (reportHashViolation) {
violations.AppendElement(static_cast<unsigned short>(
nsIContentSecurityPolicy::VIOLATION_TYPE_HASH_SCRIPT));
}
}
// query the scripttext
nsAutoString scriptText;
aElement->GetScriptText(scriptText);
// What violation(s) should be reported?
//
// 1. If the script tag has a nonce attribute, and the nonce does not match
// the policy, report VIOLATION_TYPE_NONCE_SCRIPT.
// 2. If the policy has at least one hash-source, and the hashed contents of
// the script tag did not match any of them, report VIOLATION_TYPE_HASH_SCRIPT
// 3. Otherwise, report VIOLATION_TYPE_INLINE_SCRIPT if appropriate.
//
// 1 and 2 may occur together, 3 should only occur by itself. Naturally,
// every VIOLATION_TYPE_NONCE_SCRIPT and VIOLATION_TYPE_HASH_SCRIPT are also
// VIOLATION_TYPE_INLINE_SCRIPT, but reporting the
// VIOLATION_TYPE_INLINE_SCRIPT is redundant and does not help the developer.
if (!violations.IsEmpty()) {
MOZ_ASSERT(violations[0] == nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT,
"How did we get any violations without an initial inline script violation?");
// gather information to log with violation report
nsIURI* uri = aDocument->GetDocumentURI();
nsAutoCString asciiSpec;
uri->GetAsciiSpec(asciiSpec);
nsAutoString scriptText;
aElement->GetScriptText(scriptText);
nsAutoString scriptSample(scriptText);
// cap the length of the script sample at 40 chars
if (scriptSample.Length() > 40) {
scriptSample.Truncate(40);
scriptSample.AppendLiteral("...");
}
for (uint32_t i = 0; i < violations.Length(); i++) {
// Skip reporting the redundant inline script violation if there are
// other (nonce and/or hash violations) as well.
if (i > 0 || violations.Length() == 1) {
csp->LogViolationDetails(violations[i], NS_ConvertUTF8toUTF16(asciiSpec),
scriptSample, aElement->GetScriptLineNumber(),
nonce, scriptText);
}
}
}
if (!allowInlineScript) {
NS_ASSERTION(!violations.IsEmpty(),
"CSP blocked inline script but is not reporting a violation");
return false;
}
return true;
bool allowInlineScript = false;
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
nonce, scriptText,
aElement->GetScriptLineNumber(),
&allowInlineScript);
return allowInlineScript;
}
bool

View File

@ -722,42 +722,37 @@ EventListenerManager::SetEventHandler(nsIAtom* aName,
return NS_ERROR_DOM_SECURITY_ERR;
}
// Perform CSP check
nsCOMPtr<nsIContentSecurityPolicy> csp;
rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
NS_ENSURE_SUCCESS(rv, rv);
if (csp) {
bool inlineOK = true;
bool reportViolations = false;
rv = csp->GetAllowsInlineScript(&reportViolations, &inlineOK);
// let's generate a script sample and pass it as aContent,
// it will not match the hash, but allows us to pass
// the script sample in aCOntent.
nsAutoString scriptSample, attr, tagName(NS_LITERAL_STRING("UNKNOWN"));
aName->ToString(attr);
nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mTarget));
if (domNode) {
domNode->GetNodeName(tagName);
}
// build a "script sample" based on what we know about this element
scriptSample.Assign(attr);
scriptSample.AppendLiteral(" attribute on ");
scriptSample.Append(tagName);
scriptSample.AppendLiteral(" element");
bool allowsInlineScript = true;
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
EmptyString(), // aNonce
scriptSample,
0, // aLineNumber
&allowsInlineScript);
NS_ENSURE_SUCCESS(rv, rv);
if (reportViolations) {
// gather information to log with violation report
nsIURI* uri = doc->GetDocumentURI();
nsAutoCString asciiSpec;
if (uri)
uri->GetAsciiSpec(asciiSpec);
nsAutoString scriptSample, attr, tagName(NS_LITERAL_STRING("UNKNOWN"));
aName->ToString(attr);
nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mTarget));
if (domNode)
domNode->GetNodeName(tagName);
// build a "script sample" based on what we know about this element
scriptSample.Assign(attr);
scriptSample.AppendLiteral(" attribute on ");
scriptSample.Append(tagName);
scriptSample.AppendLiteral(" element");
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT,
NS_ConvertUTF8toUTF16(asciiSpec),
scriptSample,
0,
EmptyString(),
EmptyString());
}
// return early if CSP wants us to block inline scripts
if (!inlineOK) {
if (!allowsInlineScript) {
return NS_OK;
}
}

View File

@ -178,27 +178,15 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
rv = principal->GetCsp(getter_AddRefs(csp));
NS_ENSURE_SUCCESS(rv, rv);
if (csp) {
bool allowsInline = true;
bool reportViolations = false;
rv = csp->GetAllowsInlineScript(&reportViolations, &allowsInline);
NS_ENSURE_SUCCESS(rv, rv);
if (reportViolations) {
// gather information to log with violation report
nsCOMPtr<nsIURI> uri;
principal->GetURI(getter_AddRefs(uri));
nsAutoCString asciiSpec;
uri->GetAsciiSpec(asciiSpec);
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT,
NS_ConvertUTF8toUTF16(asciiSpec),
NS_ConvertUTF8toUTF16(mURL),
0,
EmptyString(),
EmptyString());
}
bool allowsInlineScript = true;
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
EmptyString(), // aNonce
EmptyString(), // aContent
0, // aLineNumber
&allowsInlineScript);
//return early if inline scripts are not allowed
if (!allowsInline) {
if (!allowsInlineScript) {
return NS_ERROR_DOM_RETVAL_UNDEFINED;
}
}

View File

@ -679,106 +679,17 @@ nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent,
return true;
}
// An inline style can be allowed because all inline styles are allowed,
// or else because it is whitelisted by a nonce-source or hash-source. This
// is a logical OR between whitelisting methods, so the allowInlineStyle
// outparam can be reused for each check as long as we stop checking as soon
// as it is set to true. This also optimizes performance by avoiding the
// overhead of unnecessary checks.
bool allowInlineStyle = true;
nsAutoTArray<unsigned short, 3> violations;
bool reportInlineViolation;
rv = csp->GetAllowsInlineStyle(&reportInlineViolation, &allowInlineStyle);
if (NS_FAILED(rv)) {
if (aRv)
*aRv = rv;
return false;
}
if (reportInlineViolation) {
violations.AppendElement(static_cast<unsigned short>(
nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_STYLE));
}
// query the nonce
nsAutoString nonce;
if (!allowInlineStyle) {
// We can only find a nonce if aContent is provided
bool foundNonce = !!aContent &&
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
if (foundNonce) {
bool reportNonceViolation;
rv = csp->GetAllowsNonce(nonce, nsIContentPolicy::TYPE_STYLESHEET,
&reportNonceViolation, &allowInlineStyle);
if (NS_FAILED(rv)) {
if (aRv)
*aRv = rv;
return false;
}
if (reportNonceViolation) {
violations.AppendElement(static_cast<unsigned short>(
nsIContentSecurityPolicy::VIOLATION_TYPE_NONCE_STYLE));
}
}
if (aContent) {
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
}
if (!allowInlineStyle) {
bool reportHashViolation;
rv = csp->GetAllowsHash(aStyleText, nsIContentPolicy::TYPE_STYLESHEET,
&reportHashViolation, &allowInlineStyle);
if (NS_FAILED(rv)) {
if (aRv)
*aRv = rv;
return false;
}
if (reportHashViolation) {
violations.AppendElement(static_cast<unsigned short>(
nsIContentSecurityPolicy::VIOLATION_TYPE_HASH_STYLE));
}
}
bool allowInlineStyle = true;
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_STYLESHEET,
nonce, aStyleText, aLineNumber,
&allowInlineStyle);
NS_ENSURE_SUCCESS(rv, false);
// What violation(s) should be reported?
//
// 1. If the style tag has a nonce attribute, and the nonce does not match
// the policy, report VIOLATION_TYPE_NONCE_STYLE.
// 2. If the policy has at least one hash-source, and the hashed contents of
// the style tag did not match any of them, report VIOLATION_TYPE_HASH_STYLE
// 3. Otherwise, report VIOLATION_TYPE_INLINE_STYLE if appropriate.
//
// 1 and 2 may occur together, 3 should only occur by itself. Naturally,
// every VIOLATION_TYPE_NONCE_STYLE and VIOLATION_TYPE_HASH_STYLE are also
// VIOLATION_TYPE_INLINE_STYLE, but reporting the
// VIOLATION_TYPE_INLINE_STYLE is redundant and does not help the developer.
if (!violations.IsEmpty()) {
MOZ_ASSERT(violations[0] == nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_STYLE,
"How did we get any violations without an initial inline style violation?");
// This inline style is not allowed by CSP, so report the violation
nsAutoCString asciiSpec;
aSourceURI->GetAsciiSpec(asciiSpec);
nsAutoString styleSample(aStyleText);
// cap the length of the style sample at 40 chars.
if (styleSample.Length() > 40) {
styleSample.Truncate(40);
styleSample.AppendLiteral("...");
}
for (uint32_t i = 0; i < violations.Length(); i++) {
// Skip reporting the redundant inline style violation if there are
// other (nonce and/or hash violations) as well.
if (i > 0 || violations.Length() == 1) {
csp->LogViolationDetails(violations[i], NS_ConvertUTF8toUTF16(asciiSpec),
styleSample, aLineNumber, nonce, aStyleText);
}
}
}
if (!allowInlineStyle) {
NS_ASSERTION(!violations.IsEmpty(),
"CSP blocked inline style but is not reporting a violation");
// The inline style should be blocked.
return false;
}
// CSP allows inline styles.
return true;
return allowInlineStyle;
}