diff options
author | Job Bautista <jobbautista9@protonmail.com> | 2022-07-25 18:56:46 +0800 |
---|---|---|
committer | Job Bautista <jobbautista9@protonmail.com> | 2022-07-25 18:56:46 +0800 |
commit | b20b9797dcb42766f9ad114e3093cb241f4258a0 (patch) | |
tree | 3b15dbc4ab2ff9705755974a86c0ee8e2023b264 /netwerk/protocol | |
parent | 6542ca6bcdf836ee1fb82b75d77adb0e9604b97b (diff) | |
download | uxp-b20b9797dcb42766f9ad114e3093cb241f4258a0.tar.gz |
Issue #1975 - Implement Origin header CSRF mitigation.
Backported from Mozilla bug 446344.
Diffstat (limited to 'netwerk/protocol')
-rw-r--r-- | netwerk/protocol/http/HttpBaseChannel.cpp | 36 | ||||
-rw-r--r-- | netwerk/protocol/http/HttpBaseChannel.h | 2 | ||||
-rw-r--r-- | netwerk/protocol/http/nsHttpAtomList.h | 1 | ||||
-rw-r--r-- | netwerk/protocol/http/nsHttpChannel.cpp | 53 | ||||
-rw-r--r-- | netwerk/protocol/http/nsHttpChannel.h | 1 |
5 files changed, 78 insertions, 15 deletions
diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index e62ec3a2e7..0b4929bbc8 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -1398,22 +1398,10 @@ HttpBaseChannel::SetReferrerWithPolicy(nsIURI *referrer, referrer = referrerGrip.get(); } - // - // block referrer if not on our white list... - // - static const char *const referrerWhiteList[] = { - "http", - "https", - "ftp", - nullptr - }; - match = false; - const char *const *scheme = referrerWhiteList; - for (; *scheme && !match; ++scheme) { - rv = referrer->SchemeIs(*scheme, &match); - if (NS_FAILED(rv)) return rv; + // Enforce Referrer whitelist + if (!IsReferrerSchemeAllowed(referrer)) { + return NS_OK; // kick out.... } - if (!match) return NS_OK; // kick out.... // // Handle secure referrals. @@ -2844,6 +2832,24 @@ HttpBaseChannel::AddCookiesToRequest() SetRequestHeader(nsDependentCString(nsHttp::Cookie), cookie, false); } +/* static */ +bool +HttpBaseChannel::IsReferrerSchemeAllowed(nsIURI *aReferrer) +{ + NS_ENSURE_TRUE(aReferrer, false); + + nsAutoCString scheme; + nsresult rv = aReferrer->GetScheme(scheme); + NS_ENSURE_SUCCESS(rv, false); + + if (scheme.EqualsIgnoreCase("https") || + scheme.EqualsIgnoreCase("http") || + scheme.EqualsIgnoreCase("ftp")) { + return true; + } + return false; +} + bool HttpBaseChannel::ShouldRewriteRedirectToGET(uint32_t httpStatus, nsHttpRequestHead::ParsedMethodType method) diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index 6b28eb455c..c915e86622 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -319,6 +319,8 @@ public: public: /* Necko internal use only... */ bool IsNavigation(); + static bool IsReferrerSchemeAllowed(nsIURI *aReferrer); + // Return whether upon a redirect code of httpStatus for method, the // request method should be rewritten to GET. static bool ShouldRewriteRedirectToGET(uint32_t httpStatus, diff --git a/netwerk/protocol/http/nsHttpAtomList.h b/netwerk/protocol/http/nsHttpAtomList.h index 867ac0010d..e4b22e8da3 100644 --- a/netwerk/protocol/http/nsHttpAtomList.h +++ b/netwerk/protocol/http/nsHttpAtomList.h @@ -64,6 +64,7 @@ HTTP_ATOM(Lock_Token, "Lock-Token") HTTP_ATOM(Link, "Link") HTTP_ATOM(Location, "Location") HTTP_ATOM(Max_Forwards, "Max-Forwards") +HTTP_ATOM(Origin, "Origin") HTTP_ATOM(Overwrite, "Overwrite") HTTP_ATOM(Pragma, "Pragma") HTTP_ATOM(Prefer, "Prefer") diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 915a80fb68..ca2644f6ab 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -5710,6 +5710,7 @@ nsHttpChannel::BeginConnect() mRequestHead.SetHTTPS(isHttps); mRequestHead.SetOrigin(scheme, host, port); + SetOriginHeader(); SetGPC(); NeckoOriginAttributes originAttributes; @@ -7936,6 +7937,58 @@ nsHttpChannel::ResumeInternal() return NS_FAILED(rvTransaction) ? rvTransaction : rvCache; } +// Step 10 of HTTP-network-or-cache fetch +void +nsHttpChannel::SetOriginHeader() +{ + if (mRequestHead.IsGet() || mRequestHead.IsHead()) { + return; + } + nsAutoCString existingHeader; + Unused << mRequestHead.GetHeader(nsHttp::Origin, existingHeader); + if (!existingHeader.IsEmpty()) { + LOG(("nsHttpChannel::SetOriginHeader Origin header already present")); + return; + } + + DebugOnly<nsresult> rv; + + // Instead of consulting Preferences::GetInt() all the time we + // can cache the result to speed things up. + static int32_t sSendOriginHeader = 0; + static bool sIsInited = false; + if (!sIsInited) { + sIsInited = true; + Preferences::AddIntVarCache(&sSendOriginHeader, + "network.http.sendOriginHeader"); + } + if (sSendOriginHeader == 0) { + // Origin header suppressed by user setting + return; + } + + nsCOMPtr<nsIURI> referrer; + mLoadInfo->TriggeringPrincipal()->GetURI(getter_AddRefs(referrer)); + + nsAutoCString origin("null"); + if (referrer && IsReferrerSchemeAllowed(referrer)) { + nsContentUtils::GetASCIIOrigin(referrer, origin); + } + + // Restrict Origin to same-origin loads if requested by user + if (sSendOriginHeader == 1) { + nsAutoCString currentOrigin; + nsContentUtils::GetASCIIOrigin(mURI, currentOrigin); + if (!origin.EqualsIgnoreCase(currentOrigin.get())) { + // Origin header suppressed by user setting + return; + } + } + + rv = mRequestHead.SetHeader(nsHttp::Origin, origin, false /* merge */); + MOZ_ASSERT(NS_SUCCEEDED(rv)); +} + void nsHttpChannel::SetGPC() { diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index 6e0680178c..2681f34764 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -452,6 +452,7 @@ private: void SetPushedStream(Http2PushedStreamWrapper *stream); + void SetOriginHeader(); void SetGPC(); private: |