Issue #2466 - Part 3: Implement style-src-elem and style-src-attr

This commit is contained in:
Moonchild 2024-02-04 23:24:50 +01:00 • committed by roytam1
commit 721ded9b48
8 changed files with 78 additions and 12 deletions

View file

@ -62,6 +62,8 @@ interface nsIContentSecurityPolicy : nsISerializable
const unsigned short WORKER_SRC_DIRECTIVE = 22; const unsigned short WORKER_SRC_DIRECTIVE = 22;
const unsigned short SCRIPT_SRC_ELEM_DIRECTIVE = 23; const unsigned short SCRIPT_SRC_ELEM_DIRECTIVE = 23;
const unsigned short SCRIPT_SRC_ATTR_DIRECTIVE = 24; const unsigned short SCRIPT_SRC_ATTR_DIRECTIVE = 24;
const unsigned short STYLE_SRC_ELEM_DIRECTIVE = 25;
const unsigned short STYLE_SRC_ATTR_DIRECTIVE = 26;
/** /**
* Accessor method for a read-only string version of the policy at a given * Accessor method for a read-only string version of the policy at a given

View file

@ -569,9 +569,9 @@ nsCSPContext::GetAllowsInline(CSPDirective aDirective,
if (aDirective != SCRIPT_SRC_ELEM_DIRECTIVE && if (aDirective != SCRIPT_SRC_ELEM_DIRECTIVE &&
aDirective != SCRIPT_SRC_ATTR_DIRECTIVE && aDirective != SCRIPT_SRC_ATTR_DIRECTIVE &&
aDirective != STYLE_SRC_DIRECTIVE) { aDirective != STYLE_SRC_ELEM_DIRECTIVE &&
MOZ_ASSERT(false, aDirective != STYLE_SRC_ATTR_DIRECTIVE) {
"can only allow inline for script-src-(attr/elem) or style"); MOZ_ASSERT(false, "can only allow inline for (script/style)-src-(attr/elem) or style");
return NS_OK; return NS_OK;
} }

View file

@ -115,6 +115,7 @@ nsCSPParser::nsCSPParser(cspTokens& aTokens,
, mFrameSrc(nullptr) , mFrameSrc(nullptr)
, mWorkerSrc(nullptr) , mWorkerSrc(nullptr)
, mScriptSrc(nullptr) , mScriptSrc(nullptr)
, mStyleSrc(nullptr)
, mParsingFrameAncestorsDir(false) , mParsingFrameAncestorsDir(false)
, mTokens(aTokens) , mTokens(aTokens)
, mSelfURI(aSelfURI) , mSelfURI(aSelfURI)
@ -1088,6 +1089,13 @@ nsCSPParser::directiveName()
return mScriptSrc; return mScriptSrc;
} }
// If we have a style-src, cache it as a fallback for style-src-elem and
// style-src-attr.
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::STYLE_SRC_DIRECTIVE)) {
mStyleSrc = new nsCSPStyleSrcDirective(CSP_StringToCSPDirective(mCurToken));
return mStyleSrc;
}
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::REQUIRE_SRI_FOR)) { if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::REQUIRE_SRI_FOR)) {
return new nsRequireSRIForDirective(CSP_StringToCSPDirective(mCurToken)); return new nsRequireSRIForDirective(CSP_StringToCSPDirective(mCurToken));
} }
@ -1314,6 +1322,18 @@ nsCSPParser::policy()
mScriptSrc->setRestrictScriptAttr(); mScriptSrc->setRestrictScriptAttr();
} }
// If style-src is specified and style-src-elem is not specified, then
// style-src serves as a fallback.
if (mStyleSrc && !mPolicy->hasDirective(nsIContentSecurityPolicy::STYLE_SRC_ELEM_DIRECTIVE)) {
mStyleSrc->setRestrictStyleElem();
}
// If style-src is specified and style-src-attr is not specified, then
// style-src serves as a fallback.
if (mStyleSrc && !mPolicy->hasDirective(nsIContentSecurityPolicy::STYLE_SRC_ATTR_DIRECTIVE)) {
mStyleSrc->setRestrictStyleAttr();
}
return mPolicy; return mPolicy;
} }

View file

@ -255,6 +255,7 @@ class nsCSPParser {
nsCSPDirective* mFrameSrc; nsCSPDirective* mFrameSrc;
nsCSPDirective* mWorkerSrc; nsCSPDirective* mWorkerSrc;
nsCSPScriptSrcDirective* mScriptSrc; nsCSPScriptSrcDirective* mScriptSrc;
nsCSPStyleSrcDirective* mStyleSrc;
// cache variable to let nsCSPHostSrc know that it's within // cache variable to let nsCSPHostSrc know that it's within
// the frame-ancestors directive. // the frame-ancestors directive.

View file

@ -224,7 +224,7 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType)
return nsIContentSecurityPolicy::SCRIPT_SRC_ELEM_DIRECTIVE; return nsIContentSecurityPolicy::SCRIPT_SRC_ELEM_DIRECTIVE;
case nsIContentPolicy::TYPE_STYLESHEET: case nsIContentPolicy::TYPE_STYLESHEET:
return nsIContentSecurityPolicy::STYLE_SRC_DIRECTIVE; return nsIContentSecurityPolicy::STYLE_SRC_ELEM_DIRECTIVE;
case nsIContentPolicy::TYPE_FONT: case nsIContentPolicy::TYPE_FONT:
return nsIContentSecurityPolicy::FONT_SRC_DIRECTIVE; return nsIContentSecurityPolicy::FONT_SRC_DIRECTIVE;
@ -1313,12 +1313,9 @@ nsCSPScriptSrcDirective::nsCSPScriptSrcDirective(CSPDirective aDirective)
{ {
} }
nsCSPScriptSrcDirective::~nsCSPScriptSrcDirective() nsCSPScriptSrcDirective::~nsCSPScriptSrcDirective() = default;
{
}
bool nsCSPScriptSrcDirective::equals(CSPDirective aDirective) const bool nsCSPScriptSrcDirective::equals(CSPDirective aDirective) const {
{
if (aDirective == nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE) { if (aDirective == nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE) {
return mRestrictWorkers; return mRestrictWorkers;
} }
@ -1331,6 +1328,27 @@ bool nsCSPScriptSrcDirective::equals(CSPDirective aDirective) const
return (mDirective == aDirective); return (mDirective == aDirective);
} }
/* =============== nsCSPStyleSrcDirective ============= */
nsCSPStyleSrcDirective::nsCSPStyleSrcDirective(CSPDirective aDirective)
: nsCSPDirective(aDirective)
, mRestrictStyleElem(false)
, mRestrictStyleAttr(false)
{
}
nsCSPStyleSrcDirective::~nsCSPStyleSrcDirective() = default;
bool nsCSPStyleSrcDirective::equals(CSPDirective aDirective) const {
if (aDirective == nsIContentSecurityPolicy::STYLE_SRC_ELEM_DIRECTIVE) {
return mRestrictStyleElem;
}
if (aDirective == nsIContentSecurityPolicy::STYLE_SRC_ATTR_DIRECTIVE) {
return mRestrictStyleAttr;
}
return (mDirective == aDirective);
}
/* =============== nsBlockAllMixedContentDirective ============= */ /* =============== nsBlockAllMixedContentDirective ============= */
nsBlockAllMixedContentDirective::nsBlockAllMixedContentDirective(CSPDirective aDirective) nsBlockAllMixedContentDirective::nsBlockAllMixedContentDirective(CSPDirective aDirective)

View file

@ -143,7 +143,9 @@ static const char* CSPStrDirectives[] = {
"sandbox", // SANDBOX_DIRECTIVE "sandbox", // SANDBOX_DIRECTIVE
"worker-src", // WORKER_SRC_DIRECTIVE "worker-src", // WORKER_SRC_DIRECTIVE
"script-src-elem", // SCRIPT_SRC_ELEM_DIRECTIVE "script-src-elem", // SCRIPT_SRC_ELEM_DIRECTIVE
"script-src-attr" // SCRIPT_SRC_ATTR_DIRECTIVE "script-src-attr", // SCRIPT_SRC_ATTR_DIRECTIVE
"style-src-elem", // STYLE_SRC_ELEM_DIRECTIVE
"style-src-attr" // STYLE_SRC_ATTR_DIRECTIVE
}; };
inline const char* CSP_CSPDirectiveToString(CSPDirective aDir) inline const char* CSP_CSPDirectiveToString(CSPDirective aDir)
@ -551,6 +553,27 @@ class nsCSPScriptSrcDirective : public nsCSPDirective {
bool mRestrictScriptAttr; bool mRestrictScriptAttr;
}; };
/* =============== nsCSPStyleSrcDirective ============= */
/*
* In CSP 3, style-src is used as a fallback for style-src-elem and
* style-src-attr in case they aren't defined.
*/
class nsCSPStyleSrcDirective : public nsCSPDirective {
public:
explicit nsCSPStyleSrcDirective(CSPDirective aDirective);
virtual ~nsCSPStyleSrcDirective();
void setRestrictStyleElem() { mRestrictStyleElem = true; }
void setRestrictStyleAttr() { mRestrictStyleAttr = true; }
virtual bool equals(CSPDirective aDirective) const;
private:
bool mRestrictStyleElem;
bool mRestrictStyleAttr;
};
/* =============== nsBlockAllMixedContentDirective === */ /* =============== nsBlockAllMixedContentDirective === */
class nsBlockAllMixedContentDirective : public nsCSPDirective { class nsBlockAllMixedContentDirective : public nsCSPDirective {

View file

@ -50,7 +50,7 @@ function checkResults(reportStr) {
"http://mochi.test:8888/tests/dom/security/test/csp/test_report_for_import.html", "http://mochi.test:8888/tests/dom/security/test/csp/test_report_for_import.html",
"Incorrect referrer"); "Incorrect referrer");
is(cspReport["violated-directive"], is(cspReport["violated-directive"],
"style-src http://mochi.test:8888", "style-src-elem http://mochi.test:8888",
"Incorrect violated-directive"); "Incorrect violated-directive");
is(cspReport["original-policy"], is(cspReport["original-policy"],
"style-src http://mochi.test:8888; report-uri " + "style-src http://mochi.test:8888; report-uri " +

View file

@ -767,14 +767,16 @@ nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent,
return true; return true;
} }
CSPDirective directive = nsIContentSecurityPolicy::STYLE_SRC_ATTR_DIRECTIVE;
// query the nonce // query the nonce
nsAutoString nonce; nsAutoString nonce;
if (aContent) { if (aContent) {
directive = nsIContentSecurityPolicy::STYLE_SRC_ELEM_DIRECTIVE;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce); aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
} }
bool allowInlineStyle = true; bool allowInlineStyle = true;
rv = csp->GetAllowsInline(nsIContentSecurityPolicy::STYLE_SRC_DIRECTIVE, rv = csp->GetAllowsInline(directive,
nonce, nonce,
false, // aParserCreated only applies to scripts false, // aParserCreated only applies to scripts
aStyleText, aLineNumber, aColumnNumber, aStyleText, aLineNumber, aColumnNumber,