mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 02:14:43 +00:00
Bug 1817980 - replace ReferrerInfo::IsCrossOriginRequest with nsScriptSecurityManager::CheckSameOriginURI for determining cross-origin redirects. r=necko-reviewers,valentin
Since Bug 1802086, we strip authentication headers when redirected to a cross-origin page. However, the api ReferrerInfo::IsCrossOriginRequest used for determining whether a request is cross-origin cannot be used as it compares the triggering principal's uri with the redirected channel's uri. This comparison might sometimes yield to false positives. For e.g consider the following scenario: 1. Load `https://example.org/` and send the following fetch request from browser console ``` fetch("https://test.com/some_location", { "headers": { "Authorization": "Token foo" } }); ``` 2. Server responds with a redirect to https://test.com/another_location In the above scenario, the api ReferrerInfo::IsCrossOriginRequest will yield the above request as cross origin since the triggering principal uri here is example.com. Hence, this will be treated as cross-origin redirect resulting in removal of auth headers. Thus ReferrerInfo::IsCrossOriginRequest has been replaced with nsScriptSecurityManager::CheckSameOriginURI where we directly compare the origins for the two requests. Differential Revision: https://phabricator.services.mozilla.com/D170868
This commit is contained in:
parent
fb969de225
commit
3ae22e6d6f
@ -1540,7 +1540,20 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
|
||||
// Ref: https://fetch.spec.whatwg.org/#http-redirect-fetch
|
||||
bool skipAuthHeader = false;
|
||||
if (StaticPrefs::network_fetch_redirect_stripAuthHeader()) {
|
||||
skipAuthHeader = ReferrerInfo::IsCrossOriginRequest(oldHttpChannel);
|
||||
nsCOMPtr<nsIURI> oldUri;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldUri)));
|
||||
|
||||
nsCOMPtr<nsIURI> newUri;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newUri)));
|
||||
|
||||
nsresult rv = nsContentUtils::GetSecurityManager()->CheckSameOriginURI(
|
||||
newUri, oldUri, false, false);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
skipAuthHeader = true;
|
||||
}
|
||||
}
|
||||
|
||||
SetRequestHeaders(newHttpChannel, rewriteToGET, skipAuthHeader);
|
||||
|
@ -3361,7 +3361,20 @@ nsresult XMLHttpRequestMainThread::OnRedirectVerifyCallback(nsresult result) {
|
||||
// Ref: https://fetch.spec.whatwg.org/#http-redirect-fetch
|
||||
bool skipAuthHeader = false;
|
||||
if (StaticPrefs::network_fetch_redirect_stripAuthHeader()) {
|
||||
skipAuthHeader = ReferrerInfo::IsCrossOriginRequest(oldHttpChannel);
|
||||
nsCOMPtr<nsIURI> oldUri;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
NS_GetFinalChannelURI(oldHttpChannel, getter_AddRefs(oldUri)));
|
||||
|
||||
nsCOMPtr<nsIURI> newUri;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
NS_GetFinalChannelURI(newHttpChannel, getter_AddRefs(newUri)));
|
||||
|
||||
nsresult rv = nsContentUtils::GetSecurityManager()->CheckSameOriginURI(
|
||||
newUri, oldUri, false, false);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
skipAuthHeader = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure all original headers are duplicated for the new channel (bug
|
||||
|
@ -4933,13 +4933,35 @@ nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI* newURI,
|
||||
if (StaticPrefs::network_http_redirect_stripAuthHeader() &&
|
||||
NS_SUCCEEDED(
|
||||
httpChannel->GetRequestHeader("Authorization"_ns, authHeader))) {
|
||||
rv = httpChannel->SetRequestHeader("Authorization"_ns, ""_ns, false);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (!IsNewChannelSameOrigin(httpChannel)) {
|
||||
rv = httpChannel->SetRequestHeader("Authorization"_ns, ""_ns, false);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// check whether the new channel is of same origin as the current channel
|
||||
bool HttpBaseChannel::IsNewChannelSameOrigin(nsIChannel* aNewChannel) {
|
||||
bool isSameOrigin = false;
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
|
||||
if (!ssm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
|
||||
|
||||
nsresult rv = ssm->CheckSameOriginURI(newURI, mURI, false, false);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
isSameOrigin = true;
|
||||
}
|
||||
|
||||
return isSameOrigin;
|
||||
}
|
||||
|
||||
bool HttpBaseChannel::ShouldTaintReplacementChannelOrigin(
|
||||
nsIChannel* aNewChannel, uint32_t aRedirectFlags) {
|
||||
if (LoadTaintedOriginFlag()) {
|
||||
@ -4951,19 +4973,13 @@ bool HttpBaseChannel::ShouldTaintReplacementChannelOrigin(
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
if (!ssm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
|
||||
nsresult rv = ssm->CheckSameOriginURI(newURI, mURI, false, false);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// If new channel is not of same origin we need to taint unless
|
||||
// mURI <-> mOriginalURI/LoadingPrincipal are same origin.
|
||||
if (IsNewChannelSameOrigin(aNewChannel)) {
|
||||
return false;
|
||||
}
|
||||
// If newURI <-> mURI are not same-origin we need to taint unless
|
||||
// mURI <-> mOriginalURI/LoadingPrincipal are same origin.
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (mLoadInfo->GetLoadingPrincipal()) {
|
||||
bool sameOrigin = false;
|
||||
@ -4977,6 +4993,11 @@ bool HttpBaseChannel::ShouldTaintReplacementChannelOrigin(
|
||||
return true;
|
||||
}
|
||||
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
if (!ssm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
rv = ssm->CheckSameOriginURI(mOriginalURI, mURI, false, false);
|
||||
return NS_FAILED(rv);
|
||||
}
|
||||
|
@ -577,6 +577,8 @@ class HttpBaseChannel : public nsHashPropertyBag,
|
||||
[[nodiscard]] virtual nsresult SetupReplacementChannel(
|
||||
nsIURI*, nsIChannel*, bool preserveMethod, uint32_t redirectFlags);
|
||||
|
||||
bool IsNewChannelSameOrigin(nsIChannel* aNewChannel);
|
||||
|
||||
// WHATWG Fetch Standard 4.4. HTTP-redirect fetch, step 10
|
||||
virtual bool ShouldTaintReplacementChannelOrigin(nsIChannel* aNewChannel,
|
||||
uint32_t aRedirectFlags);
|
||||
|
@ -16,7 +16,10 @@ promise_test(async test => {
|
||||
}, "getAuthorizationHeaderValue - no redirection");
|
||||
|
||||
promise_test(async test => {
|
||||
const result = await getAuthorizationHeaderValue("/fetch/api/resources/redirect.py?location=" + encodeURIComponent("/fetch/api/resources/dump-authorization-header.py"));
|
||||
result = await getAuthorizationHeaderValue("/fetch/api/resources/redirect.py?location=" + encodeURIComponent("/fetch/api/resources/dump-authorization-header.py"));
|
||||
assert_equals(result, authorizationValue);
|
||||
|
||||
result = await getAuthorizationHeaderValue(get_host_info().HTTPS_REMOTE_ORIGIN + "/fetch/api/resources/redirect.py?allow_headers=Authorization&location=" + encodeURIComponent(get_host_info().HTTPS_REMOTE_ORIGIN + "/fetch/api/resources/dump-authorization-header.py"));
|
||||
assert_equals(result, authorizationValue);
|
||||
}, "getAuthorizationHeaderValue - same origin redirection");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user