mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 965727 - Implement referrer directive for CSP. (r=jst,ckerschb)
This commit is contained in:
parent
6fad6fa0b3
commit
53bc033453
@ -2987,6 +2987,33 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
}
|
||||
}
|
||||
|
||||
// ----- Set up any Referrer Policy specified by CSP
|
||||
bool hasReferrerPolicy = false;
|
||||
uint32_t referrerPolicy = mozilla::net::RP_Default;
|
||||
rv = csp->GetReferrerPolicy(&referrerPolicy, &hasReferrerPolicy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (hasReferrerPolicy) {
|
||||
// Referrer policy spec (section 6.1) says that once the referrer policy
|
||||
// is set, any future attempts to change it result in No-Referrer.
|
||||
if (!mReferrerPolicySet) {
|
||||
mReferrerPolicy = static_cast<ReferrerPolicy>(referrerPolicy);
|
||||
mReferrerPolicySet = true;
|
||||
} else if (mReferrerPolicy != referrerPolicy) {
|
||||
mReferrerPolicy = mozilla::net::RP_No_Referrer;
|
||||
#ifdef PR_LOGGING
|
||||
{
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("%s %s",
|
||||
"CSP wants to set referrer, but nsDocument"
|
||||
"already has it set. No referrers will be sent"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Referrer Policy is set separately for the speculative parser in
|
||||
// nsHTMLDocument::StartDocumentLoad() so there's nothing to do here for
|
||||
// speculative loads.
|
||||
}
|
||||
|
||||
rv = principal->SetCsp(csp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -673,10 +673,15 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
|
||||
|
||||
nsCOMPtr<nsIWyciwygChannel> wyciwygChannel;
|
||||
|
||||
// For error reporting
|
||||
// For error reporting and referrer policy setting
|
||||
nsHtml5TreeOpExecutor* executor = nullptr;
|
||||
if (loadAsHtml5) {
|
||||
executor = static_cast<nsHtml5TreeOpExecutor*> (mParser->GetContentSink());
|
||||
if (mReferrerPolicySet) {
|
||||
// CSP may have set the referrer policy, so a speculative parser should
|
||||
// start with the new referrer policy.
|
||||
executor->SetSpeculationReferrerPolicy(static_cast<ReferrerPolicy>(mReferrerPolicy));
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsHTML() || !docShell) { // no docshell for text/html XHR
|
||||
@ -1641,6 +1646,15 @@ nsHTMLDocument::Open(JSContext* cx,
|
||||
mParserAborted = false;
|
||||
mParser = nsHtml5Module::NewHtml5Parser();
|
||||
nsHtml5Module::Initialize(mParser, this, uri, shell, channel);
|
||||
if (mReferrerPolicySet) {
|
||||
// CSP may have set the referrer policy, so a speculative parser should
|
||||
// start with the new referrer policy.
|
||||
nsHtml5TreeOpExecutor* executor = nullptr;
|
||||
executor = static_cast<nsHtml5TreeOpExecutor*> (mParser->GetContentSink());
|
||||
if (executor && mReferrerPolicySet) {
|
||||
executor->SetSpeculationReferrerPolicy(static_cast<ReferrerPolicy>(mReferrerPolicy));
|
||||
}
|
||||
}
|
||||
|
||||
// This will be propagated to the parser when someone actually calls write()
|
||||
SetContentTypeInternal(contentType);
|
||||
|
@ -20,7 +20,7 @@ interface nsIURI;
|
||||
|
||||
typedef unsigned short CSPDirective;
|
||||
|
||||
[scriptable, uuid(69b7663e-117a-4a3b-81bd-d86420b7c79e)]
|
||||
[scriptable, uuid(68434447-b816-4473-a731-efc4f6d59902)]
|
||||
interface nsIContentSecurityPolicy : nsISerializable
|
||||
{
|
||||
/**
|
||||
@ -47,6 +47,7 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
const unsigned short REFLECTED_XSS_DIRECTIVE = 12;
|
||||
const unsigned short BASE_URI_DIRECTIVE = 13;
|
||||
const unsigned short FORM_ACTION_DIRECTIVE = 14;
|
||||
const unsigned short REFERRER_DIRECTIVE = 15;
|
||||
|
||||
/**
|
||||
* Accessor method for a read-only string version of the policy at a given
|
||||
@ -60,6 +61,21 @@ interface nsIContentSecurityPolicy : nsISerializable
|
||||
*/
|
||||
readonly attribute unsigned long policyCount;
|
||||
|
||||
/**
|
||||
* Obtains the referrer policy (as integer) for this browsing context as
|
||||
* specified in CSP. If there are multiple policies and...
|
||||
* - only one sets a referrer policy: that policy is returned
|
||||
* - more than one sets different referrer policies: no-referrer is returned
|
||||
* - more than one set equivalent policies: that policy is returned
|
||||
* For the enumeration of policies see ReferrerPolicy.h and nsIHttpChannel.
|
||||
*
|
||||
* @param aPolicy
|
||||
* The referrer policy to use for the protected resource.
|
||||
* @return
|
||||
* true if a referrer policy is specified, false if it's unspecified.
|
||||
*/
|
||||
bool getReferrerPolicy(out unsigned long policy);
|
||||
|
||||
/**
|
||||
* Remove a policy associated with this CSP context.
|
||||
* @throws NS_ERROR_FAILURE if the index is out of bounds or invalid.
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "nsString.h"
|
||||
#include "prlog.h"
|
||||
#include "mozilla/dom/CSPReportBinding.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -305,6 +306,34 @@ nsCSPContext::GetPolicyCount(uint32_t *outPolicyCount)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCSPContext::GetReferrerPolicy(uint32_t* outPolicy, bool* outIsSet)
|
||||
{
|
||||
*outIsSet = false;
|
||||
*outPolicy = mozilla::net::RP_Default;
|
||||
nsAutoString refpol;
|
||||
mozilla::net::ReferrerPolicy previousPolicy = mozilla::net::RP_Default;
|
||||
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
||||
mPolicies[i]->getReferrerPolicy(refpol);
|
||||
// an empty string in refpol means it wasn't set (that's the default in
|
||||
// nsCSPPolicy).
|
||||
if (!refpol.IsEmpty()) {
|
||||
// if there are two policies that specify a referrer policy, then they
|
||||
// must agree or the employed policy is no-referrer.
|
||||
uint32_t currentPolicy = mozilla::net::ReferrerPolicyFromString(refpol);
|
||||
if (*outIsSet && previousPolicy != currentPolicy) {
|
||||
*outPolicy = mozilla::net::RP_No_Referrer;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*outPolicy = currentPolicy;
|
||||
*outIsSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCSPContext::RemovePolicy(uint32_t aIndex)
|
||||
{
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -857,6 +858,30 @@ nsCSPParser::sourceList(nsTArray<nsCSPBaseSrc*>& outSrcs)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsCSPParser::referrerDirectiveValue()
|
||||
{
|
||||
// directive-value = "none" / "none-when-downgrade" / "origin" / "origin-when-cross-origin" / "unsafe-url"
|
||||
// directive name is token 0, we need to examine the remaining tokens (and
|
||||
// there should only be one token in the value).
|
||||
CSPPARSERLOG(("nsCSPParser::referrerDirectiveValue"));
|
||||
|
||||
if (mCurDir.Length() > 2) {
|
||||
CSPPARSERLOG(("Too many tokens in referrer directive, got %d expected 1",
|
||||
mCurDir.Length() - 1));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mozilla::net::IsValidReferrerPolicy(mCurDir[1])) {
|
||||
CSPPARSERLOG(("invalid value for referrer directive: %s",
|
||||
NS_ConvertUTF16toUTF8(mCurDir[1]).get()));
|
||||
return;
|
||||
}
|
||||
|
||||
// the referrer policy is valid, so go ahead and use it.
|
||||
mPolicy->setReferrerPolicy(&mCurDir[1]);
|
||||
}
|
||||
|
||||
void
|
||||
nsCSPParser::reportURIList(nsTArray<nsCSPBaseSrc*>& outSrcs)
|
||||
{
|
||||
@ -900,6 +925,14 @@ nsCSPParser::directiveValue(nsTArray<nsCSPBaseSrc*>& outSrcs)
|
||||
reportURIList(outSrcs);
|
||||
return;
|
||||
}
|
||||
|
||||
// special case handling of the referrer directive (since it doesn't contain
|
||||
// source lists)
|
||||
if (CSP_IsDirective(mCurDir[0], nsIContentSecurityPolicy::REFERRER_DIRECTIVE)) {
|
||||
referrerDirectiveValue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise just forward to sourceList
|
||||
sourceList(outSrcs);
|
||||
}
|
||||
|
@ -113,6 +113,7 @@ class nsCSPParser {
|
||||
void directive();
|
||||
nsCSPDirective* directiveName();
|
||||
void directiveValue(nsTArray<nsCSPBaseSrc*>& outSrcs);
|
||||
void referrerDirectiveValue();
|
||||
void sourceList(nsTArray<nsCSPBaseSrc*>& outSrcs);
|
||||
nsCSPBaseSrc* sourceExpression();
|
||||
nsCSPSchemeSrc* schemeSource();
|
||||
|
@ -899,7 +899,14 @@ nsCSPPolicy::toString(nsAString& outStr) const
|
||||
{
|
||||
uint32_t length = mDirectives.Length();
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
mDirectives[i]->toString(outStr);
|
||||
|
||||
if (mDirectives[i]->equals(nsIContentSecurityPolicy::REFERRER_DIRECTIVE)) {
|
||||
outStr.AppendASCII(CSP_CSPDirectiveToString(nsIContentSecurityPolicy::REFERRER_DIRECTIVE));
|
||||
outStr.AppendASCII(" ");
|
||||
outStr.Append(mReferrerPolicy);
|
||||
} else {
|
||||
mDirectives[i]->toString(outStr);
|
||||
}
|
||||
if (i != (length - 1)) {
|
||||
outStr.AppendASCII("; ");
|
||||
}
|
||||
|
@ -73,7 +73,8 @@ static const char* CSPStrDirectives[] = {
|
||||
"frame-ancestors", // FRAME_ANCESTORS_DIRECTIVE
|
||||
"reflected-xss", // REFLECTED_XSS_DIRECTIVE
|
||||
"base-uri", // BASE_URI_DIRECTIVE
|
||||
"form-action" // FORM_ACTION_DIRECTIVE
|
||||
"form-action", // FORM_ACTION_DIRECTIVE
|
||||
"referrer" // REFERRER_DIRECTIVE
|
||||
};
|
||||
|
||||
inline const char* CSP_CSPDirectiveToString(CSPDirective aDir)
|
||||
@ -332,6 +333,12 @@ class nsCSPPolicy {
|
||||
inline bool getReportOnlyFlag() const
|
||||
{ return mReportOnly; }
|
||||
|
||||
inline void setReferrerPolicy(const nsAString* aValue)
|
||||
{ mReferrerPolicy = *aValue; }
|
||||
|
||||
inline void getReferrerPolicy(nsAString& outPolicy) const
|
||||
{ outPolicy.Assign(mReferrerPolicy); }
|
||||
|
||||
void getReportURIs(nsTArray<nsString> &outReportURIs) const;
|
||||
|
||||
void getDirectiveStringForContentType(nsContentPolicyType aContentType,
|
||||
@ -345,6 +352,7 @@ class nsCSPPolicy {
|
||||
private:
|
||||
nsTArray<nsCSPDirective*> mDirectives;
|
||||
bool mReportOnly;
|
||||
nsString mReferrerPolicy;
|
||||
};
|
||||
|
||||
#endif /* nsCSPUtils_h___ */
|
||||
|
@ -56,6 +56,19 @@ ReferrerPolicyFromString(const nsAString& content)
|
||||
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsValidReferrerPolicy(const nsAString& content)
|
||||
{
|
||||
return content.LowerCaseEqualsLiteral("never")
|
||||
|| content.LowerCaseEqualsLiteral("no-referrer")
|
||||
|| content.LowerCaseEqualsLiteral("origin")
|
||||
|| content.LowerCaseEqualsLiteral("default")
|
||||
|| content.LowerCaseEqualsLiteral("no-referrer-when-downgrade")
|
||||
|| content.LowerCaseEqualsLiteral("origin-when-crossorigin")
|
||||
|| content.LowerCaseEqualsLiteral("always")
|
||||
|| content.LowerCaseEqualsLiteral("unsafe-url");
|
||||
}
|
||||
|
||||
} } //namespace mozilla::net
|
||||
|
||||
#endif
|
||||
|
@ -960,9 +960,14 @@ void
|
||||
nsHtml5TreeOpExecutor::SetSpeculationReferrerPolicy(const nsAString& aReferrerPolicy)
|
||||
{
|
||||
ReferrerPolicy policy = mozilla::net::ReferrerPolicyFromString(aReferrerPolicy);
|
||||
return SetSpeculationReferrerPolicy(policy);
|
||||
}
|
||||
|
||||
void
|
||||
nsHtml5TreeOpExecutor::SetSpeculationReferrerPolicy(ReferrerPolicy aReferrerPolicy)
|
||||
{
|
||||
if (mSpeculationReferrerPolicyWasSet &&
|
||||
policy != mSpeculationReferrerPolicy) {
|
||||
aReferrerPolicy != mSpeculationReferrerPolicy) {
|
||||
// According to the Referrer Policy spec, if there's already been a policy
|
||||
// set and another attempt is made to set a _different_ policy, the result
|
||||
// is a "No Referrer" policy.
|
||||
@ -973,7 +978,7 @@ nsHtml5TreeOpExecutor::SetSpeculationReferrerPolicy(const nsAString& aReferrerPo
|
||||
// speculation phase. The actual referrer policy will be set by
|
||||
// HTMLMetaElement::BindToTree().
|
||||
mSpeculationReferrerPolicyWasSet = true;
|
||||
mSpeculationReferrerPolicy = policy;
|
||||
mSpeculationReferrerPolicy = aReferrerPolicy;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,6 +266,7 @@ class nsHtml5TreeOpExecutor MOZ_FINAL : public nsHtml5DocumentBuilder,
|
||||
|
||||
void SetSpeculationBase(const nsAString& aURL);
|
||||
|
||||
void SetSpeculationReferrerPolicy(ReferrerPolicy aReferrerPolicy);
|
||||
void SetSpeculationReferrerPolicy(const nsAString& aReferrerPolicy);
|
||||
|
||||
void AddBase(const nsAString& aURL);
|
||||
|
Loading…
Reference in New Issue
Block a user