Bug 1790311 - update handling of request headers in Fetch/XHR. r=necko-reviewers,valentin

Differential Revision: https://phabricator.services.mozilla.com/D157729
This commit is contained in:
sunil mayya 2022-10-24 09:17:22 +00:00
parent 6fa764c7d3
commit 5bc9f5b9ac
6 changed files with 66 additions and 17 deletions

View File

@ -7311,15 +7311,25 @@ bool nsContentUtils::IsNodeInEditableRegion(nsINode* aNode) {
}
// static
bool nsContentUtils::IsForbiddenRequestHeader(const nsACString& aHeader) {
bool nsContentUtils::IsForbiddenRequestHeader(const nsACString& aHeader,
const nsACString& aValue) {
if (IsForbiddenSystemRequestHeader(aHeader)) {
return true;
}
return StringBeginsWith(aHeader, "proxy-"_ns,
if ((nsContentUtils::IsOverrideMethodHeader(aHeader) &&
nsContentUtils::ContainsForbiddenMethod(aValue))) {
return true;
}
if (StringBeginsWith(aHeader, "proxy-"_ns,
nsCaseInsensitiveCStringComparator) ||
StringBeginsWith(aHeader, "sec-"_ns,
nsCaseInsensitiveCStringComparator);
nsCaseInsensitiveCStringComparator)) {
return true;
}
return false;
}
// static
@ -7359,6 +7369,31 @@ bool nsContentUtils::IsForbiddenResponseHeader(const nsACString& aHeader) {
aHeader.LowerCaseEqualsASCII("set-cookie2"));
}
// static
bool nsContentUtils::IsOverrideMethodHeader(const nsACString& headerName) {
return headerName.EqualsIgnoreCase("x-http-method-override") ||
headerName.EqualsIgnoreCase("x-http-method") ||
headerName.EqualsIgnoreCase("x-method-override");
}
// static
bool nsContentUtils::ContainsForbiddenMethod(const nsACString& headerValue) {
bool hasInsecureMethod = false;
nsCCharSeparatedTokenizer tokenizer(headerValue, ',');
while (tokenizer.hasMoreTokens()) {
const nsDependentCSubstring& value = tokenizer.nextToken();
if (value.EqualsIgnoreCase("connect") || value.EqualsIgnoreCase("trace") ||
value.EqualsIgnoreCase("track")) {
hasInsecureMethod = true;
break;
}
}
return hasInsecureMethod;
}
// static
bool nsContentUtils::IsCorsUnsafeRequestHeaderValue(
const nsACString& aHeaderValue) {

View File

@ -2764,7 +2764,8 @@ class nsContentUtils {
* Returns whether a given header is forbidden for an XHR or fetch
* request.
*/
static bool IsForbiddenRequestHeader(const nsACString& aHeader);
static bool IsForbiddenRequestHeader(const nsACString& aHeader,
const nsACString& aValue);
/**
* Returns whether a given header is forbidden for a system XHR
@ -2772,6 +2773,14 @@ class nsContentUtils {
*/
static bool IsForbiddenSystemRequestHeader(const nsACString& aHeader);
/**
* Checks whether the header overrides any http methods
*/
static bool IsOverrideMethodHeader(const nsACString& headerName);
/**
* Checks whether the header value contains any forbidden method
*/
static bool ContainsForbiddenMethod(const nsACString& headerValue);
/**
* Returns whether a given header has characters that aren't permitted
*/

View File

@ -37,7 +37,6 @@ class FetchUtil final {
*/
static nsresult GetValidRequestMethod(const nsACString& aMethod,
nsCString& outMethod);
/**
* Extracts an HTTP header from a substring range.
*/

View File

@ -6,6 +6,7 @@
#include "mozilla/dom/InternalHeaders.h"
#include "FetchUtil.h"
#include "mozilla/dom/FetchTypes.h"
#include "mozilla/ErrorResult.h"
@ -56,11 +57,11 @@ bool InternalHeaders::IsValidHeaderValue(const nsCString& aLowerName,
}
// Step 4
if (mGuard == HeadersGuardEnum::Request &&
IsForbiddenRequestHeader(aLowerName)) {
if (mGuard == HeadersGuardEnum::Request) {
if (IsForbiddenRequestHeader(aLowerName, aNormalizedValue)) {
return false;
}
}
// Step 5
if (mGuard == HeadersGuardEnum::Request_no_cors) {
nsAutoCString tempValue;
@ -161,7 +162,9 @@ void InternalHeaders::Delete(const nsACString& aName, ErrorResult& aRv) {
}
// Step 3
if (IsForbiddenRequestHeader(lowerName)) {
nsAutoCString value;
GetInternal(lowerName, value, aRv);
if (IsForbiddenRequestHeader(lowerName, value)) {
return;
}
@ -381,9 +384,10 @@ bool InternalHeaders::IsImmutable(ErrorResult& aRv) const {
return false;
}
bool InternalHeaders::IsForbiddenRequestHeader(const nsCString& aName) const {
bool InternalHeaders::IsForbiddenRequestHeader(const nsCString& aName,
const nsACString& aValue) const {
return mGuard == HeadersGuardEnum::Request &&
nsContentUtils::IsForbiddenRequestHeader(aName);
nsContentUtils::IsForbiddenRequestHeader(aName, aValue);
}
bool InternalHeaders::IsForbiddenRequestNoCorsHeader(

View File

@ -131,7 +131,8 @@ class InternalHeaders final {
bool IsValidHeaderValue(const nsCString& aLowerName,
const nsCString& aNormalizedValue, ErrorResult& aRv);
bool IsImmutable(ErrorResult& aRv) const;
bool IsForbiddenRequestHeader(const nsCString& aName) const;
bool IsForbiddenRequestHeader(const nsCString& aName,
const nsACString& aValue) const;
bool IsForbiddenRequestNoCorsHeader(const nsCString& aName) const;
bool IsForbiddenRequestNoCorsHeader(const nsCString& aName,
const nsACString& aValue) const;
@ -144,7 +145,7 @@ class InternalHeaders final {
bool IsInvalidMutableHeader(const nsCString& aName, const nsACString& aValue,
ErrorResult& aRv) const {
return IsInvalidName(aName, aRv) || IsInvalidValue(aValue, aRv) ||
IsImmutable(aRv) || IsForbiddenRequestHeader(aName) ||
IsImmutable(aRv) || IsForbiddenRequestHeader(aName, aValue) ||
IsForbiddenRequestNoCorsHeader(aName, aValue) ||
IsForbiddenResponseHeader(aName);
}

View File

@ -3174,7 +3174,8 @@ void XMLHttpRequestMainThread::SetRequestHeader(const nsACString& aName,
// Step 5
bool isPrivilegedCaller = IsSystemXHR();
bool isForbiddenHeader = nsContentUtils::IsForbiddenRequestHeader(aName);
bool isForbiddenHeader =
nsContentUtils::IsForbiddenRequestHeader(aName, aValue);
if (!isPrivilegedCaller && isForbiddenHeader) {
AutoTArray<nsString, 1> params;
CopyUTF8toUTF16(aName, *params.AppendElement());