mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 1299483 - CSP: Implement 'strict-dynamic', parser changes. r=dveditz,freddyb
This commit is contained in:
parent
c267f70f91
commit
611dfdf9b7
@ -39,6 +39,17 @@ ignoringSrcFromMetaCSP = Ignoring source ‘%1$S’ (Not supported when delivere
|
||||
# %1$S is the ignored src
|
||||
# script-src and style-src are directive names and should not be localized
|
||||
ignoringSrcWithinScriptStyleSrc = Ignoring “%1$S” within script-src or style-src: nonce-source or hash-source specified
|
||||
# LOCALIZATION NOTE (ignoringSrcForStrictDynamic):
|
||||
# %1$S is the ignored src
|
||||
# script-src, as well as 'strict-dynamic' should not be localized
|
||||
ignoringSrcForStrictDynamic = Ignoring “%1$S” within script-src: ‘strict-dynamic’ specified
|
||||
# LOCALIZATION NOTE (ignoringStrictDynamic):
|
||||
# %1$S is the ignored src
|
||||
ignoringStrictDynamic = Ignoring source “%1$S” (Only supported within script-src).
|
||||
# LOCALIZATION NOTE (strictDynamicButNoHashOrNonce):
|
||||
# %1$S is the csp directive that contains 'strict-dynamic'
|
||||
# 'strict-dynamic' should not be localized
|
||||
strictDynamicButNoHashOrNonce = Keyword ‘strict-dynamic’ within “%1$S” with no valid nonce or hash might block all scripts from loading
|
||||
# LOCALIZATION NOTE (reportURInotHttpsOrHttp2):
|
||||
# %1$S is the ETLD of the report URI that is not HTTP or HTTPS
|
||||
reportURInotHttpsOrHttp2 = The report URI (%1$S) should be an HTTP or HTTPS URI.
|
||||
|
@ -123,6 +123,7 @@ nsCSPTokenizer::tokenizeCSPPolicy(const nsAString &aPolicyString,
|
||||
|
||||
/* ===== nsCSPParser ==================== */
|
||||
bool nsCSPParser::sCSPExperimentalEnabled = false;
|
||||
bool nsCSPParser::sStrictDynamicEnabled = false;
|
||||
|
||||
nsCSPParser::nsCSPParser(cspTokens& aTokens,
|
||||
nsIURI* aSelfURI,
|
||||
@ -131,6 +132,7 @@ nsCSPParser::nsCSPParser(cspTokens& aTokens,
|
||||
: mCurChar(nullptr)
|
||||
, mEndChar(nullptr)
|
||||
, mHasHashOrNonce(false)
|
||||
, mStrictDynamic(false)
|
||||
, mUnsafeInlineKeywordSrc(nullptr)
|
||||
, mChildSrc(nullptr)
|
||||
, mFrameSrc(nullptr)
|
||||
@ -144,6 +146,7 @@ nsCSPParser::nsCSPParser(cspTokens& aTokens,
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
Preferences::AddBoolVarCache(&sCSPExperimentalEnabled, "security.csp.experimentalEnabled");
|
||||
Preferences::AddBoolVarCache(&sStrictDynamicEnabled, "security.csp.enableStrictDynamic");
|
||||
}
|
||||
CSPPARSERLOG(("nsCSPParser::nsCSPParser"));
|
||||
}
|
||||
@ -531,6 +534,22 @@ nsCSPParser::keywordSource()
|
||||
return CSP_CreateHostSrcFromURI(mSelfURI);
|
||||
}
|
||||
|
||||
if (CSP_IsKeyword(mCurToken, CSP_STRICT_DYNAMIC)) {
|
||||
// make sure strict dynamic is enabled
|
||||
if (!sStrictDynamicEnabled) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!CSP_IsDirective(mCurDir[0], nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE)) {
|
||||
// Todo: Enforce 'strict-dynamic' within default-src; see Bug 1313937
|
||||
const char16_t* params[] = { u"strict-dynamic" };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoringStrictDynamic",
|
||||
params, ArrayLength(params));
|
||||
return nullptr;
|
||||
}
|
||||
mStrictDynamic = true;
|
||||
return new nsCSPKeywordSrc(CSP_KeywordToEnum(mCurToken));
|
||||
}
|
||||
|
||||
if (CSP_IsKeyword(mCurToken, CSP_UNSAFE_INLINE)) {
|
||||
nsWeakPtr ctx = mCSPContext->GetLoadingContext();
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(ctx);
|
||||
@ -1187,6 +1206,7 @@ nsCSPParser::directive()
|
||||
// make sure to reset cache variables when trying to invalidate unsafe-inline;
|
||||
// unsafe-inline might not only appear in script-src, but also in default-src
|
||||
mHasHashOrNonce = false;
|
||||
mStrictDynamic = false;
|
||||
mUnsafeInlineKeywordSrc = nullptr;
|
||||
|
||||
// Try to parse all the srcs by handing the array off to directiveValue
|
||||
@ -1200,12 +1220,44 @@ nsCSPParser::directive()
|
||||
srcs.AppendElement(keyword);
|
||||
}
|
||||
|
||||
// Ignore unsafe-inline within script-src or style-src if nonce
|
||||
// or hash is specified, see:
|
||||
// http://www.w3.org/TR/CSP2/#directive-script-src
|
||||
if ((cspDir->equals(nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE) ||
|
||||
cspDir->equals(nsIContentSecurityPolicy::STYLE_SRC_DIRECTIVE)) &&
|
||||
mHasHashOrNonce && mUnsafeInlineKeywordSrc) {
|
||||
// If policy contains 'strict-dynamic' invalidate all srcs within script-src.
|
||||
if (mStrictDynamic) {
|
||||
MOZ_ASSERT(cspDir->equals(nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE),
|
||||
"strict-dynamic only allowed within script-src");
|
||||
for (uint32_t i = 0; i < srcs.Length(); i++) {
|
||||
// Please note that nsCSPNonceSrc as well as nsCSPHashSrc overwrite invalidate(),
|
||||
// so it's fine to just call invalidate() on all srcs. Please also note that
|
||||
// nsCSPKeywordSrc() can not be invalidated and always returns false unless the
|
||||
// keyword is 'strict-dynamic' in which case we allow the load if the script is
|
||||
// not parser created!
|
||||
srcs[i]->invalidate();
|
||||
// Log a message to the console that src will be ignored.
|
||||
nsAutoString srcStr;
|
||||
srcs[i]->toString(srcStr);
|
||||
// Even though we invalidate all of the srcs internally, we don't want to log
|
||||
// messages for the srcs: (1) strict-dynamic, (2) unsafe-inline,
|
||||
// (3) nonces, and (4) hashes
|
||||
if (!srcStr.EqualsASCII(CSP_EnumToKeyword(CSP_STRICT_DYNAMIC)) &&
|
||||
!srcStr.EqualsASCII(CSP_EnumToKeyword(CSP_UNSAFE_EVAL)) &&
|
||||
!StringBeginsWith(NS_ConvertUTF16toUTF8(srcStr), NS_LITERAL_CSTRING("'nonce-")) &&
|
||||
!StringBeginsWith(NS_ConvertUTF16toUTF8(srcStr), NS_LITERAL_CSTRING("'sha")))
|
||||
{
|
||||
const char16_t* params[] = { srcStr.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "ignoringSrcForStrictDynamic",
|
||||
params, ArrayLength(params));
|
||||
}
|
||||
}
|
||||
// Log a warning that all scripts might be blocked because the policy contains
|
||||
// 'strict-dynamic' but no valid nonce or hash.
|
||||
if (!mHasHashOrNonce) {
|
||||
const char16_t* params[] = { mCurDir[0].get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "strictDynamicButNoHashOrNonce",
|
||||
params, ArrayLength(params));
|
||||
}
|
||||
}
|
||||
else if (mHasHashOrNonce && mUnsafeInlineKeywordSrc &&
|
||||
(cspDir->equals(nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE) ||
|
||||
cspDir->equals(nsIContentSecurityPolicy::STYLE_SRC_DIRECTIVE))) {
|
||||
mUnsafeInlineKeywordSrc->invalidate();
|
||||
// log to the console that unsafe-inline will be ignored
|
||||
const char16_t* params[] = { u"'unsafe-inline'" };
|
||||
|
@ -112,6 +112,7 @@ class nsCSPParser {
|
||||
bool aDeliveredViaMetaTag);
|
||||
|
||||
static bool sCSPExperimentalEnabled;
|
||||
static bool sStrictDynamicEnabled;
|
||||
|
||||
~nsCSPParser();
|
||||
|
||||
@ -236,8 +237,10 @@ class nsCSPParser {
|
||||
nsString mCurToken;
|
||||
nsTArray<nsString> mCurDir;
|
||||
|
||||
// cache variables to ignore unsafe-inline if hash or nonce is specified
|
||||
// helpers to allow invalidation of srcs within script-src and style-src
|
||||
// if either 'strict-dynamic' or at least a hash or nonce is present.
|
||||
bool mHasHashOrNonce; // false, if no hash or nonce is defined
|
||||
bool mStrictDynamic; // false, if 'strict-dynamic' is not defined
|
||||
nsCSPKeywordSrc* mUnsafeInlineKeywordSrc; // null, otherwise invlidate()
|
||||
|
||||
// cache variables for child-src and frame-src directive handling.
|
||||
|
@ -2135,6 +2135,7 @@ pref("security.notification_enable_delay", 500);
|
||||
|
||||
pref("security.csp.enable", true);
|
||||
pref("security.csp.experimentalEnabled", false);
|
||||
pref("security.csp.enableStrictDynamic", true);
|
||||
|
||||
// Default Content Security Policy to apply to signed contents.
|
||||
pref("security.signed_content.CSP.default", "script-src 'self'; style-src 'self'");
|
||||
|
Loading…
Reference in New Issue
Block a user