Bug 1302667 - CSP: Implement 'worker-src'. r=baku,dveditz,mckinley

This commit is contained in:
Christoph Kerschbaumer 2017-10-30 18:45:36 +01:00
Родитель 97bb052ce5
Коммит 2fd8493f7f
7 изменённых файлов: 142 добавлений и 44 удалений

Просмотреть файл

@ -63,6 +63,7 @@ interface nsIContentSecurityPolicy : nsISerializable
const unsigned short BLOCK_ALL_MIXED_CONTENT = 19;
const unsigned short REQUIRE_SRI_FOR = 20;
const unsigned short SANDBOX_DIRECTIVE = 21;
const unsigned short WORKER_SRC_DIRECTIVE = 22;
/**
* Accessor method for a read-only string version of the policy at a given

Просмотреть файл

@ -112,9 +112,10 @@ couldntParsePort = Couldnt parse port in %1$S
# LOCALIZATION NOTE (duplicateDirective):
# %1$S is the name of the duplicate directive
duplicateDirective = Duplicate %1$S directives detected. All but the first instance will be ignored.
# LOCALIZATION NOTE (deprecatedDirective):
# %1$S is the name of the deprecated directive, %2$S is the name of the replacement.
deprecatedDirective = Directive %1$S has been deprecated. Please use directive %2$S instead.
# LOCALIZATION NOTE (deprecatedChildSrcDirective):
# %1$S is the value of the deprecated directive.
# Do not localize: worker-src, frame-src
deprecatedChildSrcDirective = Directive %1$S has been deprecated. Please use directive worker-src to control workers, or directive frame-src to control frames respectively.
# LOCALIZATION NOTE (couldntParseInvalidSandboxFlag):
# %1$S is the option that could not be understood
couldntParseInvalidSandboxFlag = Couldnt parse invalid sandbox flag %1$S

Просмотреть файл

@ -134,6 +134,8 @@ nsCSPParser::nsCSPParser(cspTokens& aTokens,
, mUnsafeInlineKeywordSrc(nullptr)
, mChildSrc(nullptr)
, mFrameSrc(nullptr)
, mWorkerSrc(nullptr)
, mScriptSrc(nullptr)
, mParsingFrameAncestorsDir(false)
, mTokens(aTokens)
, mSelfURI(aSelfURI)
@ -1110,21 +1112,37 @@ nsCSPParser::directiveName()
return new nsUpgradeInsecureDirective(CSP_StringToCSPDirective(mCurToken));
}
// child-src has it's own class to handle frame-src if necessary
// child-src by itself is deprecatd but will be enforced
// * for workers (if worker-src is not explicitly specified)
// * for frames (if frame-src is not explicitly specified)
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::CHILD_SRC_DIRECTIVE)) {
const char16_t* params[] = { mCurToken.get() };
logWarningErrorToConsole(nsIScriptError::warningFlag,
"deprecatedChildSrcDirective",
params, ArrayLength(params));
mChildSrc = new nsCSPChildSrcDirective(CSP_StringToCSPDirective(mCurToken));
return mChildSrc;
}
// if we have a frame-src, cache it so we can decide whether to use child-src
// if we have a frame-src, cache it so we can discard child-src for frames
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE)) {
const char16_t* params[] = { mCurToken.get(), u"child-src" };
logWarningErrorToConsole(nsIScriptError::warningFlag, "deprecatedDirective",
params, ArrayLength(params));
mFrameSrc = new nsCSPDirective(CSP_StringToCSPDirective(mCurToken));
return mFrameSrc;
}
// if we have a worker-src, cache it so we can discard child-src for workers
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE)) {
mWorkerSrc = new nsCSPDirective(CSP_StringToCSPDirective(mCurToken));
return mWorkerSrc;
}
// if we have a script-src, cache it as a fallback for worker-src
// in case child-src is not present
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE)) {
mScriptSrc = new nsCSPScriptSrcDirective(CSP_StringToCSPDirective(mCurToken));
return mScriptSrc;
}
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::REQUIRE_SRI_FOR)) {
return new nsRequireSRIForDirective(CSP_StringToCSPDirective(mCurToken));
}
@ -1301,9 +1319,22 @@ nsCSPParser::policy()
directive();
}
if (mChildSrc && !mFrameSrc) {
// if we have a child-src, it handles frame-src too, unless frame-src is set
mChildSrc->setHandleFrameSrc();
if (mChildSrc) {
if (!mFrameSrc) {
// if frame-src is specified explicitly for that policy than child-src should
// not restrict frames; if not, than child-src needs to restrict frames.
mChildSrc->setRestrictFrames();
}
if (!mWorkerSrc) {
// if worker-src is specified explicitly for that policy than child-src should
// not restrict workers; if not, than child-src needs to restrict workers.
mChildSrc->setRestrictWorkers();
}
}
// if script-src is specified, but not worker-src and also no child-src, then
// script-src has to govern workers.
if (mScriptSrc && !mWorkerSrc && !mChildSrc) {
mScriptSrc->setRestrictWorkers();
}
return mPolicy;

Просмотреть файл

@ -242,14 +242,17 @@ class nsCSPParser {
bool mStrictDynamic; // false, if 'strict-dynamic' is not defined
nsCSPKeywordSrc* mUnsafeInlineKeywordSrc; // null, otherwise invlidate()
// cache variables for child-src and frame-src directive handling.
// frame-src is deprecated in favor of child-src, however if we
// see a frame-src directive, it takes precedence for frames and iframes.
// At the end of parsing, if we have a child-src directive, we need to
// decide whether it will handle frames, or if there is a frame-src we
// should honor instead.
// cache variables for child-src, frame-src and worker-src handling;
// in CSP 3 child-src is deprecated. For backwards compatibility
// child-src needs to restrict:
// (*) frames, in case frame-src is not expicitly specified
// (*) workers, in case worker-src is not expicitly specified
// If neither worker-src, nor child-src is present, then script-src
// needs to govern workers.
nsCSPChildSrcDirective* mChildSrc;
nsCSPDirective* mFrameSrc;
nsCSPDirective* mWorkerSrc;
nsCSPScriptSrcDirective* mScriptSrc;
// cache variable to let nsCSPHostSrc know that it's within
// the frame-ancestors directive.

Просмотреть файл

@ -232,7 +232,7 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType)
case nsIContentPolicy::TYPE_INTERNAL_WORKER:
case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER:
return nsIContentSecurityPolicy::CHILD_SRC_DIRECTIVE;
return nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE;
case nsIContentPolicy::TYPE_SUBDOCUMENT:
return nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE;
@ -1190,6 +1190,11 @@ nsCSPDirective::toDomCSPStruct(mozilla::dom::CSP& outCSP) const
outCSP.mSandbox.Value() = mozilla::Move(srcs);
return;
case nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE:
outCSP.mWorker_src.Construct();
outCSP.mWorker_src.Value() = mozilla::Move(srcs);
return;
// REFERRER_DIRECTIVE and REQUIRE_SRI_FOR are handled in nsCSPPolicy::toDomCSPStruct()
default:
@ -1242,7 +1247,8 @@ bool nsCSPDirective::equals(CSPDirective aDirective) const
nsCSPChildSrcDirective::nsCSPChildSrcDirective(CSPDirective aDirective)
: nsCSPDirective(aDirective)
, mHandleFrameSrc(false)
, mRestrictFrames(false)
, mRestrictWorkers(false)
{
}
@ -1250,30 +1256,58 @@ nsCSPChildSrcDirective::~nsCSPChildSrcDirective()
{
}
void nsCSPChildSrcDirective::setHandleFrameSrc()
{
mHandleFrameSrc = true;
}
bool nsCSPChildSrcDirective::restrictsContentType(nsContentPolicyType aContentType) const
{
if (aContentType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
return mHandleFrameSrc;
return mRestrictFrames;
}
return (aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER
|| aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER
|| aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER
);
if (aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER) {
return mRestrictWorkers;
}
return false;
}
bool nsCSPChildSrcDirective::equals(CSPDirective aDirective) const
{
if (aDirective == nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE) {
return mHandleFrameSrc;
return mRestrictFrames;
}
if (aDirective == nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE) {
return mRestrictWorkers;
}
return (mDirective == aDirective);
}
return (aDirective == nsIContentSecurityPolicy::CHILD_SRC_DIRECTIVE);
/* =============== nsCSPScriptSrcDirective ============= */
nsCSPScriptSrcDirective::nsCSPScriptSrcDirective(CSPDirective aDirective)
: nsCSPDirective(aDirective)
, mRestrictWorkers(false)
{
}
nsCSPScriptSrcDirective::~nsCSPScriptSrcDirective()
{
}
bool nsCSPScriptSrcDirective::restrictsContentType(nsContentPolicyType aContentType) const
{
if (aContentType == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
aContentType == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER ||
aContentType == nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER) {
return mRestrictWorkers;
}
return mDirective == CSP_ContentTypeToDirective(aContentType);
}
bool nsCSPScriptSrcDirective::equals(CSPDirective aDirective) const
{
if (aDirective == nsIContentSecurityPolicy::WORKER_SRC_DIRECTIVE) {
return mRestrictWorkers;
}
return (mDirective == aDirective);
}
/* =============== nsBlockAllMixedContentDirective ============= */

Просмотреть файл

@ -94,7 +94,8 @@ static const char* CSPStrDirectives[] = {
"child-src", // CHILD_SRC_DIRECTIVE
"block-all-mixed-content", // BLOCK_ALL_MIXED_CONTENT
"require-sri-for", // REQUIRE_SRI_FOR
"sandbox" // SANDBOX_DIRECTIVE
"sandbox", // SANDBOX_DIRECTIVE
"worker-src" // WORKER_SRC_DIRECTIVE
};
inline const char* CSP_CSPDirectiveToString(CSPDirective aDir)
@ -470,7 +471,7 @@ class nsCSPDirective {
bool visitSrcs(nsCSPSrcVisitor* aVisitor) const;
private:
protected:
CSPDirective mDirective;
nsTArray<nsCSPBaseSrc*> mSrcs;
};
@ -478,26 +479,52 @@ class nsCSPDirective {
/* =============== nsCSPChildSrcDirective ============= */
/*
* In CSP 2, the child-src directive covers both workers and
* subdocuments (i.e., frames and iframes). Workers were removed
* from script-src, but frames can be controlled by either child-src
* or frame-src directives, so child-src needs to know whether it should
* also restrict frames. When both are present the frame-src directive
* takes precedent.
* In CSP 3 child-src is deprecated. For backwards compatibility
* child-src needs to restrict:
* (*) frames, in case frame-src is not expicitly specified
* (*) workers, in case worker-src is not expicitly specified
*/
class nsCSPChildSrcDirective : public nsCSPDirective {
public:
explicit nsCSPChildSrcDirective(CSPDirective aDirective);
virtual ~nsCSPChildSrcDirective();
void setHandleFrameSrc();
void setRestrictFrames()
{ mRestrictFrames = true; }
void setRestrictWorkers()
{ mRestrictWorkers = true; }
virtual bool restrictsContentType(nsContentPolicyType aContentType) const;
virtual bool equals(CSPDirective aDirective) const;
private:
bool mHandleFrameSrc;
bool mRestrictFrames;
bool mRestrictWorkers;
};
/* =============== nsCSPScriptSrcDirective ============= */
/*
* In CSP 3 worker-src restricts workers, for backwards compatibily
* script-src has to restrict workers as the ultimate fallback if
* neither worker-src nor child-src is present in a CSP.
*/
class nsCSPScriptSrcDirective : public nsCSPDirective {
public:
explicit nsCSPScriptSrcDirective(CSPDirective aDirective);
virtual ~nsCSPScriptSrcDirective();
void setRestrictWorkers()
{ mRestrictWorkers = true; }
virtual bool restrictsContentType(nsContentPolicyType aContentType) const;
virtual bool equals(CSPDirective aDirective) const;
private:
bool mRestrictWorkers;
};
/* =============== nsBlockAllMixedContentDirective === */

Просмотреть файл

@ -30,6 +30,7 @@ dictionary CSP {
sequence<DOMString> block-all-mixed-content;
sequence<DOMString> require-sri-for;
sequence<DOMString> sandbox;
sequence<DOMString> worker-src;
};
dictionary CSPPolicies {