Commit 524e3541 authored by Georg Koppen's avatar Georg Koppen
Browse files

Bug 21537: Mark .onion cookies as secure

parent 9e6cb6ec
Loading
Loading
Loading
Loading
+32 −53
Original line number Diff line number Diff line
@@ -3116,6 +3116,26 @@ nsCookieService::PathMatches(nsCookie* aCookie,
  return true;
}

static bool
IsSecureHost(nsIURI *aHostURI) {
  bool isSecure = true;
  // If SchemeIs fails, assume an insecure connection, to be on the safe side.
  if (aHostURI && NS_FAILED(aHostURI->SchemeIs("https", &isSecure))) {
    isSecure = false;
  }
  // In case HTTPS is not used check whether we have a .onion host in which
  // case the cookie is secure, too.
  if (aHostURI && !isSecure) {
    nsresult rv;
    nsAutoCString hostFromURI;
    rv = aHostURI->GetAsciiHost(hostFromURI);
    if (NS_SUCCEEDED(rv)) {
      isSecure = StringEndsWith(hostFromURI, NS_LITERAL_CSTRING(".onion"));
    }
  }
  return isSecure;
}

void
nsCookieService::GetCookiesForURI(nsIURI *aHostURI,
                                  bool aIsForeign,
@@ -3177,13 +3197,10 @@ nsCookieService::GetCookiesForURI(nsIURI *aHostURI,
  // If it changes, please update that function, or file a bug for someone
  // else to do so.

  // check if aHostURI is using an https secure protocol.
  // if it isn't, then we can't send a secure cookie over the connection.
  // if SchemeIs fails, assume an insecure connection, to be on the safe side
  bool isSecure;
  if (NS_FAILED(aHostURI->SchemeIs("https", &isSecure))) {
    isSecure = false;
  }
  // Check if aHostURI is using the HTTPS protocol or if the domain is a
  // .onion. If it isn't, then we can't send a secure cookie over the
  // connection.
  bool isSecure = IsSecureHost(aHostURI);

  nsCookie *cookie;
  int64_t currentTimeInUsec = PR_Now();
@@ -3359,40 +3376,10 @@ nsCookieService::CanSetCookie(nsIURI* aHostURI,
  // so we can handle them separately.
  bool newCookie = ParseAttributes(aCookieHeader, aCookieAttributes);

  // Collect telemetry on how often secure cookies are set from non-secure
  // origins, and vice-versa.
  //
  // 0 = nonsecure and "http:"
  // 1 = nonsecure and "https:"
  // 2 = secure and "http:"
  // 3 = secure and "https:"
  bool isHTTPS;
  nsresult rv = aHostURI->SchemeIs("https", &isHTTPS);
  if (NS_SUCCEEDED(rv)) {
    Telemetry::Accumulate(Telemetry::COOKIE_SCHEME_SECURITY,
                          ((aCookieAttributes.isSecure)? 0x02 : 0x00) |
                          ((isHTTPS)? 0x01 : 0x00));

    // Collect telemetry on how often are first- and third-party cookies set
    // from HTTPS origins:
    //
    // 0 (000) = first-party and "http:"
    // 1 (001) = first-party and "http:" with bogus Secure cookie flag?!
    // 2 (010) = first-party and "https:"
    // 3 (011) = first-party and "https:" with Secure cookie flag
    // 4 (100) = third-party and "http:"
    // 5 (101) = third-party and "http:" with bogus Secure cookie flag?!
    // 6 (110) = third-party and "https:"
    // 7 (111) = third-party and "https:" with Secure cookie flag
    if (aThirdPartyUtil) {
      bool isThirdParty = true;
      aThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isThirdParty);
      Telemetry::Accumulate(Telemetry::COOKIE_SCHEME_HTTPS,
                            (isThirdParty ? 0x04 : 0x00) |
                            (isHTTPS ? 0x02 : 0x00) |
                            (aCookieAttributes.isSecure ? 0x01 : 0x00));
    }
  }
  // Check if aHostURI is using the HTTPS protocol or if the domain is a
  // .onion. If it isn't, then we can't send a secure cookie over the
  // connection.
  bool isSecure = IsSecureHost(aHostURI);

  int64_t currentTimeInUsec = PR_Now();

@@ -3432,7 +3419,7 @@ nsCookieService::CanSetCookie(nsIURI* aHostURI,
    return newCookie;
  }
  // magic prefix checks. MUST be run after CheckDomain() and CheckPath()
  if (!CheckPrefixes(aCookieAttributes, isHTTPS)) {
  if (!CheckPrefixes(aCookieAttributes, isSecure)) {
    COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "failed the prefix tests");
    return newCookie;
  }
@@ -3461,13 +3448,8 @@ nsCookieService::CanSetCookie(nsIURI* aHostURI,
    return newCookie;
  }

  bool isSecure = true;
  if (aHostURI) {
    aHostURI->SchemeIs("https", &isSecure);
  }

  // If the new cookie is non-https and wants to set secure flag,
  // browser have to ignore this new cookie.
  // If the new cookie is non-https or not set by a .onion domain, and wants to
  // set secure flag, browser have to ignore this new cookie.
  // (draft-ietf-httpbis-cookie-alone section 3.1)
  if (aLeaveSecureAlone && aCookieAttributes.isSecure && !isSecure) {
    COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
@@ -3603,10 +3585,7 @@ nsCookieService::AddInternal(const nsCookieKey &aKey,
  foundCookie = FindCookie(aKey, aCookie->Host(),
                           aCookie->Name(), aCookie->Path(), exactIter);
  bool foundSecureExact = foundCookie && exactIter.Cookie()->IsSecure();
  bool isSecure = true;
  if (aHostURI && NS_FAILED(aHostURI->SchemeIs("https", &isSecure)))  {
    isSecure = false;
  }
  bool isSecure = IsSecureHost(aHostURI);
  bool oldCookieIsSession = false;
  if (mLeaveSecureAlone) {
    // Step1, call FindSecureCookie(). FindSecureCookie() would