Issue #2734 - Add base-64 grammar check to CSP nonces where applicable.

Resolves #2734
This commit is contained in:
Moonchild 2025-06-16 13:19:51 +02:00 • committed by roytam1
commit 51022b98b2
3 changed files with 68 additions and 0 deletions

View file

@ -642,6 +642,11 @@ nsCSPParser::nonceSource()
if (dashIndex < 0) {
return nullptr;
}
if (!isValidBase64Value(expr.BeginReading() + dashIndex + 1, expr.EndReading())) {
return nullptr;
}
// cache if encountering hash or nonce to invalidate unsafe-inline
mHasHashOrNonce = true;
return new nsCSPNonceSrc(Substring(expr,
@ -671,6 +676,10 @@ nsCSPParser::hashSource()
return nullptr;
}
if (!isValidBase64Value(expr.BeginReading() + dashIndex + 1, expr.EndReading())) {
return nullptr;
}
nsAutoString algo(Substring(expr, 0, dashIndex));
nsAutoString hash(Substring(expr, dashIndex + 1, expr.Length() - dashIndex + 1));

View file

@ -61,6 +61,33 @@ isValidHexDig(char16_t aHexDig)
(aHexDig >= 'a' && aHexDig <= 'f'));
}
// Checks grammar for valid base-64 strings. Does not verify decodability.
static bool
isValidBase64Value(const char16_t* cur, const char16_t* end)
{
// Using grammar at https://w3c.github.io/webappsec-csp/#grammardef-nonce-source
// May end with one or two =
if (end > cur && *(end-1) == EQUALS) end--;
if (end > cur && *(end-1) == EQUALS) end--;
// Must have at least one character aside from any =
if (end == cur) {
return false;
}
// Rest must all be A-Za-z0-9+/-_
for (; cur < end; ++cur) {
if (!(isCharacterToken(*cur) || isNumberToken(*cur) ||
*cur == PLUS || *cur == SLASH ||
*cur == DASH || *cur == UNDERLINE)) {
return false;
}
}
return true;
}
// ============================================
namespace mozilla {

View file

@ -227,6 +227,10 @@ TEST(CSPParser, Directives)
"report-uri http://www.example.com/" },
{ "script-src 'nonce-correctscriptnonce'",
"script-src 'nonce-correctscriptnonce'" },
{ "script-src 'nonce-a'",
"script-src 'nonce-a'" },
{ "script-src 'sha256-a'",
"script-src 'sha256-a'" },
{ "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='",
"script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" },
{ "require-sri-for script style",
@ -543,6 +547,34 @@ TEST(CSPParser, PoliciesWithInvalidSrc)
"script-src 'none'" },
{ "script-src http://www.example.com:*.",
"script-src 'none'" },
{ "script-src 'nonce-{invalid}'",
"script-src 'none'" },
{ "script-src 'sha256-{invalid}'",
"script-src 'none'" },
{ "script-src 'nonce-in$valid'",
"script-src 'none'" },
{ "script-src 'sha256-in$valid'",
"script-src 'none'" },
{ "script-src 'nonce-invalid==='",
"script-src 'none'" },
{ "script-src 'sha256-invalid==='",
"script-src 'none'" },
{ "script-src 'nonce-==='",
"script-src 'none'" },
{ "script-src 'sha256-==='",
"script-src 'none'" },
{ "script-src 'nonce-=='",
"script-src 'none'" },
{ "script-src 'sha256-=='",
"script-src 'none'" },
{ "script-src 'nonce-='",
"script-src 'none'" },
{ "script-src 'sha256-='",
"script-src 'none'" },
{ "script-src 'nonce-'",
"script-src 'none'" },
{ "script-src 'sha256-'",
"script-src 'none'" },
{ "connect-src http://www.example.com/foo%zz;",
"connect-src 'none'" },
{ "script-src https://foo.com/%$",