summaryrefslogtreecommitdiff
path: root/netwerk/protocol
diff options
context:
space:
mode:
authorJob Bautista <jobbautista9@protonmail.com>2022-07-25 18:56:46 +0800
committerJob Bautista <jobbautista9@protonmail.com>2022-07-25 18:56:46 +0800
commitb20b9797dcb42766f9ad114e3093cb241f4258a0 (patch)
tree3b15dbc4ab2ff9705755974a86c0ee8e2023b264 /netwerk/protocol
parent6542ca6bcdf836ee1fb82b75d77adb0e9604b97b (diff)
downloaduxp-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.cpp36
-rw-r--r--netwerk/protocol/http/HttpBaseChannel.h2
-rw-r--r--netwerk/protocol/http/nsHttpAtomList.h1
-rw-r--r--netwerk/protocol/http/nsHttpChannel.cpp53
-rw-r--r--netwerk/protocol/http/nsHttpChannel.h1
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: