From cc64995f754d2104dc5189bb45851ee870faf20c Mon Sep 17 00:00:00 2001 From: Junior Hsu Date: Fri, 14 Jun 2019 22:24:33 +0000 Subject: [PATCH] Bug 1504085 - P2 Let Origin: honor ReferrerPolicy for non-CORS r=tnguyen,valentin Differential Revision: https://phabricator.services.mozilla.com/D34454 --HG-- extra : moz-landing-system : lando --- dom/security/ReferrerInfo.cpp | 42 +++++++++++++++++++++++++ dom/security/ReferrerInfo.h | 7 +++++ netwerk/protocol/http/nsHttpChannel.cpp | 17 ++++++++-- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/dom/security/ReferrerInfo.cpp b/dom/security/ReferrerInfo.cpp index 665b950dc0a3..747002ff6472 100644 --- a/dom/security/ReferrerInfo.cpp +++ b/dom/security/ReferrerInfo.cpp @@ -338,6 +338,48 @@ nsresult ReferrerInfo::HandleUserXOriginSendingPolicy(nsIURI* aURI, return NS_OK; } +/* static */ +bool ReferrerInfo::ShouldSetNullOriginHeader(net::HttpBaseChannel* aChannel, + nsIURI* aOriginURI) { + MOZ_ASSERT(aChannel); + MOZ_ASSERT(aOriginURI); + + // When we're dealing with CORS (mode is "cors"), we shouldn't take the + // Referrer-Policy into account + uint32_t corsMode = CORS_NONE; + NS_ENSURE_SUCCESS(aChannel->GetCorsMode(&corsMode), false); + if (corsMode == CORS_USE_CREDENTIALS) { + return false; + } + + nsCOMPtr referrerInfo; + NS_ENSURE_SUCCESS(aChannel->GetReferrerInfo(getter_AddRefs(referrerInfo)), + false); + if (!referrerInfo) { + return false; + } + uint32_t policy = referrerInfo->GetReferrerPolicy(); + if (policy == nsIHttpChannel::REFERRER_POLICY_NO_REFERRER) { + return true; + } + + bool allowed = false; + nsCOMPtr uri; + NS_ENSURE_SUCCESS(aChannel->GetURI(getter_AddRefs(uri)), false); + + if (NS_SUCCEEDED(ReferrerInfo::HandleSecureToInsecureReferral( + aOriginURI, uri, policy, allowed)) && + !allowed) { + return true; + } + + if (policy == nsIHttpChannel::REFERRER_POLICY_SAME_ORIGIN) { + return ReferrerInfo::IsCrossOriginRequest(aChannel); + } + + return false; +} + nsresult ReferrerInfo::HandleUserReferrerSendingPolicy(nsIHttpChannel* aChannel, bool& aAllowed) const { aAllowed = false; diff --git a/dom/security/ReferrerInfo.h b/dom/security/ReferrerInfo.h index fd29a98668cd..b906eefafb22 100644 --- a/dom/security/ReferrerInfo.h +++ b/dom/security/ReferrerInfo.h @@ -117,6 +117,13 @@ class ReferrerInfo : public nsIReferrerInfo { */ static bool IsCrossOriginRequest(nsIHttpChannel* aChannel); + /** + * Returns true if the given channel is suppressed by Referrer-Policy header + * and should set "null" to Origin header. + */ + static bool ShouldSetNullOriginHeader(net::HttpBaseChannel* aChannel, + nsIURI* aOriginURI); + /** * Return default referrer policy which is controlled by user * prefs: diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index d923b5279021..581e19fa7bcc 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -9720,15 +9720,24 @@ void nsHttpChannel::SetOriginHeader() { if (mRequestHead.IsGet() || mRequestHead.IsHead()) { return; } + nsresult rv; + nsAutoCString existingHeader; Unused << mRequestHead.GetHeader(nsHttp::Origin, existingHeader); if (!existingHeader.IsEmpty()) { LOG(("nsHttpChannel::SetOriginHeader Origin header already present")); + nsCOMPtr uri; + rv = NS_NewURI(getter_AddRefs(uri), existingHeader); + if (NS_SUCCEEDED(rv) && + ReferrerInfo::ShouldSetNullOriginHeader(this, uri)) { + LOG(("nsHttpChannel::SetOriginHeader null Origin by Referrer-Policy")); + rv = mRequestHead.SetHeader(nsHttp::Origin, NS_LITERAL_CSTRING("null"), + false /* merge */); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + } return; } - DebugOnly rv; - // Instead of consulting Preferences::GetInt() all the time we // can cache the result to speed things up. static int32_t sSendOriginHeader = 0; @@ -9773,6 +9782,10 @@ void nsHttpChannel::SetOriginHeader() { } } + if (referrer && ReferrerInfo::ShouldSetNullOriginHeader(this, referrer)) { + origin.AssignLiteral("null"); + } + rv = mRequestHead.SetHeader(nsHttp::Origin, origin, false /* merge */); MOZ_ASSERT(NS_SUCCEEDED(rv)); }