Files
UXP-Fixed/netwerk/protocol/http/nsHttpRequestHead.h
Gaming4JC c5c9445e3a backport mozbug 1334776 - CVE-2017-7797 Header name interning leaks across origins
Potential attack: session supercookie.

[Moz Notes](https://bugzilla.mozilla.org/show_bug.cgi?id=1334776#c5):
"The problem is that for unknown header names we store the first one we see and then later we case-insensitively match against that name *globally*. That means you can track if a user agent has already seen a certain header name used (by using a different casing and observing whether it gets normalized). This would allow you to see if a user has used a sensitive service that uses custom header names, or allows you to track a user across sites, by teaching the browser about a certain header case once and then observing if different casings get normalized to that.

What we should do instead is only store the casing for a header name for each header list and not globally. That way it only leaks where it's expected (and necessary) to leak."

[Moz fix note](https://bugzilla.mozilla.org/show_bug.cgi?id=1334776#c8):
"nsHttpAtom now holds the old nsHttpAtom and a string that is case sensitive (only for not standard headers).
So nsHttpAtom holds a pointer to a header name. (header names are store on a static structure). This is how it used to be. I left that part the same but added a nsCString which holds a string that was used to resoled the header name. So when we parse headers we call ResolveHeader with a char*. If it is a new header name the char* will be stored in a HttpHeapAtom, nsHttpAtom::_val will point to HttpHeapAtom::value and the same strings will be stored in mLocalCaseSensitiveHeader. For the first resolve request they will be the same but for the following maybe not. At the end this nsHttpAtom will be stored in nsHttpHeaderArray. For all operation we will used the old char* except when we are returning it to a script using VisitHeaders."
2018-09-25 23:03:28 -04:00

131 lines
4.4 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsHttpRequestHead_h__
#define nsHttpRequestHead_h__
#include "nsHttp.h"
#include "nsHttpHeaderArray.h"
#include "nsString.h"
#include "mozilla/ReentrantMonitor.h"
class nsIHttpHeaderVisitor;
namespace mozilla { namespace net {
//-----------------------------------------------------------------------------
// nsHttpRequestHead represents the request line and headers from an HTTP
// request.
//-----------------------------------------------------------------------------
class nsHttpRequestHead
{
public:
nsHttpRequestHead();
~nsHttpRequestHead();
// The following function is only used in HttpChannelParent to avoid
// copying headers. If you use it be careful to do it only under
// nsHttpRequestHead lock!!!
const nsHttpHeaderArray &Headers() const;
void Enter() { mReentrantMonitor.Enter(); }
void Exit() { mReentrantMonitor.Exit(); }
void SetHeaders(const nsHttpHeaderArray& aHeaders);
void SetMethod(const nsACString &method);
void SetVersion(nsHttpVersion version);
void SetRequestURI(const nsCSubstring &s);
void SetPath(const nsCSubstring &s);
uint32_t HeaderCount();
// Using this function it is possible to itereate through all headers
// automatically under one lock.
nsresult VisitHeaders(nsIHttpHeaderVisitor *visitor,
nsHttpHeaderArray::VisitorFilter filter =
nsHttpHeaderArray::eFilterAll);
void Method(nsACString &aMethod);
nsHttpVersion Version();
void RequestURI(nsACString &RequestURI);
void Path(nsACString &aPath);
void SetHTTPS(bool val);
bool IsHTTPS();
void SetOrigin(const nsACString &scheme, const nsACString &host,
int32_t port);
void Origin(nsACString &aOrigin);
nsresult SetHeader(const nsACString &h, const nsACString &v,
bool m=false);
nsresult SetHeader(nsHttpAtom h, const nsACString &v, bool m=false);
nsresult SetHeader(nsHttpAtom h, const nsACString &v, bool m,
nsHttpHeaderArray::HeaderVariety variety);
nsresult SetEmptyHeader(const nsACString &h);
nsresult GetHeader(nsHttpAtom h, nsACString &v);
nsresult ClearHeader(nsHttpAtom h);
void ClearHeaders();
bool HasHeaderValue(nsHttpAtom h, const char *v);
// This function returns true if header is set even if it is an empty
// header.
bool HasHeader(nsHttpAtom h);
void Flatten(nsACString &, bool pruneProxyHeaders = false);
// Don't allow duplicate values
nsresult SetHeaderOnce(nsHttpAtom h, const char *v, bool merge = false);
bool IsSafeMethod();
enum ParsedMethodType
{
kMethod_Custom,
kMethod_Get,
kMethod_Post,
kMethod_Options,
kMethod_Connect,
kMethod_Head,
kMethod_Put,
kMethod_Trace
};
ParsedMethodType ParsedMethod();
bool EqualsMethod(ParsedMethodType aType);
bool IsGet() { return EqualsMethod(kMethod_Get); }
bool IsPost() { return EqualsMethod(kMethod_Post); }
bool IsOptions() { return EqualsMethod(kMethod_Options); }
bool IsConnect() { return EqualsMethod(kMethod_Connect); }
bool IsHead() { return EqualsMethod(kMethod_Head); }
bool IsPut() { return EqualsMethod(kMethod_Put); }
bool IsTrace() { return EqualsMethod(kMethod_Trace); }
void ParseHeaderSet(const char *buffer);
private:
// All members must be copy-constructable and assignable
nsHttpHeaderArray mHeaders;
nsCString mMethod;
nsHttpVersion mVersion;
// mRequestURI and mPath are strings instead of an nsIURI
// because this is used off the main thread
nsCString mRequestURI;
nsCString mPath;
nsCString mOrigin;
ParsedMethodType mParsedMethod;
bool mHTTPS;
// We are using ReentrantMonitor instead of a Mutex because VisitHeader
// function calls nsIHttpHeaderVisitor::VisitHeader while under lock.
ReentrantMonitor mReentrantMonitor;
// During VisitHeader we sould not allow cal to SetHeader.
bool mInVisitHeaders;
};
} // namespace net
} // namespace mozilla
#endif // nsHttpRequestHead_h__