Commit 3f8bb0cd authored by Kathleen Brade's avatar Kathleen Brade Committed by Georg Koppen
Browse files

Bug 13900: Remove 3rd party HTTP auth tokens.

Prevent user tracking via HTTP Basic Authentication by
removing Authorization headers from third party requests.

This is a port of a piece of the Stanford SafeCache code that
previously was included in Torbutton.
parent 090091f8
Loading
Loading
Loading
Loading
+15 −6
Original line number Diff line number Diff line
@@ -501,20 +501,28 @@ ThirdPartyUtil::GetBaseDomain(nsIURI* aHostURI,
  return NS_OK;
}

// Returns true if First Party Isolation is currently active for the given nsIChannel.
// Depends on Preference setting and possibly the state of Private Browsing mode.
bool ThirdPartyUtil::IsFirstPartyIsolationActive(nsIChannel *aChannel, nsIDocument *aDoc)
// Determine if First Party Isolation is currently active for the given
// nsIChannel or nsIDocument.  Depends on preference setting and
// possibly the state of Private Browsing mode.
NS_IMETHODIMP
ThirdPartyUtil::IsFirstPartyIsolationActive(nsIChannel *aChannel,
                                            nsIDocument *aDoc,
                                            bool* aResult)
{
  NS_ASSERTION(aResult, "null outparam pointer");

  int32_t isolationState = mozilla::Preferences::GetInt("privacy.thirdparty.isolate");
  if (isolationState == 1) {
    if (!aChannel && aDoc) {
      // No channel passed directly. Can we get a channel from aDoc?
      aChannel = aDoc->GetChannel();
    }
    return aChannel && NS_UsePrivateBrowsing(aChannel);
    *aResult = aChannel && NS_UsePrivateBrowsing(aChannel);
  } else { // (isolationState == 0) || (isolationState == 2)
    return (isolationState == 2);
    *aResult = (isolationState == 2);
  }

  return NS_OK;
}

// Produces a URI that uniquely identifies the first party to which
@@ -524,7 +532,8 @@ bool ThirdPartyUtil::IsFirstPartyIsolationActive(nsIChannel *aChannel, nsIDocume
NS_IMETHODIMP
ThirdPartyUtil::GetFirstPartyIsolationURI(nsIChannel *aChannel, nsIDocument *aDoc, nsIURI **aOutput)
{
  bool isolationActive = IsFirstPartyIsolationActive(aChannel, aDoc);
  bool isolationActive = false;
  (void)IsFirstPartyIsolationActive(aChannel, aDoc, &isolationActive);
  if (isolationActive) {
    return GetFirstPartyURI(aChannel, aDoc, aOutput);
  } else {
+21 −1
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@ interface nsIDocument;
 * Utility functions for determining whether a given URI, channel, or window
 * hierarchy is third party with respect to a known URI.
 */
[scriptable, uuid(b711bd7f-0674-49be-ae77-f221db5f7b6c)]
[scriptable, uuid(b538074d-5e00-40b3-b5c4-e060ae010b83)]
interface mozIThirdPartyUtil : nsISupports
{
  /**
@@ -178,6 +178,26 @@ interface mozIThirdPartyUtil : nsISupports
  [noscript] nsIURI getFirstPartyURI(in nsIChannel aChannel,
                                     in nsIDocument aDoc);

  /**
   * isFirstPartyIsolationActive
   *
   * Determine if First Party Isolation is currently active for the given
   * nsIChannel or nsIDocument.  Depends on preference setting and
   * possibly the state of Private Browsing mode.
   *
   * @param aChannel
   *        An arbitrary channel for some content element of a first party
   *        load. Can be null.
   *
   * @param aDoc
   *        An arbitrary third party document. Can be null.
   *
   * @return true if first party isolation is active.
   */

  [noscript] bool isFirstPartyIsolationActive(in nsIChannel aChannel,
                                              in nsIDocument aDoc);

  /**
   * getFirstPartyIsolationURI
   *
+70 −0
Original line number Diff line number Diff line
@@ -4907,6 +4907,8 @@ nsHttpChannel::BeginConnect()
    // notify "http-on-modify-request" observers
    CallOnModifyRequestObservers();

    RemoveAuthorizationHeaderIfAppropriate();

    // Check to see if we should redirect this channel elsewhere by
    // nsIHttpChannel.redirectTo API request
    if (mAPIRedirectToURI) {
@@ -6168,6 +6170,72 @@ nsHttpChannel::ResumeAt(uint64_t aStartPos,
    return NS_OK;
}

// Remove the Authorization header if first party isolation is active and
// this channel is processing a third party request. This prevents user
// tracking via HTTP Basic Authentication.
// Note that this approach disables authentication for 3rd party domains. It
// would be better if we could isolate the authentication while still allowing
// it to be transmitted... but HTTP authentication is rarely used anyway.
void
nsHttpChannel::RemoveAuthorizationHeaderIfAppropriate()
{
    if (!mRequestHead.PeekHeader(nsHttp::Authorization)) {
        return; // No Authorization header is present.
    }

    nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
                                = do_GetService(THIRDPARTYUTIL_CONTRACTID);
    bool isolationActive = true;
    (void)thirdPartySvc->IsFirstPartyIsolationActive(this, nullptr,
                                                     &isolationActive);
    if (!isolationActive)
        return; // First party isolation is disabled for this channel.

    bool isAuthAllowed = false;
    nsCOMPtr<nsIURI> firstPartyURI;
    nsresult rv = thirdPartySvc->GetFirstPartyURIFromChannel(this, false,
                                               getter_AddRefs(firstPartyURI));
    if (NS_SUCCEEDED(rv) && firstPartyURI) {
        isAuthAllowed = (mURI == firstPartyURI)
                        || HostPartIsTheSame(firstPartyURI);
    } else {
        // We failed to get the first party URI. Check the document URI so
        // that we can allow authentication if the request originates from the
        // the browser chrome, e.g., some favicon requests. If there is no
        // document URI associated with this request, it cannot be associated
        // with a content document, so it must be a special request (e.g.,
        // favicon fetch or OSCP), for which we also allow authenication.
        nsCOMPtr<nsIURI> docURI;
        rv = GetDocumentURI(getter_AddRefs(docURI));
        if (NS_FAILED(rv) || !docURI) {
            isAuthAllowed = true;
        } else {
            nsAutoCString docURISpec;
            docURI->GetAsciiSpec(docURISpec);
            if (docURISpec == "chrome://browser/content/browser.xul")
                isAuthAllowed = true;
        }
    }

    if (!isAuthAllowed) {
        mRequestHead.ClearHeader(nsHttp::Authorization);
        mRequestHead.ClearHeader(nsHttp::Cache_Control);
        mRequestHead.ClearHeader(nsHttp::Pragma);

#ifdef PR_LOGGING
        nsAutoCString requestURIStr, firstPartyURIStr;
        mURI->GetAsciiSpec(requestURIStr);
        if (firstPartyURI)
            firstPartyURI->GetAsciiSpec(firstPartyURIStr);
        else
            firstPartyURIStr = "--N/A--";
        LOG(("Removed Authorization header from third party request"
              " [Request URI=%s, First Party URI=%s]\n",
              requestURIStr.get(), firstPartyURIStr.get()));
#endif
    }
}

nsresult
nsHttpChannel::DoAuthRetry(nsAHttpConnection *conn)
{
@@ -6189,6 +6257,8 @@ nsHttpChannel::DoAuthRetry(nsAHttpConnection *conn)
    // notify "http-on-modify-request" observers
    CallOnModifyRequestObservers();

    RemoveAuthorizationHeaderIfAppropriate();

    mIsPending = true;

    // get rid of the old response headers
+1 −0
Original line number Diff line number Diff line
@@ -310,6 +310,7 @@ private:
    nsresult ProcessPartialContent();
    nsresult OnDoneReadingPartialCacheEntry(bool *streamDone);

    void     RemoveAuthorizationHeaderIfAppropriate();
    nsresult DoAuthRetry(nsAHttpConnection *);

    void     HandleAsyncRedirectChannelToHttps();