mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1890277: part 2) Add require-trusted-types-for
directive to CSP parser, guarded behind the Trusted Types pref. r=tschuster,webidl,smaug
Differential Revision: https://phabricator.services.mozilla.com/D206998
This commit is contained in:
parent
2fcd7e5c5c
commit
db3ca28481
@ -40,31 +40,32 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
* add it to the CSPStrDirectives array in nsCSPUtils.h.
|
||||
*/
|
||||
cenum CSPDirective : 8 {
|
||||
NO_DIRECTIVE = 0,
|
||||
DEFAULT_SRC_DIRECTIVE = 1,
|
||||
SCRIPT_SRC_DIRECTIVE = 2,
|
||||
OBJECT_SRC_DIRECTIVE = 3,
|
||||
STYLE_SRC_DIRECTIVE = 4,
|
||||
IMG_SRC_DIRECTIVE = 5,
|
||||
MEDIA_SRC_DIRECTIVE = 6,
|
||||
FRAME_SRC_DIRECTIVE = 7,
|
||||
FONT_SRC_DIRECTIVE = 8,
|
||||
CONNECT_SRC_DIRECTIVE = 9,
|
||||
REPORT_URI_DIRECTIVE = 10,
|
||||
FRAME_ANCESTORS_DIRECTIVE = 11,
|
||||
REFLECTED_XSS_DIRECTIVE = 12,
|
||||
BASE_URI_DIRECTIVE = 13,
|
||||
FORM_ACTION_DIRECTIVE = 14,
|
||||
WEB_MANIFEST_SRC_DIRECTIVE = 15,
|
||||
UPGRADE_IF_INSECURE_DIRECTIVE = 16,
|
||||
CHILD_SRC_DIRECTIVE = 17,
|
||||
BLOCK_ALL_MIXED_CONTENT = 18,
|
||||
SANDBOX_DIRECTIVE = 19,
|
||||
WORKER_SRC_DIRECTIVE = 20,
|
||||
SCRIPT_SRC_ELEM_DIRECTIVE = 21,
|
||||
SCRIPT_SRC_ATTR_DIRECTIVE = 22,
|
||||
STYLE_SRC_ELEM_DIRECTIVE = 23,
|
||||
STYLE_SRC_ATTR_DIRECTIVE = 24,
|
||||
NO_DIRECTIVE = 0,
|
||||
DEFAULT_SRC_DIRECTIVE = 1,
|
||||
SCRIPT_SRC_DIRECTIVE = 2,
|
||||
OBJECT_SRC_DIRECTIVE = 3,
|
||||
STYLE_SRC_DIRECTIVE = 4,
|
||||
IMG_SRC_DIRECTIVE = 5,
|
||||
MEDIA_SRC_DIRECTIVE = 6,
|
||||
FRAME_SRC_DIRECTIVE = 7,
|
||||
FONT_SRC_DIRECTIVE = 8,
|
||||
CONNECT_SRC_DIRECTIVE = 9,
|
||||
REPORT_URI_DIRECTIVE = 10,
|
||||
FRAME_ANCESTORS_DIRECTIVE = 11,
|
||||
REFLECTED_XSS_DIRECTIVE = 12,
|
||||
BASE_URI_DIRECTIVE = 13,
|
||||
FORM_ACTION_DIRECTIVE = 14,
|
||||
WEB_MANIFEST_SRC_DIRECTIVE = 15,
|
||||
UPGRADE_IF_INSECURE_DIRECTIVE = 16,
|
||||
CHILD_SRC_DIRECTIVE = 17,
|
||||
BLOCK_ALL_MIXED_CONTENT = 18,
|
||||
SANDBOX_DIRECTIVE = 19,
|
||||
WORKER_SRC_DIRECTIVE = 20,
|
||||
SCRIPT_SRC_ELEM_DIRECTIVE = 21,
|
||||
SCRIPT_SRC_ATTR_DIRECTIVE = 22,
|
||||
STYLE_SRC_ELEM_DIRECTIVE = 23,
|
||||
STYLE_SRC_ATTR_DIRECTIVE = 24,
|
||||
REQUIRE_TRUSTED_TYPES_FOR_DIRECTIVE = 25,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -201,6 +201,13 @@ duplicateDirective = Duplicate %1$S directives detected. All but the first inst
|
||||
# LOCALIZATION NOTE (couldntParseInvalidSandboxFlag):
|
||||
# %1$S is the option that could not be understood
|
||||
couldntParseInvalidSandboxFlag = Couldn’t parse invalid sandbox flag ‘%1$S’
|
||||
# LOCALIZATION NOTE (invalidNumberOfTrustedTypesForDirectiveValues):
|
||||
# %1$S is the number of passed tokens.
|
||||
invalidNumberOfTrustedTypesForDirectiveValues = Received an invalid number of tokens for the 'require-trusted-types-for' directive: %1$S; expected 1
|
||||
# LOCALIZATION NOTE (invalidRequireTrustedTypesForDirectiveValue):
|
||||
# %1$S is the passed token
|
||||
invalidRequireTrustedTypesForDirectiveValue = Received an invalid token for the 'require-trusted-types-for' directive: %1$S; expected 'script'
|
||||
|
||||
|
||||
# LOCALIZATION NOTE (CSPMessagePrefix):
|
||||
# Do not translate "Content-Security-Policy", only handle spacing for the colon.
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "mozilla/TextUtils.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include "mozilla/StaticPrefs_security.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
@ -19,6 +20,9 @@
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
@ -813,6 +817,54 @@ void nsCSPParser::sandboxFlagList(nsCSPDirective* aDir) {
|
||||
mPolicy->addDirective(aDir);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/trusted-types/dist/spec/#integration-with-content-security-policy
|
||||
static constexpr nsLiteralString kValidRequireTrustedTypesForDirectiveValue =
|
||||
u"'script'"_ns;
|
||||
|
||||
static bool IsValidRequireTrustedTypesForDirectiveValue(
|
||||
const nsAString& aToken) {
|
||||
return aToken.Equals(kValidRequireTrustedTypesForDirectiveValue);
|
||||
}
|
||||
|
||||
void nsCSPParser::handleRequireTrustedTypesForDirective(nsCSPDirective* aDir) {
|
||||
// "srcs" start at index 1. Here "srcs" should represent Trusted Types' sink
|
||||
// groups
|
||||
// (https://w3c.github.io/trusted-types/dist/spec/#require-trusted-types-for-csp-directive).
|
||||
|
||||
if (mCurDir.Length() != 2) {
|
||||
nsString numberOfTokensStr;
|
||||
|
||||
// Casting is required to avoid ambiguous function calls on some platforms.
|
||||
numberOfTokensStr.AppendInt(static_cast<uint64_t>(mCurDir.Length()));
|
||||
|
||||
AutoTArray<nsString, 1> numberOfTokensArr = {std::move(numberOfTokensStr)};
|
||||
logWarningErrorToConsole(nsIScriptError::errorFlag,
|
||||
"invalidNumberOfTrustedTypesForDirectiveValues",
|
||||
numberOfTokensArr);
|
||||
return;
|
||||
}
|
||||
|
||||
mCurToken = mCurDir.LastElement();
|
||||
|
||||
CSPPARSERLOG(
|
||||
("nsCSPParser::handleRequireTrustedTypesForDirective, mCurToken: %s",
|
||||
NS_ConvertUTF16toUTF8(mCurToken).get()));
|
||||
|
||||
if (!IsValidRequireTrustedTypesForDirectiveValue(mCurToken)) {
|
||||
AutoTArray<nsString, 1> token = {mCurToken};
|
||||
logWarningErrorToConsole(nsIScriptError::errorFlag,
|
||||
"invalidRequireTrustedTypesForDirectiveValue",
|
||||
token);
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<nsCSPBaseSrc*> srcs = {
|
||||
new nsCSPRequireTrustedTypesForDirectiveValue(mCurToken)};
|
||||
|
||||
aDir->addSrcs(srcs);
|
||||
mPolicy->addDirective(aDir);
|
||||
}
|
||||
|
||||
// directive-value = *( WSP / <VCHAR except ";" and ","> )
|
||||
void nsCSPParser::directiveValue(nsTArray<nsCSPBaseSrc*>& outSrcs) {
|
||||
CSPPARSERLOG(("nsCSPParser::directiveValue"));
|
||||
@ -829,7 +881,10 @@ nsCSPDirective* nsCSPParser::directiveName() {
|
||||
|
||||
// Check if it is a valid directive
|
||||
CSPDirective directive = CSP_StringToCSPDirective(mCurToken);
|
||||
if (directive == nsIContentSecurityPolicy::NO_DIRECTIVE) {
|
||||
if (directive == nsIContentSecurityPolicy::NO_DIRECTIVE ||
|
||||
(!StaticPrefs::dom_security_trusted_types_enabled() &&
|
||||
directive ==
|
||||
nsIContentSecurityPolicy::REQUIRE_TRUSTED_TYPES_FOR_DIRECTIVE)) {
|
||||
AutoTArray<nsString, 1> params = {mCurToken};
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag,
|
||||
"couldNotProcessUnknownDirective", params);
|
||||
@ -1008,6 +1063,14 @@ void nsCSPParser::directive() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Special case handling since these directives don't contain source lists.
|
||||
if (CSP_IsDirective(
|
||||
mCurDir[0],
|
||||
nsIContentSecurityPolicy::REQUIRE_TRUSTED_TYPES_FOR_DIRECTIVE)) {
|
||||
handleRequireTrustedTypesForDirective(cspDir);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
@ -72,6 +72,7 @@ class nsCSPParser {
|
||||
void referrerDirectiveValue(nsCSPDirective* aDir);
|
||||
void reportURIList(nsCSPDirective* aDir);
|
||||
void sandboxFlagList(nsCSPDirective* aDir);
|
||||
void handleRequireTrustedTypesForDirective(nsCSPDirective* aDir);
|
||||
void sourceList(nsTArray<nsCSPBaseSrc*>& outSrcs);
|
||||
nsCSPBaseSrc* sourceExpression();
|
||||
nsCSPSchemeSrc* schemeSource();
|
||||
|
@ -243,6 +243,20 @@ void CSP_LogMessage(const nsAString& aMessage, const nsAString& aSourceName,
|
||||
console->LogMessage(error);
|
||||
}
|
||||
|
||||
CSPDirective CSP_StringToCSPDirective(const nsAString& aDir) {
|
||||
nsString lowerDir = PromiseFlatString(aDir);
|
||||
ToLowerCase(lowerDir);
|
||||
|
||||
uint32_t numDirs = (sizeof(CSPStrDirectives) / sizeof(CSPStrDirectives[0]));
|
||||
|
||||
for (uint32_t i = 1; i < numDirs; i++) {
|
||||
if (lowerDir.EqualsASCII(CSPStrDirectives[i])) {
|
||||
return static_cast<CSPDirective>(i);
|
||||
}
|
||||
}
|
||||
return nsIContentSecurityPolicy::NO_DIRECTIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines CSP_LogMessage and CSP_GetLocalizedStr into one call.
|
||||
*/
|
||||
@ -997,6 +1011,24 @@ void nsCSPSandboxFlags::toString(nsAString& outStr) const {
|
||||
outStr.Append(mFlags);
|
||||
}
|
||||
|
||||
/* ===== nsCSPRequireTrustedTypesForDirectiveValue ===================== */
|
||||
|
||||
nsCSPRequireTrustedTypesForDirectiveValue::
|
||||
nsCSPRequireTrustedTypesForDirectiveValue(const nsAString& aValue)
|
||||
: mValue{aValue} {}
|
||||
|
||||
bool nsCSPRequireTrustedTypesForDirectiveValue::visit(
|
||||
nsCSPSrcVisitor* aVisitor) const {
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"This method should only be called for other overloads of this method.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void nsCSPRequireTrustedTypesForDirectiveValue::toString(
|
||||
nsAString& aOutStr) const {
|
||||
aOutStr.Append(mValue);
|
||||
}
|
||||
|
||||
/* ===== nsCSPDirective ====================== */
|
||||
|
||||
nsCSPDirective::nsCSPDirective(CSPDirective aDirective) {
|
||||
@ -1414,6 +1446,14 @@ void nsCSPDirective::toDomCSPStruct(mozilla::dom::CSP& outCSP) const {
|
||||
outCSP.mScript_src_attr.Value() = std::move(srcs);
|
||||
return;
|
||||
|
||||
case nsIContentSecurityPolicy::REQUIRE_TRUSTED_TYPES_FOR_DIRECTIVE:
|
||||
outCSP.mRequire_trusted_types_for.Construct();
|
||||
|
||||
// Here, the srcs represent the sink group
|
||||
// (https://w3c.github.io/trusted-types/dist/spec/#integration-with-content-security-policy).
|
||||
outCSP.mRequire_trusted_types_for.Value() = std::move(srcs);
|
||||
return;
|
||||
|
||||
default:
|
||||
NS_ASSERTION(false, "cannot find directive to convert CSP to JSON");
|
||||
}
|
||||
|
@ -93,24 +93,14 @@ static const char* CSPStrDirectives[] = {
|
||||
"script-src-attr", // SCRIPT_SRC_ATTR_DIRECTIVE
|
||||
"style-src-elem", // STYLE_SRC_ELEM_DIRECTIVE
|
||||
"style-src-attr", // STYLE_SRC_ATTR_DIRECTIVE
|
||||
"require-trusted-types-for", // REQUIRE_TRUSTED_TYPES_FOR_DIRECTIVE
|
||||
};
|
||||
|
||||
inline const char* CSP_CSPDirectiveToString(CSPDirective aDir) {
|
||||
return CSPStrDirectives[static_cast<uint32_t>(aDir)];
|
||||
}
|
||||
|
||||
inline CSPDirective CSP_StringToCSPDirective(const nsAString& aDir) {
|
||||
nsString lowerDir = PromiseFlatString(aDir);
|
||||
ToLowerCase(lowerDir);
|
||||
|
||||
uint32_t numDirs = (sizeof(CSPStrDirectives) / sizeof(CSPStrDirectives[0]));
|
||||
for (uint32_t i = 1; i < numDirs; i++) {
|
||||
if (lowerDir.EqualsASCII(CSPStrDirectives[i])) {
|
||||
return static_cast<CSPDirective>(i);
|
||||
}
|
||||
}
|
||||
return nsIContentSecurityPolicy::NO_DIRECTIVE;
|
||||
}
|
||||
CSPDirective CSP_StringToCSPDirective(const nsAString& aDir);
|
||||
|
||||
#define FOR_EACH_CSP_KEYWORD(MACRO) \
|
||||
MACRO(CSP_SELF, "'self'") \
|
||||
@ -396,6 +386,20 @@ class nsCSPSandboxFlags : public nsCSPBaseSrc {
|
||||
nsString mFlags;
|
||||
};
|
||||
|
||||
/* =============== nsCSPRequireTrustedTypesForDirectiveValue =============== */
|
||||
|
||||
class nsCSPRequireTrustedTypesForDirectiveValue : public nsCSPBaseSrc {
|
||||
public:
|
||||
explicit nsCSPRequireTrustedTypesForDirectiveValue(const nsAString& aValue);
|
||||
virtual ~nsCSPRequireTrustedTypesForDirectiveValue() = default;
|
||||
|
||||
bool visit(nsCSPSrcVisitor* aVisitor) const override;
|
||||
void toString(nsAString& aOutStr) const override;
|
||||
|
||||
private:
|
||||
const nsString mValue;
|
||||
};
|
||||
|
||||
/* =============== nsCSPSrcVisitor ================== */
|
||||
|
||||
class nsCSPSrcVisitor {
|
||||
|
@ -32,6 +32,7 @@ dictionary CSP {
|
||||
sequence<DOMString> worker-src;
|
||||
sequence<DOMString> script-src-elem;
|
||||
sequence<DOMString> script-src-attr;
|
||||
sequence<DOMString> require-trusted-types-for;
|
||||
};
|
||||
|
||||
[GenerateToJSON]
|
||||
|
Loading…
Reference in New Issue
Block a user