зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1424917 - Remove support for HSTS Priming. r=mayhemer, r=ckerschb
This patch removes support and tests for HSTS priming from the tree.
This commit is contained in:
Родитель
e876c969d0
Коммит
e97980a95e
|
@ -82,8 +82,6 @@ function pushPrefEnv() {
|
|||
const prefs = [
|
||||
["security.mixed_content.block_active_content", true],
|
||||
["security.mixed_content.block_display_content", true],
|
||||
["security.mixed_content.use_hsts", false],
|
||||
["security.mixed_content.send_hsts_priming", false],
|
||||
];
|
||||
|
||||
return Promise.all(prefs.map(([pref, value]) => pushPref(pref, value)));
|
||||
|
|
|
@ -61,8 +61,6 @@ function pushPrefEnv() {
|
|||
"set": [
|
||||
["security.mixed_content.block_active_content", true],
|
||||
["security.mixed_content.block_display_content", true],
|
||||
["security.mixed_content.use_hsts", false],
|
||||
["security.mixed_content.send_hsts_priming", false],
|
||||
]
|
||||
};
|
||||
SpecialPowers.pushPrefEnv(options, deferred.resolve);
|
||||
|
|
|
@ -95,10 +95,6 @@ function testXhrWarn() {
|
|||
|
||||
let lastRequest = yield waitForFinishedRequest(XHR_WARN_REQUEST_PREDICATE);
|
||||
if (lastRequest.request.method == "HEAD") {
|
||||
// in non-e10s, we get the HEAD request that priming sends, so make sure
|
||||
// a priming request should be sent, and then get the actual request
|
||||
is(Services.prefs.getBoolPref("security.mixed_content.send_hsts_priming"),
|
||||
true, "Found HSTS Priming Request");
|
||||
lastRequest = yield waitForFinishedRequest(XHR_WARN_REQUEST_PREDICATE);
|
||||
}
|
||||
|
||||
|
|
|
@ -9557,27 +9557,6 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
|||
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
||||
// If HSTS priming was set by nsMixedContentBlocker::ShouldLoad, and we
|
||||
// would block due to mixed content, go ahead and block here. If we try to
|
||||
// proceed with priming, we will error out later on.
|
||||
nsCOMPtr<nsIDocShell> docShell = NS_CP_GetDocShellFromContext(requestingContext);
|
||||
// When loading toplevel windows, requestingContext can be null. We don't
|
||||
// really care about HSTS in that situation, though; loads in toplevel
|
||||
// windows should all be browser UI.
|
||||
if (docShell) {
|
||||
nsIDocument* document = docShell->GetDocument();
|
||||
NS_ENSURE_TRUE(document, NS_OK);
|
||||
|
||||
HSTSPrimingState state = document->GetHSTSPrimingStateForLocation(aURI);
|
||||
if (state == HSTSPrimingState::eHSTS_PRIMING_BLOCK) {
|
||||
// HSTS Priming currently disabled for InternalLoad, so we need to clear
|
||||
// the location that was added by nsMixedContentBlocker::ShouldLoad
|
||||
// Bug 1269815 will address images loaded via InternalLoad
|
||||
document->ClearHSTSPrimingLocation(aURI);
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
#include "nsIPresShell.h"
|
||||
#include "nsIScriptGlobalObject.h" // for member (in nsCOMPtr)
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIURI.h" // for use in inline functions
|
||||
#include "nsIUUIDGenerator.h"
|
||||
#include "nsPIDOMWindow.h" // for use in inline functions
|
||||
#include "nsPropertyTable.h" // for member
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsDataHashtable.h" // for member
|
||||
#include "nsURIHashKey.h" // for member
|
||||
#include "nsTHashtable.h" // for member
|
||||
#include "mozilla/net/ReferrerPolicy.h" // for member
|
||||
#include "nsWeakReference.h"
|
||||
#include "mozilla/UseCounter.h"
|
||||
|
@ -194,13 +194,6 @@ enum DocumentFlavor {
|
|||
DocumentFlavorPlain, // Just a Document
|
||||
};
|
||||
|
||||
// Enum for HSTS priming states
|
||||
enum class HSTSPrimingState {
|
||||
eNO_HSTS_PRIMING = 0, // don't do HSTS Priming
|
||||
eHSTS_PRIMING_ALLOW = 1, // if HSTS priming fails, allow the load to proceed
|
||||
eHSTS_PRIMING_BLOCK = 2 // if HSTS priming fails, block the load
|
||||
};
|
||||
|
||||
// Document states
|
||||
|
||||
// RTL locale: specific to the XUL localedir attribute
|
||||
|
@ -424,34 +417,6 @@ public:
|
|||
mReferrer = aReferrer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if a subresource we want to load requires HSTS priming
|
||||
* to be done.
|
||||
*/
|
||||
HSTSPrimingState GetHSTSPrimingStateForLocation(nsIURI* aContentLocation) const
|
||||
{
|
||||
HSTSPrimingState state;
|
||||
if (mHSTSPrimingURIList.Get(aContentLocation, &state)) {
|
||||
return state;
|
||||
}
|
||||
return HSTSPrimingState::eNO_HSTS_PRIMING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a subresource to the HSTS priming list. If this URI is
|
||||
* not in the HSTS cache, it will trigger an HSTS priming request
|
||||
* when we try to load it.
|
||||
*/
|
||||
void AddHSTSPrimingLocation(nsIURI* aContentLocation, HSTSPrimingState aState)
|
||||
{
|
||||
mHSTSPrimingURIList.Put(aContentLocation, aState);
|
||||
}
|
||||
|
||||
void ClearHSTSPrimingLocation(nsIURI* aContentLocation)
|
||||
{
|
||||
mHSTSPrimingURIList.Remove(aContentLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the principal responsible for this document. Chances are,
|
||||
* you do not want to be using this.
|
||||
|
@ -3339,11 +3304,6 @@ protected:
|
|||
bool mUpgradeInsecureRequests;
|
||||
bool mUpgradeInsecurePreloads;
|
||||
|
||||
// if nsMixedContentBlocker requires sending an HSTS priming request,
|
||||
// temporarily store that in the document so that it can be propogated to the
|
||||
// LoadInfo and eventually the HTTP Channel
|
||||
nsDataHashtable<nsURIHashKey, HSTSPrimingState> mHSTSPrimingURIList;
|
||||
|
||||
mozilla::WeakPtr<nsDocShell> mDocumentContainer;
|
||||
|
||||
NotNull<const Encoding*> mCharacterSet;
|
||||
|
|
|
@ -194,12 +194,6 @@ function createPolicyTest(policy, optionalEarlierPolicy) {
|
|||
}
|
||||
|
||||
function handleRequest(request, response) {
|
||||
if (request.method == 'HEAD') {
|
||||
// respond to a HEAD request with a 418 so that we can easily distinguish
|
||||
// HSTS priming responses and ignore them
|
||||
response.setStatusLine('1.1', 418, "I'm a teapot");
|
||||
return;
|
||||
}
|
||||
var sharedKey = 'bug704320.sjs';
|
||||
var params = request.queryString.split('&');
|
||||
var action = params[0].split('=')[1];
|
||||
|
|
|
@ -25,9 +25,6 @@ function doXHR(url, onSuccess, onFail) {
|
|||
xhr.onload = function () {
|
||||
if (xhr.status == 200) {
|
||||
onSuccess(xhr);
|
||||
} else if (xhr.status == 418) {
|
||||
// Ignore HSTS priming responses
|
||||
return;
|
||||
} else {
|
||||
onFail(xhr);
|
||||
}
|
||||
|
|
|
@ -38,15 +38,10 @@ let tests = [
|
|||
function setup() {
|
||||
Services.prefs.setBoolPref("browser.send_pings", true);
|
||||
Services.prefs.setIntPref("browser.send_pings.max_per_link", -1);
|
||||
Services.prefs.setBoolPref("security.mixed_content.block_active_content", false);
|
||||
// The server we create can't handle the priming HEAD requests
|
||||
Services.prefs.setBoolPref("security.mixed_content.send_hsts_priming", false);
|
||||
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("browser.send_pings");
|
||||
Services.prefs.clearUserPref("browser.send_pings.max_per_link");
|
||||
Services.prefs.clearUserPref("security.mixed_content.block_active_content");
|
||||
Services.prefs.clearUserPref("security.mixed_content.send_hsts_priming");
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -149,7 +144,7 @@ let tests = [
|
|||
|
||||
// The referrer will be loaded using a secure channel.
|
||||
navigate("https://example.com/chrome/dom/html/test/" +
|
||||
"file_anchor_ping.html?" + "http://localhost:" +
|
||||
"file_anchor_ping.html?" + "http://127.0.0.1:" +
|
||||
server.identity.primaryPort + ping);
|
||||
|
||||
// Wait until the ping has been sent.
|
||||
|
|
|
@ -3566,14 +3566,14 @@ ContentParent::RecvIsSecureURI(const uint32_t& aType,
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvAccumulateMixedContentHSTS(const URIParams& aURI, const bool& aActive, const bool& aHSTSPriming,
|
||||
ContentParent::RecvAccumulateMixedContentHSTS(const URIParams& aURI, const bool& aActive,
|
||||
const OriginAttributes& aOriginAttributes)
|
||||
{
|
||||
nsCOMPtr<nsIURI> ourURI = DeserializeURI(aURI);
|
||||
if (!ourURI) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
nsMixedContentBlocker::AccumulateMixedContentHSTS(ourURI, aActive, aHSTSPriming, aOriginAttributes);
|
||||
nsMixedContentBlocker::AccumulateMixedContentHSTS(ourURI, aActive, aOriginAttributes);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -894,7 +894,6 @@ private:
|
|||
|
||||
virtual mozilla::ipc::IPCResult RecvAccumulateMixedContentHSTS(const URIParams& aURI,
|
||||
const bool& aActive,
|
||||
const bool& aHSTSPriming,
|
||||
const OriginAttributes& aOriginAttributes) override;
|
||||
|
||||
virtual bool DeallocPHalParent(PHalParent*) override;
|
||||
|
|
|
@ -743,7 +743,7 @@ parent:
|
|||
OriginAttributes aOriginAttributes)
|
||||
returns (bool isSecureURI);
|
||||
|
||||
async AccumulateMixedContentHSTS(URIParams aURI, bool aActive, bool aHasHSTSPriming,
|
||||
async AccumulateMixedContentHSTS(URIParams aURI, bool aActive,
|
||||
OriginAttributes aOriginAttributes);
|
||||
|
||||
nested(inside_cpow) async PHal();
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
#include "nsContentUtils.h"
|
||||
#include "nsCORSListenerProxy.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsMixedContentBlocker.h"
|
||||
#include "nsCDefaultURIFixup.h"
|
||||
#include "nsIURIFixup.h"
|
||||
#include "nsIImageLoadingContent.h"
|
||||
|
@ -512,13 +510,6 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
|
|||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
||||
if (nsMixedContentBlocker::sSendHSTSPriming) {
|
||||
rv = nsMixedContentBlocker::MarkLoadInfoForPriming(uri,
|
||||
requestingContext,
|
||||
aLoadInfo);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,40 +58,6 @@ bool nsMixedContentBlocker::sBlockMixedObjectSubrequest = false;
|
|||
// Is mixed display content blocking (images, audio, video, <a ping>) enabled?
|
||||
bool nsMixedContentBlocker::sBlockMixedDisplay = false;
|
||||
|
||||
// Do we move HSTS before mixed-content
|
||||
bool nsMixedContentBlocker::sUseHSTS = false;
|
||||
// Do we send an HSTS priming request
|
||||
bool nsMixedContentBlocker::sSendHSTSPriming = false;
|
||||
// Default HSTS Priming failure timeout to 7 days, in seconds
|
||||
uint32_t nsMixedContentBlocker::sHSTSPrimingCacheTimeout = (60 * 60 * 24 * 7);
|
||||
|
||||
bool
|
||||
IsEligibleForHSTSPriming(nsIURI* aContentLocation) {
|
||||
bool isHttpScheme = false;
|
||||
nsresult rv = aContentLocation->SchemeIs("http", &isHttpScheme);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
if (!isHttpScheme) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t port = -1;
|
||||
rv = aContentLocation->GetPort(&port);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
int32_t defaultPort = NS_GetDefaultPort("https");
|
||||
|
||||
if (port != -1 && port != defaultPort) {
|
||||
// HSTS priming requests are only sent if the port is the default port
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString hostname;
|
||||
rv = aContentLocation->GetHost(hostname);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
PRNetAddr hostAddr;
|
||||
return (PR_StringToNetAddr(hostname.get(), &hostAddr) != PR_SUCCESS);
|
||||
}
|
||||
|
||||
enum MixedContentHSTSState {
|
||||
MCB_HSTS_PASSIVE_NO_HSTS = 0,
|
||||
MCB_HSTS_PASSIVE_WITH_HSTS = 1,
|
||||
|
@ -99,22 +65,6 @@ enum MixedContentHSTSState {
|
|||
MCB_HSTS_ACTIVE_WITH_HSTS = 3
|
||||
};
|
||||
|
||||
// Similar to the existing mixed-content HSTS, except MCB_HSTS_*_NO_HSTS is
|
||||
// broken into two distinct states, indicating whether we plan to send a priming
|
||||
// request or not. If we decided not go send a priming request, it could be
|
||||
// because it is a type we do not support, or because we cached a previous
|
||||
// negative response.
|
||||
enum MixedContentHSTSPrimingState {
|
||||
eMCB_HSTS_PASSIVE_WITH_HSTS = 0,
|
||||
eMCB_HSTS_ACTIVE_WITH_HSTS = 1,
|
||||
eMCB_HSTS_PASSIVE_NO_PRIMING = 2,
|
||||
eMCB_HSTS_PASSIVE_DO_PRIMING = 3,
|
||||
eMCB_HSTS_ACTIVE_NO_PRIMING = 4,
|
||||
eMCB_HSTS_ACTIVE_DO_PRIMING = 5,
|
||||
eMCB_HSTS_PASSIVE_UPGRADE = 6,
|
||||
eMCB_HSTS_ACTIVE_UPGRADE = 7,
|
||||
};
|
||||
|
||||
// Fired at the document that attempted to load mixed content. The UI could
|
||||
// handle this event, for example, by displaying an info bar that offers the
|
||||
// choice to reload the page with mixed content permitted.
|
||||
|
@ -264,18 +214,6 @@ nsMixedContentBlocker::nsMixedContentBlocker()
|
|||
// Cache the pref for mixed display blocking
|
||||
Preferences::AddBoolVarCache(&sBlockMixedDisplay,
|
||||
"security.mixed_content.block_display_content");
|
||||
|
||||
// Cache the pref for HSTS
|
||||
Preferences::AddBoolVarCache(&sUseHSTS,
|
||||
"security.mixed_content.use_hsts");
|
||||
|
||||
// Cache the pref for sending HSTS priming
|
||||
Preferences::AddBoolVarCache(&sSendHSTSPriming,
|
||||
"security.mixed_content.send_hsts_priming");
|
||||
|
||||
// Cache the pref for HSTS priming failure cache time
|
||||
Preferences::AddUintVarCache(&sHSTSPrimingCacheTimeout,
|
||||
"security.mixed_content.hsts_priming_cache_timeout");
|
||||
}
|
||||
|
||||
nsMixedContentBlocker::~nsMixedContentBlocker()
|
||||
|
@ -405,26 +343,6 @@ nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
|
|||
return NS_BINDING_FAILED;
|
||||
}
|
||||
|
||||
if (nsMixedContentBlocker::sSendHSTSPriming) {
|
||||
// The LoadInfo passed in is for the original channel, HSTS priming needs to
|
||||
// be set on the new channel, if required. If the redirect changes
|
||||
// http->https, or vice-versa, the need for priming may change.
|
||||
nsCOMPtr<nsILoadInfo> newLoadInfo;
|
||||
rv = aNewChannel->GetLoadInfo(getter_AddRefs(newLoadInfo));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (newLoadInfo) {
|
||||
rv = nsMixedContentBlocker::MarkLoadInfoForPriming(newUri,
|
||||
requestingContext,
|
||||
newLoadInfo);
|
||||
if (NS_FAILED(rv)) {
|
||||
decision = REJECT_REQUEST;
|
||||
newLoadInfo->ClearHSTSPriming();
|
||||
}
|
||||
} else {
|
||||
decision = REJECT_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
// If the channel is about to load mixed content, abort the channel
|
||||
if (!NS_CP_ACCEPTED(decision)) {
|
||||
autoCallback.DontCallback();
|
||||
|
@ -946,37 +864,6 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
|||
originAttributes = aRequestPrincipal->OriginAttributesRef();
|
||||
}
|
||||
|
||||
bool active = (classification == eMixedScript);
|
||||
bool doHSTSPriming = false;
|
||||
if (IsEligibleForHSTSPriming(aContentLocation)) {
|
||||
bool hsts = false;
|
||||
bool cached = false;
|
||||
nsCOMPtr<nsISiteSecurityService> sss =
|
||||
do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aContentLocation,
|
||||
0, originAttributes, &cached, nullptr, &hsts);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (hsts && sUseHSTS) {
|
||||
// assume we will be upgraded later
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_2,
|
||||
(active) ? MixedContentHSTSPrimingState::eMCB_HSTS_ACTIVE_UPGRADE
|
||||
: MixedContentHSTSPrimingState::eMCB_HSTS_PASSIVE_UPGRADE);
|
||||
*aDecision = ACCEPT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Send a priming request if the result is not already cached and priming
|
||||
// requests are allowed
|
||||
if (!cached && sSendHSTSPriming) {
|
||||
// add this URI as a priming location
|
||||
doHSTSPriming = true;
|
||||
document->AddHSTSPrimingLocation(innerContentLocation,
|
||||
HSTSPrimingState::eHSTS_PRIMING_ALLOW);
|
||||
*aDecision = ACCEPT;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point we know that the request is mixed content, and the only
|
||||
// question is whether we block it. Record telemetry at this point as to
|
||||
|
@ -990,9 +877,10 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
|||
//
|
||||
// We do not count requests aHadInsecureImageRedirect=true, since these are
|
||||
// just an artifact of the image caching system.
|
||||
bool active = (classification == eMixedScript);
|
||||
if (!aHadInsecureImageRedirect) {
|
||||
if (XRE_IsParentProcess()) {
|
||||
AccumulateMixedContentHSTS(innerContentLocation, active, doHSTSPriming,
|
||||
AccumulateMixedContentHSTS(innerContentLocation, active,
|
||||
originAttributes);
|
||||
} else {
|
||||
// Ask the parent process to do the same call
|
||||
|
@ -1000,7 +888,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
|||
if (cc) {
|
||||
mozilla::ipc::URIParams uri;
|
||||
SerializeURI(innerContentLocation, uri);
|
||||
cc->SendAccumulateMixedContentHSTS(uri, active, doHSTSPriming,
|
||||
cc->SendAccumulateMixedContentHSTS(uri, active,
|
||||
originAttributes);
|
||||
}
|
||||
}
|
||||
|
@ -1044,13 +932,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if (doHSTSPriming) {
|
||||
document->AddHSTSPrimingLocation(innerContentLocation,
|
||||
HSTSPrimingState::eHSTS_PRIMING_BLOCK);
|
||||
*aDecision = nsIContentPolicy::ACCEPT;
|
||||
} else {
|
||||
*aDecision = nsIContentPolicy::REJECT_REQUEST;
|
||||
}
|
||||
*aDecision = nsIContentPolicy::REJECT_REQUEST;
|
||||
LogMixedContentMessage(classification, aContentLocation, rootDoc, eBlocked);
|
||||
if (!rootDoc->GetHasMixedDisplayContentBlocked() && NS_SUCCEEDED(stateRV)) {
|
||||
rootDoc->SetHasMixedDisplayContentBlocked(true);
|
||||
|
@ -1096,13 +978,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
|||
}
|
||||
} else {
|
||||
//User has not overriden the pref by Disabling protection. Reject the request and update the security state.
|
||||
if (doHSTSPriming) {
|
||||
document->AddHSTSPrimingLocation(innerContentLocation,
|
||||
HSTSPrimingState::eHSTS_PRIMING_BLOCK);
|
||||
*aDecision = nsIContentPolicy::ACCEPT;
|
||||
} else {
|
||||
*aDecision = nsIContentPolicy::REJECT_REQUEST;
|
||||
}
|
||||
*aDecision = nsIContentPolicy::REJECT_REQUEST;
|
||||
LogMixedContentMessage(classification, aContentLocation, rootDoc, eBlocked);
|
||||
// See if the pref will change here. If it will, only then do we need to call OnSecurityChange() to update the UI.
|
||||
if (rootDoc->GetHasMixedActiveContentBlocked()) {
|
||||
|
@ -1164,8 +1040,7 @@ nsMixedContentBlocker::ShouldProcess(uint32_t aContentType,
|
|||
// content (regardless of whether it was actually blocked)
|
||||
void
|
||||
nsMixedContentBlocker::AccumulateMixedContentHSTS(
|
||||
nsIURI* aURI, bool aActive, bool aHasHSTSPriming,
|
||||
const OriginAttributes& aOriginAttributes)
|
||||
nsIURI* aURI, bool aActive, const OriginAttributes& aOriginAttributes)
|
||||
{
|
||||
// This method must only be called in the parent, because
|
||||
// nsSiteSecurityService is only available in the parent
|
||||
|
@ -1193,101 +1068,19 @@ nsMixedContentBlocker::AccumulateMixedContentHSTS(
|
|||
if (!hsts) {
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
|
||||
MCB_HSTS_PASSIVE_NO_HSTS);
|
||||
if (aHasHSTSPriming) {
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_2,
|
||||
eMCB_HSTS_PASSIVE_DO_PRIMING);
|
||||
} else {
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_2,
|
||||
eMCB_HSTS_PASSIVE_NO_PRIMING);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
|
||||
MCB_HSTS_PASSIVE_WITH_HSTS);
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_2,
|
||||
eMCB_HSTS_PASSIVE_WITH_HSTS);
|
||||
}
|
||||
} else {
|
||||
if (!hsts) {
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
|
||||
MCB_HSTS_ACTIVE_NO_HSTS);
|
||||
if (aHasHSTSPriming) {
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_2,
|
||||
eMCB_HSTS_ACTIVE_DO_PRIMING);
|
||||
} else {
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_2,
|
||||
eMCB_HSTS_ACTIVE_NO_PRIMING);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
|
||||
MCB_HSTS_ACTIVE_WITH_HSTS);
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_2,
|
||||
eMCB_HSTS_ACTIVE_WITH_HSTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
nsresult
|
||||
nsMixedContentBlocker::MarkLoadInfoForPriming(nsIURI* aURI,
|
||||
nsISupports* aRequestingContext,
|
||||
nsILoadInfo* aLoadInfo)
|
||||
{
|
||||
nsresult rv;
|
||||
bool sendPriming = false;
|
||||
bool mixedContentWouldBlock = false;
|
||||
rv = GetHSTSPrimingFromRequestingContext(aURI,
|
||||
aRequestingContext,
|
||||
&sendPriming,
|
||||
&mixedContentWouldBlock);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (sendPriming) {
|
||||
aLoadInfo->SetHSTSPriming(mixedContentWouldBlock);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//static
|
||||
nsresult
|
||||
nsMixedContentBlocker::GetHSTSPrimingFromRequestingContext(nsIURI* aURI,
|
||||
nsISupports* aRequestingContext,
|
||||
bool* aSendPrimingRequest,
|
||||
bool* aMixedContentWouldBlock)
|
||||
{
|
||||
*aSendPrimingRequest = false;
|
||||
*aMixedContentWouldBlock = false;
|
||||
// If we marked for priming, we used the innermost URI, so get that
|
||||
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
|
||||
if (!innerURI) {
|
||||
NS_ERROR("Can't get innerURI from aContentLocation");
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
||||
bool isHttp = false;
|
||||
innerURI->SchemeIs("http", &isHttp);
|
||||
if (!isHttp) {
|
||||
// there is nothign to do
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If the DocShell was marked for HSTS priming, propagate that to the LoadInfo
|
||||
nsCOMPtr<nsIDocShell> docShell = NS_CP_GetDocShellFromContext(aRequestingContext);
|
||||
if (!docShell) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> document = docShell->GetDocument();
|
||||
if (!document) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
HSTSPrimingState status = document->GetHSTSPrimingStateForLocation(innerURI);
|
||||
if (status != HSTSPrimingState::eNO_HSTS_PRIMING) {
|
||||
*aSendPrimingRequest = (status != HSTSPrimingState::eNO_HSTS_PRIMING);
|
||||
*aMixedContentWouldBlock = (status == HSTSPrimingState::eHSTS_PRIMING_BLOCK);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -69,45 +69,11 @@ public:
|
|||
int16_t* aDecision);
|
||||
static void AccumulateMixedContentHSTS(nsIURI* aURI,
|
||||
bool aActive,
|
||||
bool aHasHSTSPriming,
|
||||
const OriginAttributes& aOriginAttributes);
|
||||
/* If the document associated with aRequestingContext requires priming for
|
||||
* aURI, propagate that to the LoadInfo so the HttpChannel will find out about
|
||||
* it.
|
||||
*
|
||||
* @param aURI The URI associated with the load
|
||||
* @param aRequestingContext the requesting context passed to ShouldLoad
|
||||
* @param aLoadInfo the LoadInfo for the load
|
||||
*/
|
||||
static nsresult MarkLoadInfoForPriming(nsIURI* aURI,
|
||||
nsISupports* aRequestingContext,
|
||||
nsILoadInfo* aLoadInfo);
|
||||
|
||||
/* Given a context, return whether HSTS was marked on the document associated
|
||||
* with the load for the given URI. This is used by MarkLoadInfoForPriming and
|
||||
* directly by the image loader to determine whether to allow a load to occur
|
||||
* from the cache.
|
||||
*
|
||||
* @param aURI The URI associated with the load
|
||||
* @param aRequestingContext the requesting context passed to ShouldLoad
|
||||
* @param aSendPrimingRequest out true if priming is required on the channel
|
||||
* @param aMixedContentWouldBlock out true if mixed content would block
|
||||
*/
|
||||
static nsresult GetHSTSPrimingFromRequestingContext(nsIURI* aURI,
|
||||
nsISupports* aRequestingContext,
|
||||
bool* aSendPrimingRequest,
|
||||
bool* aMixedContentWouldBlock);
|
||||
|
||||
|
||||
static bool sBlockMixedScript;
|
||||
static bool sBlockMixedObjectSubrequest;
|
||||
static bool sBlockMixedDisplay;
|
||||
// Do we move HSTS before mixed-content
|
||||
static bool sUseHSTS;
|
||||
// Do we send an HSTS priming request
|
||||
static bool sSendHSTSPriming;
|
||||
// Default HSTS Priming failure timeout in seconds
|
||||
static uint32_t sHSTSPrimingCacheTimeout;
|
||||
};
|
||||
|
||||
#endif /* nsMixedContentBlocker_h___ */
|
||||
|
|
|
@ -116,8 +116,6 @@ SimpleTest.waitForExplicitFinish();
|
|||
SpecialPowers.pushPrefEnv({
|
||||
'set': [['security.mixed_content.block_active_content', false],
|
||||
['security.mixed_content.block_display_content', false],
|
||||
['security.mixed_content.send_hsts_priming', false],
|
||||
['security.mixed_content.use_hsts', false],
|
||||
]
|
||||
},
|
||||
function() {
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
[DEFAULT]
|
||||
skip-if = true # Bug 1425968 - Depends on an expiring Telemetry probe and feature is being removed
|
||||
support-files =
|
||||
head.js
|
||||
file_priming-top.html
|
||||
file_testserver.sjs
|
||||
file_1x1.png
|
||||
file_priming.js
|
||||
file_stylesheet.css
|
||||
|
||||
[browser_hsts-priming_allow_active.js]
|
||||
[browser_hsts-priming_block_active.js]
|
||||
[browser_hsts-priming_hsts_after_mixed.js]
|
||||
skip-if = os == "linux" # Bug 1311239
|
||||
[browser_hsts-priming_allow_display.js]
|
||||
[browser_hsts-priming_block_display.js]
|
||||
[browser_hsts-priming_block_active_css.js]
|
||||
[browser_hsts-priming_block_active_with_redir_same.js]
|
||||
[browser_hsts-priming_no-duplicates.js]
|
||||
[browser_hsts-priming_cache-timeout.js]
|
||||
[browser_hsts-priming_timeout.js]
|
||||
[browser_hsts-priming_no-non-standard-ports.js]
|
||||
[browser_hsts-priming_no-ip-address.js]
|
||||
[browser_hsts-priming_include-subdomains.js]
|
||||
skip-if = os == "linux" # Bug 1376238
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* Check that HSTS priming occurs correctly with mixed content when active
|
||||
* content is allowed.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 3,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 6,
|
||||
"HSTS_UPGRADE_SOURCE": [ 0,0,1,0,0,0,0,0,0 ]
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"success": 1,
|
||||
"failure": 2,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Services.obs.addObserver(Observer, "console-api-log-event");
|
||||
Services.obs.addObserver(Observer, "http-on-examine-response");
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
let which = "allow_active";
|
||||
|
||||
SetupPrefTestEnvironment(which);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
for (let server of Object.keys(test_servers)) {
|
||||
await execute_test(server, test_settings[which].mimetype);
|
||||
}
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* Check that HSTS priming occurs correctly with mixed content when display
|
||||
* content is allowed.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 3,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 6,
|
||||
"HSTS_UPGRADE_SOURCE": [ 0,0,1,0,0,0,0,0,0 ]
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"success": 1,
|
||||
"failure": 2,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Services.obs.addObserver(Observer, "console-api-log-event");
|
||||
Services.obs.addObserver(Observer, "http-on-examine-response");
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
let which = "allow_display";
|
||||
|
||||
SetupPrefTestEnvironment(which);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
for (let server of Object.keys(test_servers)) {
|
||||
await execute_test(server, test_settings[which].mimetype);
|
||||
}
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* Check that HSTS priming occurs correctly with mixed content when active
|
||||
* content is blocked.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 3,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 6,
|
||||
"HSTS_UPGRADE_SOURCE": [ 0,0,1,0,0,0,0,0,0 ]
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"success": 1,
|
||||
"failure": 2,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Services.obs.addObserver(Observer, "console-api-log-event");
|
||||
Services.obs.addObserver(Observer, "http-on-examine-response");
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
let which = "block_active";
|
||||
|
||||
SetupPrefTestEnvironment(which);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
for (let server of Object.keys(test_servers)) {
|
||||
await execute_test(server, test_settings[which].mimetype);
|
||||
}
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* Check that HSTS priming occurs correctly with mixed content when active
|
||||
* content is blocked for css.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 3,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 6,
|
||||
"HSTS_UPGRADE_SOURCE": [ 0,0,1,0,0,0,0,0,0 ]
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"success": 1,
|
||||
"failure": 2,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Services.obs.addObserver(Observer, "console-api-log-event");
|
||||
Services.obs.addObserver(Observer, "http-on-examine-response");
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
let which = "block_active_css";
|
||||
|
||||
SetupPrefTestEnvironment(which);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
for (let server of Object.keys(test_servers)) {
|
||||
await execute_test(server, test_settings[which].mimetype);
|
||||
}
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* Check that HSTS priming occurs correctly with mixed content when active
|
||||
* content is blocked and redirect to the same host should still upgrade.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 3,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 6,
|
||||
"HSTS_UPGRADE_SOURCE": [ 0,0,1,0,0,0,0,0,0 ]
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"success": 1,
|
||||
"failure": 2,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Services.obs.addObserver(Observer, "console-api-log-event");
|
||||
Services.obs.addObserver(Observer, "http-on-examine-response");
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
let which = "block_active_with_redir_same";
|
||||
|
||||
SetupPrefTestEnvironment(which);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
for (let server of Object.keys(test_servers)) {
|
||||
await execute_test(server, test_settings[which].mimetype);
|
||||
}
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* Check that HSTS priming occurs correctly with mixed content when display
|
||||
* content is blocked.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 3,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 6,
|
||||
"HSTS_UPGRADE_SOURCE": [ 0,0,1,0,0,0,0,0,0 ]
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"success": 1,
|
||||
"failure": 2,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Services.obs.addObserver(Observer, "console-api-log-event");
|
||||
Services.obs.addObserver(Observer, "http-on-examine-response");
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
let which = "block_display";
|
||||
|
||||
SetupPrefTestEnvironment(which);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
for (let server of Object.keys(test_servers)) {
|
||||
await execute_test(server, test_settings[which].mimetype);
|
||||
}
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* Test that the network.hsts_priming.cache_timeout preferene causes the cache
|
||||
* to timeout
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 2,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 4,
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"failure": 2,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Observer.add_observers(Services);
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
let which = "block_display";
|
||||
|
||||
SetupPrefTestEnvironment(which, [["security.mixed_content.hsts_priming_cache_timeout", 1]]);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
await execute_test("no-ssl", test_settings[which].mimetype);
|
||||
|
||||
let pre_promise = performance.now();
|
||||
|
||||
while ((performance.now() - pre_promise) < 1000) {
|
||||
await new Promise(function (resolve) {
|
||||
setTimeout(resolve, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
// clear the fact that we saw a priming request
|
||||
test_settings[which].priming = {};
|
||||
|
||||
await execute_test("no-ssl", test_settings[which].mimetype);
|
||||
is(test_settings[which].priming["no-ssl"], true,
|
||||
"Correctly send a priming request after expiration.");
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* Check that HSTS priming occurs correctly with mixed content when the
|
||||
* mixed-content blocks before HSTS.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 3,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 6,
|
||||
"HSTS_UPGRADE_SOURCE": [ 0,0,0,0,0,0,0,0,0 ]
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"success": 1,
|
||||
"failure": 2,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Services.obs.addObserver(Observer, "console-api-log-event");
|
||||
Services.obs.addObserver(Observer, "http-on-examine-response");
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
let which = "hsts_after_mixed";
|
||||
|
||||
SetupPrefTestEnvironment(which);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
for (let server of Object.keys(test_servers)) {
|
||||
await execute_test(server, test_settings[which].mimetype);
|
||||
}
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -1,55 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
/*
|
||||
* Description of the test:
|
||||
* If the top-level domain sends the STS header but does not have
|
||||
* includeSubdomains, HSTS priming requests should still be sent to
|
||||
* subdomains.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 2,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 4,
|
||||
"HSTS_UPGRADE_SOURCE": [ 0,0,2,0,0,0,0,0,0 ]
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"success": 2,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Observer.add_observers(Services);
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
// add the top-level server
|
||||
test_servers['top-level'] = {
|
||||
host: 'example.com',
|
||||
response: true,
|
||||
id: 'top-level',
|
||||
};
|
||||
test_settings.block_active.result['top-level'] = 'secure';
|
||||
|
||||
let which = "block_active";
|
||||
|
||||
SetupPrefTestEnvironment(which);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
await execute_test("top-level", test_settings[which].mimetype);
|
||||
|
||||
await execute_test("prime-hsts", test_settings[which].mimetype);
|
||||
|
||||
ok("prime-hsts" in test_settings[which].priming,
|
||||
"HSTS priming on a subdomain when top-level does not includeSubDomains");
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* Only one request should be sent per host, even if we run the test more
|
||||
* than once.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 3,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 8,
|
||||
"HSTS_UPGRADE_SOURCE": [ 0,0,2,0,0,0,0,0,0 ]
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"success": 1,
|
||||
"failure": 2,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Observer.add_observers(Services);
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
let which = "block_display";
|
||||
|
||||
SetupPrefTestEnvironment(which);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
for (let server of Object.keys(test_servers)) {
|
||||
await execute_test(server, test_settings[which].mimetype);
|
||||
}
|
||||
|
||||
// run the tests twice to validate the cache is being used
|
||||
for (let server of Object.keys(test_servers)) {
|
||||
await execute_test(server, test_settings[which].mimetype);
|
||||
}
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* If the top-level domain sends the STS header but does not have
|
||||
* includeSubdomains, HSTS priming requests should still be sent to
|
||||
* subdomains.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 0,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 1,
|
||||
},
|
||||
"keyed-histograms": {
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Observer.add_observers(Services);
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
// add the top-level server
|
||||
test_servers['localhost-ip'] = {
|
||||
host: '127.0.0.2',
|
||||
response: true,
|
||||
id: 'localhost-ip',
|
||||
};
|
||||
test_settings.block_active.result['localhost-ip'] = 'blocked';
|
||||
|
||||
let which = "block_active";
|
||||
|
||||
SetupPrefTestEnvironment(which);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
await execute_test("localhost-ip", test_settings[which].mimetype);
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* If the top-level domain sends the STS header but does not have
|
||||
* includeSubdomains, HSTS priming requests should still be sent to
|
||||
* subdomains.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 1,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 3,
|
||||
"HSTS_UPGRADE_SOURCE": [ 0,0,1,0,0,0,0,0,0 ]
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"success": 1,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Observer.add_observers(Services);
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
// add the top-level server
|
||||
test_servers['non-standard-port'] = {
|
||||
host: 'test1.example.com:1234',
|
||||
response: true,
|
||||
id: 'non-standard-port',
|
||||
};
|
||||
test_settings.block_active.result['non-standard-port'] = 'blocked';
|
||||
|
||||
let which = "block_active";
|
||||
|
||||
SetupPrefTestEnvironment(which);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
await execute_test("non-standard-port", test_settings[which].mimetype);
|
||||
|
||||
await execute_test("prime-hsts", test_settings[which].mimetype);
|
||||
|
||||
ok("prime-hsts" in test_settings[which_test].priming, "Sent priming request on standard port after non-standard was not primed");
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Description of the test:
|
||||
* Only one request should be sent per host, even if we run the test more
|
||||
* than once.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 3,
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": 3,
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"failure": 3,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
//jscs:disable
|
||||
add_task(async function() {
|
||||
//jscs:enable
|
||||
Observer.add_observers(Services);
|
||||
registerCleanupFunction(do_cleanup);
|
||||
|
||||
let which = "timeout";
|
||||
|
||||
SetupPrefTestEnvironment(which, [["security.mixed_content.hsts_priming_request_timeout",
|
||||
1000]]);
|
||||
clear_hists(expected_telemetry);
|
||||
|
||||
for (let server of Object.keys(test_servers)) {
|
||||
await execute_test(server, test_settings[which].mimetype);
|
||||
}
|
||||
|
||||
test_telemetry(expected_telemetry);
|
||||
|
||||
SpecialPowers.popPrefEnv();
|
||||
});
|
Двоичные данные
dom/security/test/hsts/file_1x1.png
Двоичные данные
dom/security/test/hsts/file_1x1.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 17 KiB |
|
@ -1,89 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1246540</title>
|
||||
<meta http-equiv='content-type' content="text/html;charset=utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="visibility: hidden">
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
/*
|
||||
* Description of the test:
|
||||
* Attempt to load an insecure resource. If the resource responds to HSTS
|
||||
* priming with an STS header, the load should continue securely.
|
||||
* If it does not, the load should continue be blocked or continue insecurely.
|
||||
*/
|
||||
|
||||
function parse_query_string() {
|
||||
var q = {};
|
||||
document.location.search.substr(1).
|
||||
split('&').forEach(function (item, idx, ar) {
|
||||
let [k, v] = item.split('=');
|
||||
q[k] = unescape(v);
|
||||
});
|
||||
return q;
|
||||
}
|
||||
|
||||
var args = parse_query_string();
|
||||
|
||||
var subresources = {
|
||||
css: { mimetype: 'text/css', file: 'file_stylesheet.css' },
|
||||
img: { mimetype: 'image/png', file: 'file_1x1.png' },
|
||||
script: { mimetype: 'text/javascript', file: 'file_priming.js' },
|
||||
};
|
||||
|
||||
function handler(ev) {
|
||||
console.log("HSTS_PRIMING: Blocked "+args.id);
|
||||
let elem = document.getElementById(args.id);
|
||||
elem.parentElement.removeChild(elem);
|
||||
}
|
||||
|
||||
function loadCss(src) {
|
||||
let head = document.getElementsByTagName("head")[0];
|
||||
let link = document.createElement("link");
|
||||
link.setAttribute("rel", "stylesheet");
|
||||
link.setAttribute("id", args.id);
|
||||
link.setAttribute("type", subresources[args.type].mimetype);
|
||||
link.setAttribute("href", src);
|
||||
link.onerror = handler;
|
||||
head.appendChild(link);
|
||||
}
|
||||
|
||||
function loadResource(src) {
|
||||
let content = document.getElementById("content");
|
||||
let testElem = document.createElement(args.type);
|
||||
testElem.setAttribute("id", args.id);
|
||||
testElem.setAttribute("charset", "UTF-8");
|
||||
testElem.onerror = handler;
|
||||
content.appendChild(testElem);
|
||||
testElem.src = src;
|
||||
}
|
||||
|
||||
function loadTest() {
|
||||
let subresource = subresources[args.type];
|
||||
|
||||
let src = "http://"
|
||||
+ args.host
|
||||
+ "/browser/dom/security/test/hsts/file_testserver.sjs"
|
||||
+ "?file=" +escape("browser/dom/security/test/hsts/" + subresource.file)
|
||||
+ "&primer=" + escape(args.id)
|
||||
+ "&mimetype=" + escape(subresource.mimetype)
|
||||
+ "&timeout=" + escape(args.timeout)
|
||||
;
|
||||
if (args.type == 'css') {
|
||||
loadCss(src);
|
||||
return;
|
||||
}
|
||||
|
||||
loadResource(src);
|
||||
}
|
||||
|
||||
// start running the tests
|
||||
loadTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,4 +0,0 @@
|
|||
function completed() {
|
||||
return;
|
||||
}
|
||||
completed();
|
|
@ -1 +0,0 @@
|
|||
body {}
|
|
@ -1,84 +0,0 @@
|
|||
// SJS file for HSTS mochitests
|
||||
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
Components.utils.importGlobalProperties(["URLSearchParams"]);
|
||||
|
||||
function loadFromFile(path) {
|
||||
// Load the HTML to return in the response from file.
|
||||
// Since it's relative to the cwd of the test runner, we start there and
|
||||
// append to get to the actual path of the file.
|
||||
var testFile =
|
||||
Components.classes["@mozilla.org/file/directory_service;1"].
|
||||
getService(Components.interfaces.nsIProperties).
|
||||
get("CurWorkD", Components.interfaces.nsIFile);
|
||||
var dirs = path.split("/");
|
||||
for (var i = 0; i < dirs.length; i++) {
|
||||
testFile.append(dirs[i]);
|
||||
}
|
||||
var testFileStream =
|
||||
Components.classes["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileInputStream);
|
||||
testFileStream.init(testFile, -1, 0, 0);
|
||||
var test = NetUtil.readInputStreamToString(testFileStream, testFileStream.available());
|
||||
return test;
|
||||
}
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
const query = new URLSearchParams(request.queryString);
|
||||
|
||||
var timeout = parseInt(query.get('timeout'));
|
||||
response.processAsync();
|
||||
|
||||
timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
|
||||
timer.initWithCallback(function()
|
||||
{
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
|
||||
// avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
redir = query.get('redir');
|
||||
if (redir == 'same') {
|
||||
query.delete("redir");
|
||||
response.setStatus(302);
|
||||
let newURI = request.uri;
|
||||
newURI.queryString = query.serialize();
|
||||
response.setHeader("Location", newURI.spec)
|
||||
response.write('xyzzy');
|
||||
response.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// if we have a priming header, check for required behavior
|
||||
// and set header appropriately
|
||||
if (request.hasHeader('Upgrade-Insecure-Requests')) {
|
||||
var expected = query.get('primer');
|
||||
if (expected == 'prime-hsts' || expected == 'top-level') {
|
||||
// set it for 5 minutes
|
||||
response.setHeader("Strict-Transport-Security", "max-age="+(60*5), false);
|
||||
} else if (expected == 'reject-upgrade') {
|
||||
response.setHeader("Strict-Transport-Security", "max-age=0", false);
|
||||
}
|
||||
response.write('xyzzy');
|
||||
response.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var file = query.get('file');
|
||||
if (file) {
|
||||
var mimetype = unescape(query.get('mimetype'));
|
||||
response.setHeader("Content-Type", mimetype, false);
|
||||
let contents = loadFromFile(unescape(file));
|
||||
response.write(contents);
|
||||
response.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
response.setHeader("Content-Type", "application/json", false);
|
||||
response.write('{}');
|
||||
response.finish();
|
||||
}, timeout, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
|
@ -1,543 +0,0 @@
|
|||
/*
|
||||
* Description of the tests:
|
||||
* Check that HSTS priming occurs correctly with mixed content
|
||||
*
|
||||
* This test uses three hostnames, each of which treats an HSTS priming
|
||||
* request differently.
|
||||
* * no-ssl never returns an ssl response
|
||||
* * reject-upgrade returns an ssl response, but with no STS header
|
||||
* * prime-hsts returns an ssl response with the appropriate STS header
|
||||
*
|
||||
* For each server, test that it response appropriately when the we allow
|
||||
* or block active or display content, as well as when we send an hsts priming
|
||||
* request, but do not change the order of mixed-content and HSTS.
|
||||
*
|
||||
* Test use http-on-examine-response, so must be run in browser context.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
var TOP_URI = "https://example.com/browser/dom/security/test/hsts/file_priming-top.html";
|
||||
|
||||
var test_servers = {
|
||||
// a test server that does not support TLS
|
||||
'no-ssl': {
|
||||
host: 'example.co.jp',
|
||||
response: false,
|
||||
id: 'no-ssl',
|
||||
},
|
||||
// a test server which does not support STS upgrade
|
||||
'reject-upgrade': {
|
||||
host: 'example.org',
|
||||
response: true,
|
||||
id: 'reject-upgrade',
|
||||
},
|
||||
// a test server when sends an STS header when priming
|
||||
'prime-hsts': {
|
||||
host: 'test1.example.com',
|
||||
response: true,
|
||||
id: 'prime-hsts'
|
||||
},
|
||||
};
|
||||
|
||||
var test_settings = {
|
||||
// mixed active content is allowed, priming will upgrade
|
||||
allow_active: {
|
||||
block_active: false,
|
||||
block_display: false,
|
||||
use_hsts: true,
|
||||
send_hsts_priming: true,
|
||||
type: 'script',
|
||||
timeout: 0,
|
||||
result: {
|
||||
'no-ssl': 'insecure',
|
||||
'reject-upgrade': 'insecure',
|
||||
'prime-hsts': 'secure',
|
||||
},
|
||||
},
|
||||
// mixed active content is blocked, priming will upgrade
|
||||
block_active: {
|
||||
block_active: true,
|
||||
block_display: false,
|
||||
use_hsts: true,
|
||||
send_hsts_priming: true,
|
||||
type: 'script',
|
||||
timeout: 0,
|
||||
result: {
|
||||
'no-ssl': 'blocked',
|
||||
'reject-upgrade': 'blocked',
|
||||
'prime-hsts': 'secure',
|
||||
},
|
||||
},
|
||||
// keep the original order of mixed-content and HSTS, but send
|
||||
// priming requests
|
||||
hsts_after_mixed: {
|
||||
block_active: true,
|
||||
block_display: false,
|
||||
use_hsts: false,
|
||||
send_hsts_priming: true,
|
||||
type: 'script',
|
||||
timeout: 0,
|
||||
result: {
|
||||
'no-ssl': 'blocked',
|
||||
'reject-upgrade': 'blocked',
|
||||
'prime-hsts': 'blocked',
|
||||
},
|
||||
},
|
||||
// mixed display content is allowed, priming will upgrade
|
||||
allow_display: {
|
||||
block_active: true,
|
||||
block_display: false,
|
||||
use_hsts: true,
|
||||
send_hsts_priming: true,
|
||||
type: 'img',
|
||||
timeout: 0,
|
||||
result: {
|
||||
'no-ssl': 'insecure',
|
||||
'reject-upgrade': 'insecure',
|
||||
'prime-hsts': 'secure',
|
||||
},
|
||||
},
|
||||
// mixed display content is blocked, priming will upgrade
|
||||
block_display: {
|
||||
block_active: true,
|
||||
block_display: true,
|
||||
use_hsts: true,
|
||||
send_hsts_priming: true,
|
||||
type: 'img',
|
||||
timeout: 0,
|
||||
result: {
|
||||
'no-ssl': 'blocked',
|
||||
'reject-upgrade': 'blocked',
|
||||
'prime-hsts': 'secure',
|
||||
},
|
||||
},
|
||||
// mixed active content is blocked, priming will upgrade (css)
|
||||
block_active_css: {
|
||||
block_active: true,
|
||||
block_display: true,
|
||||
use_hsts: true,
|
||||
send_hsts_priming: true,
|
||||
type: 'css',
|
||||
timeout: 0,
|
||||
result: {
|
||||
'no-ssl': 'blocked',
|
||||
'reject-upgrade': 'blocked',
|
||||
'prime-hsts': 'secure',
|
||||
},
|
||||
},
|
||||
// mixed active content is blocked, priming will upgrade
|
||||
// redirect to the same host
|
||||
block_active_with_redir_same: {
|
||||
block_active: true,
|
||||
block_display: false,
|
||||
use_hsts: true,
|
||||
send_hsts_priming: true,
|
||||
type: 'script',
|
||||
redir: 'same',
|
||||
timeout: 0,
|
||||
result: {
|
||||
'no-ssl': 'blocked',
|
||||
'reject-upgrade': 'blocked',
|
||||
'prime-hsts': 'secure',
|
||||
},
|
||||
},
|
||||
// mixed active content is blocked, priming will upgrade
|
||||
// redirect to the same host
|
||||
timeout: {
|
||||
block_active: true,
|
||||
block_display: true,
|
||||
use_hsts: true,
|
||||
send_hsts_priming: true,
|
||||
type: 'script',
|
||||
timeout: 100000,
|
||||
result: {
|
||||
'no-ssl': 'blocked',
|
||||
'reject-upgrade': 'blocked',
|
||||
'prime-hsts': 'blocked',
|
||||
},
|
||||
},
|
||||
}
|
||||
// track which test we are on
|
||||
var which_test = "";
|
||||
|
||||
/**
|
||||
* A stream listener that just forwards all calls
|
||||
*/
|
||||
var StreamListener = function(subject) {
|
||||
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let traceable = subject.QueryInterface(Ci.nsITraceableChannel);
|
||||
|
||||
this.uri = channel.URI.asciiSpec;
|
||||
this.listener = traceable.setNewListener(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
// Next three methods are part of `nsIStreamListener` interface and are
|
||||
// invoked by `nsIInputStreamPump.asyncRead`.
|
||||
StreamListener.prototype.onDataAvailable = function(request, context, input, offset, count) {
|
||||
if (request.status == Cr.NS_ERROR_ABORT) {
|
||||
this.listener = null;
|
||||
return Cr.NS_SUCCESS;
|
||||
}
|
||||
let listener = this.listener;
|
||||
if (listener) {
|
||||
try {
|
||||
let rv = listener.onDataAvailable(request, context, input, offset, count);
|
||||
if (rv != Cr.NS_ERROR_ABORT) {
|
||||
// If the channel gets canceled, we sometimes get NS_ERROR_ABORT here.
|
||||
// Anything else is an error.
|
||||
return rv;
|
||||
}
|
||||
} catch (e) {
|
||||
if (e != Cr.NS_ERROR_ABORT) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Cr.NS_SUCCESS;
|
||||
};
|
||||
|
||||
// Next two methods implement `nsIRequestObserver` interface and are invoked
|
||||
// by `nsIInputStreamPump.asyncRead`.
|
||||
StreamListener.prototype.onStartRequest = function(request, context) {
|
||||
if (request.status == Cr.NS_ERROR_ABORT) {
|
||||
this.listener = null;
|
||||
return Cr.NS_SUCCESS;
|
||||
}
|
||||
let listener = this.listener;
|
||||
if (listener) {
|
||||
try {
|
||||
let rv = listener.onStartRequest(request, context);
|
||||
if (rv != Cr.NS_ERROR_ABORT) {
|
||||
// If the channel gets canceled, we sometimes get NS_ERROR_ABORT here.
|
||||
// Anything else is an error.
|
||||
return rv;
|
||||
}
|
||||
} catch (e) {
|
||||
if (e != Cr.NS_ERROR_ABORT) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Cr.NS_SUCCESS;
|
||||
};
|
||||
|
||||
// Called to signify the end of an asynchronous request. We only care to
|
||||
// discover errors.
|
||||
StreamListener.prototype.onStopRequest = function(request, context, status) {
|
||||
if (status == Cr.NS_ERROR_ABORT) {
|
||||
this.listener = null;
|
||||
return Cr.NS_SUCCESS;
|
||||
}
|
||||
let listener = this.listener;
|
||||
if (listener) {
|
||||
try {
|
||||
let rv = listener.onStopRequest(request, context, status);
|
||||
if (rv != Cr.NS_ERROR_ABORT) {
|
||||
// If the channel gets canceled, we sometimes get NS_ERROR_ABORT here.
|
||||
// Anything else is an error.
|
||||
return rv;
|
||||
}
|
||||
} catch (e) {
|
||||
if (e != Cr.NS_ERROR_ABORT) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Cr.NS_SUCCESS;
|
||||
};
|
||||
|
||||
var Observer = {
|
||||
listeners: {},
|
||||
observe: function (subject, topic, data) {
|
||||
switch (topic) {
|
||||
case 'console-api-log-event':
|
||||
return Observer.console_api_log_event(subject, topic, data);
|
||||
case 'http-on-examine-response':
|
||||
return Observer.http_on_examine_response(subject, topic, data);
|
||||
case 'http-on-modify-request':
|
||||
return Observer.http_on_modify_request(subject, topic, data);
|
||||
}
|
||||
throw "Can't handle topic "+topic;
|
||||
},
|
||||
add_observers: function (services, include_on_modify = false) {
|
||||
services.obs.addObserver(Observer, "console-api-log-event");
|
||||
services.obs.addObserver(Observer, "http-on-examine-response");
|
||||
services.obs.addObserver(Observer, "http-on-modify-request");
|
||||
},
|
||||
cleanup: function () {
|
||||
this.listeners = {};
|
||||
},
|
||||
// When a load is blocked which results in an error event within a page, the
|
||||
// test logs to the console.
|
||||
console_api_log_event: function (subject, topic, data) {
|
||||
var message = subject.wrappedJSObject.arguments[0];
|
||||
// when we are blocked, this will match the message we sent to the console,
|
||||
// ignore everything else.
|
||||
var re = RegExp(/^HSTS_PRIMING: Blocked ([-\w]+).*$/);
|
||||
if (!re.test(message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let id = message.replace(re, '$1');
|
||||
let curTest =test_servers[id];
|
||||
|
||||
if (!curTest) {
|
||||
ok(false, "HSTS priming got a console message blocked, "+
|
||||
"but doesn't match expectations "+id+" (msg="+message);
|
||||
return;
|
||||
}
|
||||
|
||||
is("blocked", test_settings[which_test].result[curTest.id], "HSTS priming "+
|
||||
which_test+":"+curTest.id+" expected "+
|
||||
test_settings[which_test].result[curTest.id]+", got blocked");
|
||||
test_settings[which_test].finished[curTest.id] = "blocked";
|
||||
},
|
||||
get_current_test: function(uri) {
|
||||
for (let item in test_servers) {
|
||||
let re = RegExp('https?://'+test_servers[item].host+'.*\/browser/dom/security/test/hsts/file_testserver.sjs');
|
||||
if (re.test(uri)) {
|
||||
return test_servers[item];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
http_on_modify_request: function (subject, topic, data) {
|
||||
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let uri = channel.URI.asciiSpec;
|
||||
|
||||
let curTest = this.get_current_test(channel.URI.asciiSpec);
|
||||
|
||||
if (!curTest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(uri in this.listeners)) {
|
||||
// Add an nsIStreamListener to ensure that the listener is not NULL
|
||||
this.listeners[uri] = new StreamListener(subject);
|
||||
}
|
||||
|
||||
if (channel.requestMethod != 'HEAD') {
|
||||
return;
|
||||
}
|
||||
if (typeof ok === 'undefined') {
|
||||
// we are in the wrong thread and ok and is not available
|
||||
return;
|
||||
}
|
||||
ok(!(curTest.id in test_settings[which_test].priming), "Already saw a priming request for " + curTest.id);
|
||||
test_settings[which_test].priming[curTest.id] = true;
|
||||
},
|
||||
// When we see a response come back, peek at the response and test it is secure
|
||||
// or insecure as needed. Addtionally, watch the response for priming requests.
|
||||
http_on_examine_response: function (subject, topic, data) {
|
||||
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let curTest = this.get_current_test(channel.URI.asciiSpec);
|
||||
let uri = channel.URI.asciiSpec;
|
||||
|
||||
if (!curTest) {
|
||||
return;
|
||||
}
|
||||
|
||||
let result = (channel.URI.asciiSpec.startsWith('https:')) ? "secure" : "insecure";
|
||||
|
||||
// This is a priming request, go ahead and validate we were supposed to see
|
||||
// a response from the server
|
||||
if (channel.requestMethod == 'HEAD') {
|
||||
is(true, curTest.response, "HSTS priming response found " + curTest.id);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the response to our query, make sure it matches
|
||||
is(result, test_settings[which_test].result[curTest.id],
|
||||
"HSTS priming result " + which_test + ":" + curTest.id);
|
||||
test_settings[which_test].finished[curTest.id] = result;
|
||||
if (this.listeners[uri]) {
|
||||
this.listeners[uri] = undefined;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// opens `uri' in a new tab and focuses it.
|
||||
// returns the newly opened tab
|
||||
function openTab(uri) {
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, uri);
|
||||
|
||||
// select tab and make sure its browser is focused
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.ownerGlobal.focus();
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
||||
function clear_sts_data() {
|
||||
for (let test in test_servers) {
|
||||
SpecialPowers.cleanUpSTSData('http://'+test_servers[test].host);
|
||||
}
|
||||
}
|
||||
|
||||
var oldCanRecord = Services.telemetry.canRecordExtended;
|
||||
|
||||
function do_cleanup() {
|
||||
clear_sts_data();
|
||||
|
||||
Services.obs.removeObserver(Observer, "console-api-log-event");
|
||||
Services.obs.removeObserver(Observer, "http-on-examine-response");
|
||||
|
||||
Services.telemetry.canRecordExtended = oldCanRecord;
|
||||
|
||||
Observer.cleanup();
|
||||
}
|
||||
|
||||
function SetupPrefTestEnvironment(which, additional_prefs) {
|
||||
which_test = which;
|
||||
clear_sts_data();
|
||||
|
||||
var settings = test_settings[which];
|
||||
// priming counts how many priming requests we saw
|
||||
settings.priming = {};
|
||||
// priming counts how many tests were finished
|
||||
settings.finished= {};
|
||||
|
||||
var prefs = [["security.mixed_content.block_active_content",
|
||||
settings.block_active],
|
||||
["security.mixed_content.block_display_content",
|
||||
settings.block_display],
|
||||
["security.mixed_content.use_hsts",
|
||||
settings.use_hsts],
|
||||
["security.mixed_content.send_hsts_priming",
|
||||
settings.send_hsts_priming],
|
||||
];
|
||||
|
||||
if (additional_prefs) {
|
||||
for (let idx in additional_prefs) {
|
||||
prefs.push(additional_prefs[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
Services.telemetry.canRecordExtended = true;
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': prefs});
|
||||
}
|
||||
|
||||
// make the top-level test uri
|
||||
function build_test_uri(base_uri, host, test_id, type, timeout) {
|
||||
return base_uri +
|
||||
"?host=" + escape(host) +
|
||||
"&id=" + escape(test_id) +
|
||||
"&type=" + escape(type) +
|
||||
"&timeout=" + escape(timeout)
|
||||
;
|
||||
}
|
||||
|
||||
// open a new tab, load the test, and wait for it to finish
|
||||
async function execute_test(test, mimetype) {
|
||||
var src = build_test_uri(TOP_URI, test_servers[test].host,
|
||||
test, test_settings[which_test].type,
|
||||
test_settings[which_test].timeout);
|
||||
|
||||
await BrowserTestUtils.withNewTab(src, () => {});
|
||||
}
|
||||
|
||||
/* Expected should look something like this:
|
||||
* The numbers are the sum of all telemetry values.
|
||||
var expected_telemetry = {
|
||||
"histograms": {
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": 6,
|
||||
"HSTS_PRIMING_REQUESTS": 10,
|
||||
"HSTS_UPGRADE_SOURCE": [ 0,0,2,0,0,0,0,0,0 ]
|
||||
},
|
||||
"keyed-histograms": {
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"success": 1,
|
||||
"failure": 2,
|
||||
},
|
||||
}
|
||||
};
|
||||
*/
|
||||
function test_telemetry(expected) {
|
||||
for (let key in expected['histograms']) {
|
||||
let hs = undefined;
|
||||
try {
|
||||
let hist = Services.telemetry.getHistogramById(key);
|
||||
hs = hist.snapshot();
|
||||
hist.clear();
|
||||
} catch(e) {
|
||||
ok(false, "Caught exception trying to get histogram for key " + key + ":" + e);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hs) {
|
||||
ok(false, "No histogram found for key " + key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Array.isArray(expected['histograms'][key])) {
|
||||
var is_ok = true;
|
||||
if (expected['histograms'][key].length != hs.counts.length) {
|
||||
ok(false, "Histogram lengths match");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let idx in expected['histograms'][key]) {
|
||||
is_ok = (hs.counts[idx] >= expected['histograms'][key][idx]);
|
||||
if (!is_ok) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(is_ok, "Histogram counts match for " + key + " - Got " + hs.counts + ", expected " + expected['histograms'][key]);
|
||||
} else {
|
||||
// there may have been other background requests processed
|
||||
ok(hs.counts.reduce(sum) >= expected['histograms'][key], "Histogram counts match expected, got " + hs.counts.reduce(sum) + ", expected at least " + expected['histograms'][key]);
|
||||
}
|
||||
}
|
||||
|
||||
for (let key in expected['keyed-histograms']) {
|
||||
let hs = undefined;
|
||||
try {
|
||||
let hist = Services.telemetry.getKeyedHistogramById(key);
|
||||
hs = hist.snapshot();
|
||||
hist.clear();
|
||||
} catch(e) {
|
||||
ok(false, "Caught exception trying to get histogram for key " + key + " :" + e);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hs) {
|
||||
ok(false, "No keyed histogram found for key " + key);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let hist_key in expected['keyed-histograms'][key]) {
|
||||
ok(hist_key in hs, "Keyed histogram exists with key");
|
||||
if (hist_key in hs) {
|
||||
ok(hs[hist_key].counts.reduce(sum) >= expected['keyed-histograms'][key][hist_key], "Keyed histogram counts match expected got " + hs[hist_key].counts.reduce(sum) + ", expected at least " + expected['keyed-histograms'][key][hist_key])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sum(a, b) {
|
||||
return a+b;
|
||||
}
|
||||
|
||||
function clear_hists(hists) {
|
||||
for (let key in hists['histograms']) {
|
||||
try {
|
||||
let hist = Services.telemetry.getHistogramById(key);
|
||||
hist.clear();
|
||||
} catch(e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (let key in hists['keyed-histograms']) {
|
||||
try {
|
||||
let hist = Services.telemetry.getKeyedHistogramById(key);
|
||||
hist.clear();
|
||||
} catch(e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -162,9 +162,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=62178
|
|||
}
|
||||
|
||||
function startTest() {
|
||||
// Set prefs to use mixed-content before HSTS
|
||||
SpecialPowers.pushPrefEnv({'set': [["security.mixed_content.use_hsts", false],
|
||||
["security.mixed_content.send_hsts_priming", false]]});
|
||||
//Set the first set of mixed content settings and increment the counter.
|
||||
changePrefs([], function() {
|
||||
//listen for a messages from the mixed content test harness
|
||||
|
|
|
@ -36,13 +36,8 @@ function receiveMessage(event) {
|
|||
}
|
||||
|
||||
function startTest() {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
'set': [["security.mixed_content.use_hsts", false],
|
||||
["security.mixed_content.send_hsts_priming", false]]
|
||||
}, function () {
|
||||
let testframe = document.getElementById("testframe");
|
||||
testframe.src = PATH + "file_redirect.html";
|
||||
});
|
||||
let testframe = document.getElementById("testframe");
|
||||
testframe.src = PATH + "file_redirect.html";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
@ -31,5 +31,4 @@ BROWSER_CHROME_MANIFESTS += [
|
|||
'cors/browser.ini',
|
||||
'csp/browser.ini',
|
||||
'general/browser.ini',
|
||||
'hsts/browser.ini',
|
||||
]
|
||||
|
|
|
@ -685,19 +685,6 @@ ShouldLoadCachedImage(imgRequest* aImgRequest,
|
|||
}
|
||||
}
|
||||
|
||||
bool sendPriming = false;
|
||||
bool mixedContentWouldBlock = false;
|
||||
rv = nsMixedContentBlocker::GetHSTSPrimingFromRequestingContext(contentLocation,
|
||||
aLoadingContext, &sendPriming, &mixedContentWouldBlock);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
if (sendPriming && mixedContentWouldBlock) {
|
||||
// if either of the securty checks above would cause a priming request, we
|
||||
// can't load this image from the cache, so go ahead and return false here
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -398,11 +398,7 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
|
|||
aLoadInfo->GetForcePreflight(),
|
||||
aLoadInfo->GetIsPreflight(),
|
||||
aLoadInfo->GetLoadTriggeredFromExternal(),
|
||||
aLoadInfo->GetServiceWorkerTaintingSynthesized(),
|
||||
aLoadInfo->GetForceHSTSPriming(),
|
||||
aLoadInfo->GetMixedContentWouldBlock(),
|
||||
aLoadInfo->GetIsHSTSPriming(),
|
||||
aLoadInfo->GetIsHSTSPrimingUpgrade()
|
||||
aLoadInfo->GetServiceWorkerTaintingSynthesized()
|
||||
);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -508,11 +504,7 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs,
|
|||
loadInfoArgs.forcePreflight(),
|
||||
loadInfoArgs.isPreflight(),
|
||||
loadInfoArgs.loadTriggeredFromExternal(),
|
||||
loadInfoArgs.serviceWorkerTaintingSynthesized(),
|
||||
loadInfoArgs.forceHSTSPriming(),
|
||||
loadInfoArgs.mixedContentWouldBlock(),
|
||||
loadInfoArgs.isHSTSPriming(),
|
||||
loadInfoArgs.isHSTSPrimingUpgrade()
|
||||
loadInfoArgs.serviceWorkerTaintingSynthesized()
|
||||
);
|
||||
|
||||
loadInfo.forget(outLoadInfo);
|
||||
|
|
|
@ -5794,25 +5794,6 @@ pref("layout.css.servo.enabled", false);
|
|||
pref("layout.css.servo.chrome.enabled", false);
|
||||
#endif
|
||||
|
||||
// HSTS Priming
|
||||
// If a request is mixed-content, send an HSTS priming request to attempt to
|
||||
// see if it is available over HTTPS.
|
||||
// Don't change the order of evaluation of mixed-content and HSTS upgrades in
|
||||
// order to be most compatible with current standards in Release
|
||||
pref("security.mixed_content.send_hsts_priming", false);
|
||||
pref("security.mixed_content.use_hsts", false);
|
||||
#ifdef EARLY_BETA_OR_EARLIER
|
||||
// Change the order of evaluation so HSTS upgrades happen before
|
||||
// mixed-content blocking
|
||||
pref("security.mixed_content.send_hsts_priming", true);
|
||||
pref("security.mixed_content.use_hsts", true);
|
||||
#endif
|
||||
// Approximately 1 week default cache for HSTS priming failures, in seconds
|
||||
pref("security.mixed_content.hsts_priming_cache_timeout", 604800);
|
||||
// Force the channel to timeout in 2 seconds if we have not received
|
||||
// expects a time in milliseconds
|
||||
pref("security.mixed_content.hsts_priming_request_timeout", 2000);
|
||||
|
||||
// TODO: Bug 1324406: Treat 'data:' documents as unique, opaque origins
|
||||
// If true, data: URIs will be treated as unique opaque origins, hence will use
|
||||
// a NullPrincipal as the security context.
|
||||
|
|
|
@ -74,10 +74,6 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
|||
, mIsPreflight(false)
|
||||
, mLoadTriggeredFromExternal(false)
|
||||
, mServiceWorkerTaintingSynthesized(false)
|
||||
, mForceHSTSPriming(false)
|
||||
, mMixedContentWouldBlock(false)
|
||||
, mIsHSTSPriming(false)
|
||||
, mIsHSTSPrimingUpgrade(false)
|
||||
{
|
||||
MOZ_ASSERT(mLoadingPrincipal);
|
||||
MOZ_ASSERT(mTriggeringPrincipal);
|
||||
|
@ -264,10 +260,6 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
|
|||
, mIsPreflight(false)
|
||||
, mLoadTriggeredFromExternal(false)
|
||||
, mServiceWorkerTaintingSynthesized(false)
|
||||
, mForceHSTSPriming(false)
|
||||
, mMixedContentWouldBlock(false)
|
||||
, mIsHSTSPriming(false)
|
||||
, mIsHSTSPrimingUpgrade(false)
|
||||
{
|
||||
// Top-level loads are never third-party
|
||||
// Grab the information we can out of the window.
|
||||
|
@ -346,10 +338,6 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
|
|||
, mIsPreflight(rhs.mIsPreflight)
|
||||
, mLoadTriggeredFromExternal(rhs.mLoadTriggeredFromExternal)
|
||||
, mServiceWorkerTaintingSynthesized(rhs.mServiceWorkerTaintingSynthesized)
|
||||
, mForceHSTSPriming(rhs.mForceHSTSPriming)
|
||||
, mMixedContentWouldBlock(rhs.mMixedContentWouldBlock)
|
||||
, mIsHSTSPriming(rhs.mIsHSTSPriming)
|
||||
, mIsHSTSPrimingUpgrade(rhs.mIsHSTSPrimingUpgrade)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -383,11 +371,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
|||
bool aForcePreflight,
|
||||
bool aIsPreflight,
|
||||
bool aLoadTriggeredFromExternal,
|
||||
bool aServiceWorkerTaintingSynthesized,
|
||||
bool aForceHSTSPriming,
|
||||
bool aMixedContentWouldBlock,
|
||||
bool aIsHSTSPriming,
|
||||
bool aIsHSTSPrimingUpgrade)
|
||||
bool aServiceWorkerTaintingSynthesized)
|
||||
: mLoadingPrincipal(aLoadingPrincipal)
|
||||
, mTriggeringPrincipal(aTriggeringPrincipal)
|
||||
, mPrincipalToInherit(aPrincipalToInherit)
|
||||
|
@ -416,10 +400,6 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
|||
, mIsPreflight(aIsPreflight)
|
||||
, mLoadTriggeredFromExternal(aLoadTriggeredFromExternal)
|
||||
, mServiceWorkerTaintingSynthesized(aServiceWorkerTaintingSynthesized)
|
||||
, mForceHSTSPriming (aForceHSTSPriming)
|
||||
, mMixedContentWouldBlock(aMixedContentWouldBlock)
|
||||
, mIsHSTSPriming(aIsHSTSPriming)
|
||||
, mIsHSTSPrimingUpgrade(aIsHSTSPrimingUpgrade)
|
||||
{
|
||||
// Only top level TYPE_DOCUMENT loads can have a null loadingPrincipal
|
||||
MOZ_ASSERT(mLoadingPrincipal || aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT);
|
||||
|
@ -1068,66 +1048,6 @@ LoadInfo::GetServiceWorkerTaintingSynthesized(bool* aServiceWorkerTaintingSynthe
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetForceHSTSPriming(bool* aForceHSTSPriming)
|
||||
{
|
||||
*aForceHSTSPriming = mForceHSTSPriming;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetMixedContentWouldBlock(bool *aMixedContentWouldBlock)
|
||||
{
|
||||
*aMixedContentWouldBlock = mMixedContentWouldBlock;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
LoadInfo::SetHSTSPriming(bool aMixedContentWouldBlock)
|
||||
{
|
||||
mForceHSTSPriming = true;
|
||||
mMixedContentWouldBlock = aMixedContentWouldBlock;
|
||||
}
|
||||
|
||||
void
|
||||
LoadInfo::ClearHSTSPriming()
|
||||
{
|
||||
mForceHSTSPriming = false;
|
||||
mMixedContentWouldBlock = false;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::SetIsHSTSPriming(bool aIsHSTSPriming)
|
||||
{
|
||||
MOZ_ASSERT(aIsHSTSPriming);
|
||||
mIsHSTSPriming = aIsHSTSPriming;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetIsHSTSPriming(bool* aIsHSTSPriming)
|
||||
{
|
||||
MOZ_ASSERT(aIsHSTSPriming);
|
||||
*aIsHSTSPriming = mIsHSTSPriming;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::SetIsHSTSPrimingUpgrade(bool aIsHSTSPrimingUpgrade)
|
||||
{
|
||||
MOZ_ASSERT(aIsHSTSPrimingUpgrade);
|
||||
mIsHSTSPrimingUpgrade = aIsHSTSPrimingUpgrade;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetIsHSTSPrimingUpgrade(bool* aIsHSTSPrimingUpgrade)
|
||||
{
|
||||
MOZ_ASSERT(aIsHSTSPrimingUpgrade);
|
||||
*aIsHSTSPrimingUpgrade = mIsHSTSPrimingUpgrade;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetTainting(uint32_t* aTaintingOut)
|
||||
{
|
||||
|
|
|
@ -124,11 +124,7 @@ private:
|
|||
bool aForcePreflight,
|
||||
bool aIsPreflight,
|
||||
bool aLoadTriggeredFromExternal,
|
||||
bool aServiceWorkerTaintingSynthesized,
|
||||
bool aForceHSTSPriming,
|
||||
bool aMixedContentWouldBlock,
|
||||
bool aIsHSTSPriming,
|
||||
bool aIsHSTSPrimingUpgrade);
|
||||
bool aServiceWorkerTaintingSynthesized);
|
||||
LoadInfo(const LoadInfo& rhs);
|
||||
|
||||
NS_IMETHOD GetRedirects(JSContext* aCx, JS::MutableHandle<JS::Value> aRedirects,
|
||||
|
@ -190,11 +186,6 @@ private:
|
|||
bool mIsPreflight;
|
||||
bool mLoadTriggeredFromExternal;
|
||||
bool mServiceWorkerTaintingSynthesized;
|
||||
|
||||
bool mForceHSTSPriming : 1;
|
||||
bool mMixedContentWouldBlock : 1;
|
||||
bool mIsHSTSPriming: 1;
|
||||
bool mIsHSTSPrimingUpgrade: 1;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
|
|
@ -744,42 +744,6 @@ interface nsILoadInfo : nsISupports
|
|||
*/
|
||||
[infallible] readonly attribute boolean isPreflight;
|
||||
|
||||
/**
|
||||
* When this request would be mixed-content and we do not have an
|
||||
* entry in the HSTS cache, we send an HSTS priming request to
|
||||
* determine if it is ok to upgrade the request to HTTPS.
|
||||
*/
|
||||
/**
|
||||
* True if this is a mixed-content load and HSTS priming request will be sent.
|
||||
*/
|
||||
[noscript, infallible] readonly attribute boolean forceHSTSPriming;
|
||||
/**
|
||||
* Carry the decision whether this load would be blocked by mixed content so
|
||||
* that if HSTS priming fails, the correct decision can be made.
|
||||
*/
|
||||
[noscript, infallible] readonly attribute boolean mixedContentWouldBlock;
|
||||
|
||||
/**
|
||||
* True if this load is an HSTS priming request.
|
||||
*/
|
||||
[noscript, infallible] attribute boolean isHSTSPriming;
|
||||
|
||||
/**
|
||||
* True if this load was upgraded from HSTS priming
|
||||
*/
|
||||
[noscript, infallible] attribute boolean isHSTSPrimingUpgrade;
|
||||
|
||||
/**
|
||||
* Mark this LoadInfo as needing HSTS Priming
|
||||
*
|
||||
* @param wouldBlock Carry the decision of Mixed Content Blocking to be
|
||||
* applied when HSTS priming is complete.
|
||||
*/
|
||||
[noscript, notxpcom, nostdcall]
|
||||
void setHSTSPriming(in boolean mixeContentWouldBlock);
|
||||
[noscript, notxpcom, nostdcall]
|
||||
void clearHSTSPriming();
|
||||
|
||||
/**
|
||||
* Constants reflecting the channel tainting. These are mainly defined here
|
||||
* for script. Internal C++ code should use the enum defined in LoadTainting.h.
|
||||
|
|
|
@ -2807,14 +2807,6 @@ NS_ShouldSecureUpgrade(nsIURI* aURI,
|
|||
aShouldUpgrade = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aLoadInfo->GetForceHSTSPriming()) {
|
||||
// don't log requests which might be upgraded due to HSTS Priming
|
||||
// they get logged in nsHttpChannel::OnHSTSPrimingSucceeded or
|
||||
// nsHttpChannel::OnHSTSPrimingFailed if the load is allowed to proceed.
|
||||
aShouldUpgrade = false;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// enforce Strict-Transport-Security
|
||||
|
@ -2844,9 +2836,6 @@ NS_ShouldSecureUpgrade(nsIURI* aURI,
|
|||
case nsISiteSecurityService::SOURCE_ORGANIC_REQUEST:
|
||||
Telemetry::Accumulate(Telemetry::HSTS_UPGRADE_SOURCE, 1);
|
||||
break;
|
||||
case nsISiteSecurityService::SOURCE_HSTS_PRIMING:
|
||||
Telemetry::Accumulate(Telemetry::HSTS_UPGRADE_SOURCE, 2);
|
||||
break;
|
||||
case nsISiteSecurityService::SOURCE_UNKNOWN:
|
||||
default:
|
||||
// record this as an organic request
|
||||
|
@ -2861,21 +2850,6 @@ NS_ShouldSecureUpgrade(nsIURI* aURI,
|
|||
Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 1);
|
||||
}
|
||||
} else {
|
||||
if (aLoadInfo) {
|
||||
if (aLoadInfo->GetIsHSTSPriming()) {
|
||||
// don't log HSTS priming requests
|
||||
aShouldUpgrade = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aLoadInfo->GetIsHSTSPrimingUpgrade()) {
|
||||
// if the upgrade occured due to HSTS priming, it was logged in
|
||||
// nsHttpChannel::OnHSTSPrimingSucceeded before redirect
|
||||
aShouldUpgrade = false;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 0);
|
||||
}
|
||||
aShouldUpgrade = false;
|
||||
|
|
|
@ -73,10 +73,6 @@ struct LoadInfoArgs
|
|||
bool isPreflight;
|
||||
bool loadTriggeredFromExternal;
|
||||
bool serviceWorkerTaintingSynthesized;
|
||||
bool forceHSTSPriming;
|
||||
bool mixedContentWouldBlock;
|
||||
bool isHSTSPriming;
|
||||
bool isHSTSPrimingUpgrade;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,396 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
#include "HttpLog.h"
|
||||
|
||||
#include "nsHttp.h"
|
||||
|
||||
#include "HSTSPrimerListener.h"
|
||||
#include "nsIHstsPrimingCallback.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsSecurityHeaderParser.h"
|
||||
#include "nsISiteSecurityService.h"
|
||||
#include "nsISocketProvider.h"
|
||||
#include "nsISSLStatus.h"
|
||||
#include "nsISSLStatusProvider.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsStreamListenerWrapper.h"
|
||||
#include "nsHttpChannel.h"
|
||||
#include "LoadInfo.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsQueryObject.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS(HSTSPrimingListener, nsIStreamListener,
|
||||
nsIRequestObserver, nsIInterfaceRequestor,
|
||||
nsITimerCallback, nsINamed)
|
||||
|
||||
// default to 2000ms, same as the preference
|
||||
// security.mixed_content.hsts_priming_request_timeout
|
||||
uint32_t HSTSPrimingListener::sHSTSPrimingTimeout = 2000;
|
||||
|
||||
|
||||
HSTSPrimingListener::HSTSPrimingListener(nsIHstsPrimingCallback* aCallback)
|
||||
: mCallback(aCallback)
|
||||
{
|
||||
static nsresult rv =
|
||||
Preferences::AddUintVarCache(&sHSTSPrimingTimeout,
|
||||
"security.mixed_content.hsts_priming_request_timeout");
|
||||
Unused << rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HSTSPrimingListener::GetInterface(const nsIID & aIID, void **aResult)
|
||||
{
|
||||
return QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
void
|
||||
HSTSPrimingListener::ReportTiming(nsIHstsPrimingCallback* aCallback, nsresult aResult)
|
||||
{
|
||||
nsCOMPtr<nsITimedChannel> timingChannel =
|
||||
do_QueryInterface(aCallback);
|
||||
if (!timingChannel) {
|
||||
LOG(("HSTS priming: mCallback is not an nsITimedChannel!"));
|
||||
return;
|
||||
}
|
||||
|
||||
TimeStamp channelCreationTime;
|
||||
nsresult rv = timingChannel->GetChannelCreation(&channelCreationTime);
|
||||
if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull()) {
|
||||
PRUint32 interval =
|
||||
(PRUint32) (TimeStamp::Now() - channelCreationTime).ToMilliseconds();
|
||||
Telemetry::Accumulate(Telemetry::HSTS_PRIMING_REQUEST_DURATION,
|
||||
(NS_SUCCEEDED(aResult)) ? NS_LITERAL_CSTRING("success")
|
||||
: NS_LITERAL_CSTRING("failure"),
|
||||
interval);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HSTSPrimingListener::OnStartRequest(nsIRequest *aRequest,
|
||||
nsISupports *aContext)
|
||||
{
|
||||
nsCOMPtr<nsIHstsPrimingCallback> callback;
|
||||
callback.swap(mCallback);
|
||||
|
||||
if (mHSTSPrimingTimer) {
|
||||
Unused << mHSTSPrimingTimer->Cancel();
|
||||
mHSTSPrimingTimer = nullptr;
|
||||
}
|
||||
|
||||
// if callback is null, we have already canceled this request and reported
|
||||
// the failure
|
||||
if (!callback) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult primingResult = CheckHSTSPrimingRequestStatus(aRequest);
|
||||
ReportTiming(callback, primingResult);
|
||||
|
||||
if (NS_FAILED(primingResult)) {
|
||||
LOG(("HSTS Priming Failed (request was not approved)"));
|
||||
return callback->OnHSTSPrimingFailed(primingResult, false);
|
||||
}
|
||||
|
||||
LOG(("HSTS Priming Succeeded (request was approved)"));
|
||||
return callback->OnHSTSPrimingSucceeded(false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HSTSPrimingListener::OnStopRequest(nsIRequest *aRequest,
|
||||
nsISupports *aContext,
|
||||
nsresult aStatus)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HSTSPrimingListener::CheckHSTSPrimingRequestStatus(nsIRequest* aRequest)
|
||||
{
|
||||
nsresult status;
|
||||
nsresult rv = aRequest->GetStatus(&status);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_FAILED(status)) {
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
||||
// Test that things worked on a HTTP level
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
|
||||
NS_ENSURE_STATE(httpChannel);
|
||||
nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(aRequest);
|
||||
NS_ENSURE_STATE(internal);
|
||||
|
||||
bool succeedded;
|
||||
rv = httpChannel->GetRequestSucceeded(&succeedded);
|
||||
if (NS_FAILED(rv) || !succeedded) {
|
||||
// If the request did not return a 2XX response, don't process it
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
||||
bool synthesized = false;
|
||||
RefPtr<nsHttpChannel> rawHttpChannel = do_QueryObject(httpChannel);
|
||||
NS_ENSURE_STATE(rawHttpChannel);
|
||||
|
||||
rv = rawHttpChannel->GetResponseSynthesized(&synthesized);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (synthesized) {
|
||||
// Don't consider synthesized responses
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
||||
// check to see if the HSTS cache was updated
|
||||
nsCOMPtr<nsISiteSecurityService> sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = httpChannel->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(uri, NS_ERROR_CONTENT_BLOCKED);
|
||||
|
||||
OriginAttributes originAttributes;
|
||||
NS_GetOriginAttributes(httpChannel, originAttributes);
|
||||
|
||||
bool hsts;
|
||||
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, 0,
|
||||
originAttributes, nullptr, nullptr, &hsts);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (hsts) {
|
||||
// An HSTS upgrade was found
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// There is no HSTS upgrade available
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
||||
/** nsIStreamListener methods **/
|
||||
|
||||
NS_IMETHODIMP
|
||||
HSTSPrimingListener::OnDataAvailable(nsIRequest *aRequest,
|
||||
nsISupports *ctxt,
|
||||
nsIInputStream *inStr,
|
||||
uint64_t sourceOffset,
|
||||
uint32_t count)
|
||||
{
|
||||
uint32_t totalRead;
|
||||
return inStr->ReadSegments(NS_DiscardSegment, nullptr, count, &totalRead);
|
||||
}
|
||||
|
||||
/** nsITimerCallback **/
|
||||
NS_IMETHODIMP
|
||||
HSTSPrimingListener::Notify(nsITimer* timer)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIHstsPrimingCallback> callback;
|
||||
callback.swap(mCallback);
|
||||
if (!callback) {
|
||||
// we already processed this channel
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ReportTiming(callback, NS_ERROR_HSTS_PRIMING_TIMEOUT);
|
||||
|
||||
if (mPrimingChannel) {
|
||||
rv = mPrimingChannel->Cancel(NS_ERROR_HSTS_PRIMING_TIMEOUT);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("HSTS Priming timed out, and we got an error canceling the priming channel.");
|
||||
}
|
||||
}
|
||||
|
||||
rv = callback->OnHSTSPrimingFailed(NS_ERROR_HSTS_PRIMING_TIMEOUT, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("HSTS Priming timed out, and we got an error reporting the failure.");
|
||||
}
|
||||
|
||||
return NS_OK; // unused
|
||||
}
|
||||
|
||||
/** nsINamed **/
|
||||
NS_IMETHODIMP
|
||||
HSTSPrimingListener::GetName(nsACString& aName)
|
||||
{
|
||||
aName.AssignLiteral("HSTSPrimingListener");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
HSTSPrimingListener::StartHSTSPriming(nsIChannel* aRequestChannel,
|
||||
nsIHstsPrimingCallback* aCallback)
|
||||
{
|
||||
nsCOMPtr<nsIURI> finalChannelURI;
|
||||
nsresult rv = NS_GetFinalChannelURI(aRequestChannel, getter_AddRefs(finalChannelURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = NS_GetSecureUpgradedURI(finalChannelURI, getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
// check the HSTS cache
|
||||
bool hsts;
|
||||
bool hstsCached;
|
||||
nsCOMPtr<nsISiteSecurityService> sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
OriginAttributes originAttributes;
|
||||
NS_GetOriginAttributes(aRequestChannel, originAttributes);
|
||||
|
||||
rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, 0,
|
||||
originAttributes, &hstsCached, nullptr, &hsts);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (hsts) {
|
||||
// already saw this host and will upgrade if allowed by preferences
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_REQUESTS,
|
||||
HSTSPrimingRequest::eHSTS_PRIMING_REQUEST_CACHED_HSTS);
|
||||
return aCallback->OnHSTSPrimingSucceeded(true);
|
||||
}
|
||||
|
||||
if (hstsCached) {
|
||||
// there is a non-expired entry in the cache that doesn't allow us to
|
||||
// upgrade, so go ahead and fail early.
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_REQUESTS,
|
||||
HSTSPrimingRequest::eHSTS_PRIMING_REQUEST_CACHED_NO_HSTS);
|
||||
return aCallback->OnHSTSPrimingFailed(NS_ERROR_CONTENT_BLOCKED, true);
|
||||
}
|
||||
|
||||
// Either it wasn't cached or the cached result has expired. Build a
|
||||
// channel for the HEAD request.
|
||||
|
||||
nsCOMPtr<nsILoadInfo> originalLoadInfo = aRequestChannel->GetLoadInfo();
|
||||
MOZ_ASSERT(originalLoadInfo, "can not perform HSTS priming without a loadInfo");
|
||||
if (!originalLoadInfo) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = static_cast<mozilla::LoadInfo*>
|
||||
(originalLoadInfo.get())->CloneForNewRequest();
|
||||
loadInfo->SetIsHSTSPriming(true);
|
||||
|
||||
// the LoadInfo must have a security flag set in order to pass through priming
|
||||
// if none of these security flags are set, go ahead and fail now instead of
|
||||
// crashing in nsContentSecurityManager::ValidateSecurityFlags
|
||||
nsSecurityFlags securityMode = loadInfo->GetSecurityMode();
|
||||
if (securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS &&
|
||||
securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED &&
|
||||
securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS &&
|
||||
securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
|
||||
securityMode != nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
|
||||
return aCallback->OnHSTSPrimingFailed(NS_ERROR_CONTENT_BLOCKED, true);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
rv = aRequestChannel->GetLoadGroup(getter_AddRefs(loadGroup));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsLoadFlags loadFlags;
|
||||
rv = aRequestChannel->GetLoadFlags(&loadFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
loadFlags &= HttpBaseChannel::INHIBIT_CACHING |
|
||||
HttpBaseChannel::INHIBIT_PERSISTENT_CACHING |
|
||||
HttpBaseChannel::LOAD_BYPASS_CACHE |
|
||||
HttpBaseChannel::LOAD_FROM_CACHE |
|
||||
HttpBaseChannel::VALIDATE_ALWAYS;
|
||||
// Priming requests should never be intercepted by service workers and
|
||||
// are always anonymous.
|
||||
loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER |
|
||||
nsIRequest::LOAD_ANONYMOUS;
|
||||
|
||||
// Create a new channel to send the priming request
|
||||
nsCOMPtr<nsIChannel> primingChannel;
|
||||
rv = NS_NewChannelInternal(getter_AddRefs(primingChannel),
|
||||
uri,
|
||||
loadInfo,
|
||||
loadGroup,
|
||||
nullptr, // aCallbacks are set later
|
||||
loadFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Set method and headers
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(primingChannel);
|
||||
if (!httpChannel) {
|
||||
NS_ERROR("HSTSPrimingListener: Failed to QI to nsIHttpChannel!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(primingChannel);
|
||||
NS_ENSURE_STATE(internal);
|
||||
|
||||
// Since this is a perfomrance critical request (blocks the page load) we
|
||||
// want to get the response ASAP.
|
||||
nsCOMPtr<nsIClassOfService> classOfService(do_QueryInterface(primingChannel));
|
||||
if (classOfService) {
|
||||
classOfService->AddClassFlags(nsIClassOfService::UrgentStart);
|
||||
}
|
||||
|
||||
// Currently using HEAD per the draft, but under discussion to change to GET
|
||||
// with credentials so if the upgrade is approved the result is already cached.
|
||||
rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("HEAD"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = httpChannel->
|
||||
SetRequestHeader(NS_LITERAL_CSTRING("Upgrade-Insecure-Requests"),
|
||||
NS_LITERAL_CSTRING("1"), false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// attempt to set the class of service flags on the new channel
|
||||
nsCOMPtr<nsIClassOfService> requestClass = do_QueryInterface(aRequestChannel);
|
||||
if (!requestClass) {
|
||||
NS_ERROR("HSTSPrimingListener: aRequestChannel is not an nsIClassOfService");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsIClassOfService> primingClass = do_QueryInterface(httpChannel);
|
||||
if (!primingClass) {
|
||||
NS_ERROR("HSTSPrimingListener: httpChannel is not an nsIClassOfService");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint32_t classFlags = 0;
|
||||
rv = requestClass ->GetClassFlags(&classFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = primingClass->SetClassFlags(classFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// The priming channel should have highest priority so that it completes as
|
||||
// quickly as possible, allowing the load to proceed.
|
||||
nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(primingChannel);
|
||||
if (p) {
|
||||
uint32_t priority = nsISupportsPriority::PRIORITY_HIGHEST;
|
||||
|
||||
p->SetPriority(priority);
|
||||
}
|
||||
|
||||
// Set up listener which will start the original channel
|
||||
HSTSPrimingListener* listener = new HSTSPrimingListener(aCallback);
|
||||
// Start priming
|
||||
rv = primingChannel->AsyncOpen2(listener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
listener->mPrimingChannel.swap(primingChannel);
|
||||
|
||||
nsCOMPtr<nsITimer> timer;
|
||||
rv = NS_NewTimerWithCallback(getter_AddRefs(timer),
|
||||
listener,
|
||||
sHSTSPrimingTimeout,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("HSTS Priming failed to initialize channel cancellation timer");
|
||||
}
|
||||
|
||||
listener->mHSTSPrimingTimer.swap(timer);
|
||||
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_REQUESTS,
|
||||
HSTSPrimingRequest::eHSTS_PRIMING_REQUEST_SENT);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
|
@ -1,162 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 HSTSPrimingListener_h__
|
||||
#define HSTSPrimingListener_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsINamed.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIThreadRetargetableStreamListener.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
class nsINetworkInterceptController;
|
||||
class nsIHstsPrimingCallback;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class HttpChannelParent;
|
||||
class nsHttpChannel;
|
||||
|
||||
/*
|
||||
* How often do we send an HSTS priming request (over all requests)
|
||||
*/
|
||||
enum HSTSPrimingRequest {
|
||||
// No HSTS priming request. The request is not mixed-content, or we have
|
||||
// already cached the result before nsMixedContentBlocker::ShouldLoad
|
||||
eHSTS_PRIMING_NO_REQUEST = 0,
|
||||
// Sent an HSTS priming request
|
||||
eHSTS_PRIMING_REQUEST_SENT = 1,
|
||||
// Channel marked for priming, but already had a cached result
|
||||
eHSTS_PRIMING_REQUEST_CACHED_HSTS = 2,
|
||||
// Channel marked for priming, but already had a cached result
|
||||
eHSTS_PRIMING_REQUEST_CACHED_NO_HSTS = 3,
|
||||
// An error occured setting up the the priming request channel. If the
|
||||
// priming channel failed in OnstopRequest, there is no HSTS, or the
|
||||
// channel is redirected, that is recorded by
|
||||
// MIXED_CONTENT_HSTS_PRIMING_RESULT.
|
||||
eHSTS_PRIMING_REQUEST_ERROR = 4,
|
||||
// The channel had no load info, so is ineligible for priming
|
||||
eHSTS_PRIMING_REQUEST_NO_LOAD_INFO = 5,
|
||||
// The request was marked for HSTS priming, but was upgraded by
|
||||
// NS_ShouldSecureUpgrade before HSTS priming was sent.
|
||||
eHSTS_PRIMING_REQUEST_ALREADY_UPGRADED = 6,
|
||||
};
|
||||
|
||||
/*
|
||||
* How often do we get back an HSTS priming result which upgrades the connection to HTTPS?
|
||||
*/
|
||||
enum HSTSPrimingResult {
|
||||
// This site has been seen before and won't be upgraded
|
||||
eHSTS_PRIMING_CACHED_NO_UPGRADE = 0,
|
||||
// This site has been seen before and will be upgraded
|
||||
eHSTS_PRIMING_CACHED_DO_UPGRADE = 1,
|
||||
// This site has been seen before and will be blocked
|
||||
eHSTS_PRIMING_CACHED_BLOCK = 2,
|
||||
// The request was already upgraded, probably through
|
||||
// upgrade-insecure-requests
|
||||
eHSTS_PRIMING_ALREADY_UPGRADED = 3,
|
||||
// HSTS priming is successful and the connection will be upgraded to HTTPS
|
||||
eHSTS_PRIMING_SUCCEEDED = 4,
|
||||
// When priming succeeds, but preferences require preservation of the order
|
||||
// of mixed-content and hsts, and mixed-content blocks the load
|
||||
eHSTS_PRIMING_SUCCEEDED_BLOCK = 5,
|
||||
// When priming succeeds, but preferences require preservation of the order
|
||||
// of mixed-content and hsts, and mixed-content allows the load over http
|
||||
eHSTS_PRIMING_SUCCEEDED_HTTP = 6,
|
||||
// HSTS priming failed, and the load is blocked by mixed-content
|
||||
eHSTS_PRIMING_FAILED_BLOCK = 7,
|
||||
// HSTS priming failed, and the load is allowed by mixed-content
|
||||
eHSTS_PRIMING_FAILED_ACCEPT = 8,
|
||||
// The HSTS Priming request timed out, and the load is blocked by
|
||||
// mixed-content
|
||||
eHSTS_PRIMING_TIMEOUT_BLOCK = 9,
|
||||
// The HSTS Priming request timed out, and the load is allowed by
|
||||
// mixed-content
|
||||
eHSTS_PRIMING_TIMEOUT_ACCEPT = 10,
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Class used as streamlistener and notification callback when
|
||||
// doing the HEAD request for an HSTS Priming check. Needs to be an
|
||||
// nsIStreamListener in order to receive events from AsyncOpen2
|
||||
class HSTSPrimingListener final : public nsIStreamListener,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsITimerCallback,
|
||||
public nsINamed
|
||||
{
|
||||
public:
|
||||
explicit HSTSPrimingListener(nsIHstsPrimingCallback* aCallback);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
NS_DECL_NSINAMED
|
||||
|
||||
private:
|
||||
~HSTSPrimingListener() {}
|
||||
|
||||
// Only nsHttpChannel can invoke HSTS priming
|
||||
friend class mozilla::net::nsHttpChannel;
|
||||
|
||||
/**
|
||||
* Start the HSTS priming request. This will send an anonymous HEAD request to
|
||||
* the URI aRequestChannel is attempting to load. On success, the new HSTS
|
||||
* priming channel is allocated in aHSTSPrimingChannel.
|
||||
*
|
||||
* @param aRequestChannel the reference channel used to initialze the HSTS
|
||||
* priming channel
|
||||
* @param aCallback the callback stored to handle the results of HSTS priming.
|
||||
* @param aHSTSPrimingChannel if the new HSTS priming channel is allocated
|
||||
* successfully, it will be placed here.
|
||||
*/
|
||||
static nsresult StartHSTSPriming(nsIChannel* aRequestChannel,
|
||||
nsIHstsPrimingCallback* aCallback);
|
||||
|
||||
/**
|
||||
* Given a request, return NS_OK if it has resulted in a cached HSTS update.
|
||||
* We don't need to check for the header as that has already been done for us.
|
||||
*/
|
||||
nsresult CheckHSTSPrimingRequestStatus(nsIRequest* aRequest);
|
||||
|
||||
// send telemetry about how long HSTS priming requests take
|
||||
void ReportTiming(nsIHstsPrimingCallback* aCallback, nsresult aResult);
|
||||
|
||||
/**
|
||||
* the nsIHttpChannel to notify with the result of HSTS priming.
|
||||
*/
|
||||
nsCOMPtr<nsIHstsPrimingCallback> mCallback;
|
||||
|
||||
/**
|
||||
* Keep a handle to the priming channel so we can cancel it on timeout
|
||||
*/
|
||||
nsCOMPtr<nsIChannel> mPrimingChannel;
|
||||
|
||||
/**
|
||||
* Keep a handle to the timer around so it can be canceled if we don't time
|
||||
* out.
|
||||
*/
|
||||
nsCOMPtr<nsITimer> mHSTSPrimingTimer;
|
||||
|
||||
/**
|
||||
* How long (in ms) before an HSTS Priming channel times out.
|
||||
* Preference: security.mixed_content.hsts_priming_request_timeout
|
||||
*/
|
||||
static uint32_t sHSTSPrimingTimeout;
|
||||
};
|
||||
|
||||
|
||||
}} // mozilla::net
|
||||
|
||||
#endif // HSTSPrimingListener_h__
|
|
@ -2143,8 +2143,8 @@ NS_IMETHODIMP
|
|||
HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
|
||||
{
|
||||
LOG(("HttpChannelChild::OnRedirectVerifyCallback [this=%p]\n", this));
|
||||
nsresult rv;
|
||||
OptionalURIParams redirectURI;
|
||||
nsresult rv;
|
||||
|
||||
uint32_t referrerPolicy = REFERRER_POLICY_UNSET;
|
||||
OptionalURIParams referrerURI;
|
||||
|
@ -2164,19 +2164,10 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
|
|||
result = NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
bool forceHSTSPriming = false;
|
||||
bool mixedContentWouldBlock = false;
|
||||
if (newHttpChannel) {
|
||||
// Must not be called until after redirect observers called.
|
||||
newHttpChannel->SetOriginalURI(mOriginalURI);
|
||||
|
||||
nsCOMPtr<nsILoadInfo> newLoadInfo;
|
||||
rv = newHttpChannel->GetLoadInfo(getter_AddRefs(newLoadInfo));
|
||||
if (NS_SUCCEEDED(rv) && newLoadInfo) {
|
||||
forceHSTSPriming = newLoadInfo->GetForceHSTSPriming();
|
||||
mixedContentWouldBlock = newLoadInfo->GetMixedContentWouldBlock();
|
||||
}
|
||||
|
||||
rv = newHttpChannel->GetReferrerPolicy(&referrerPolicy);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
nsCOMPtr<nsIURI> newChannelReferrerURI;
|
||||
|
@ -2242,7 +2233,7 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
|
|||
do_QueryInterface(mRedirectChannelChild);
|
||||
if (newHttpChannelInternal) {
|
||||
nsCOMPtr<nsIURI> apiRedirectURI;
|
||||
nsresult rv = newHttpChannelInternal->GetApiRedirectToURI(
|
||||
rv = newHttpChannelInternal->GetApiRedirectToURI(
|
||||
getter_AddRefs(apiRedirectURI));
|
||||
if (NS_SUCCEEDED(rv) && apiRedirectURI) {
|
||||
/* If there was an API redirect of this channel, we need to send it
|
||||
|
@ -2269,7 +2260,7 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
|
|||
if (mIPCOpen)
|
||||
SendRedirect2Verify(result, *headerTuples, loadFlags, referrerPolicy,
|
||||
referrerURI, redirectURI, corsPreflightArgs,
|
||||
forceHSTSPriming, mixedContentWouldBlock, chooseAppcache);
|
||||
chooseAppcache);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -954,8 +954,6 @@ HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
|
|||
const OptionalURIParams& aReferrerURI,
|
||||
const OptionalURIParams& aAPIRedirectURI,
|
||||
const OptionalCorsPreflightArgs& aCorsPreflightArgs,
|
||||
const bool& aForceHSTSPriming,
|
||||
const bool& aMixedContentWouldBlock,
|
||||
const bool& aChooseAppcache)
|
||||
{
|
||||
LOG(("HttpChannelParent::RecvRedirect2Verify [this=%p result=%" PRIx32 "]\n",
|
||||
|
@ -998,14 +996,6 @@ HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
|
|||
newInternalChannel->SetCorsPreflightParameters(args.unsafeHeaders());
|
||||
}
|
||||
|
||||
if (aForceHSTSPriming) {
|
||||
nsCOMPtr<nsILoadInfo> newLoadInfo;
|
||||
rv = newHttpChannel->GetLoadInfo(getter_AddRefs(newLoadInfo));
|
||||
if (NS_SUCCEEDED(rv) && newLoadInfo) {
|
||||
newLoadInfo->SetHSTSPriming(aMixedContentWouldBlock);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI);
|
||||
rv = newHttpChannel->SetReferrerWithPolicy(referrerUri, referrerPolicy);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
|
|
@ -188,8 +188,6 @@ protected:
|
|||
const OptionalURIParams& aReferrerURI,
|
||||
const OptionalURIParams& apiRedirectUri,
|
||||
const OptionalCorsPreflightArgs& aCorsPreflightArgs,
|
||||
const bool& aForceHSTSPriming,
|
||||
const bool& aMixedContentWouldBlock,
|
||||
const bool& aChooseAppcache) override;
|
||||
virtual mozilla::ipc::IPCResult RecvUpdateAssociatedContentSecurity(const int32_t& broken,
|
||||
const int32_t& no) override;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "InterceptedHttpChannel.h"
|
||||
#include "nsContentSecurityManager.h"
|
||||
#include "nsEscape.h"
|
||||
#include "mozilla/dom/Performance.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
|
|
@ -47,7 +47,6 @@ parent:
|
|||
OptionalURIParams referrerUri,
|
||||
OptionalURIParams apiRedirectTo,
|
||||
OptionalCorsPreflightArgs corsPreflightArgs,
|
||||
bool forceHSTSPriming, bool mixedContentWouldBlock,
|
||||
bool chooseAppcache);
|
||||
|
||||
// For document loads we keep this protocol open after child's
|
||||
|
|
|
@ -9,7 +9,6 @@ with Files('**'):
|
|||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIBackgroundChannelRegistrar.idl',
|
||||
'nsIHstsPrimingCallback.idl',
|
||||
'nsIHttpActivityObserver.idl',
|
||||
'nsIHttpAuthenticableChannel.idl',
|
||||
'nsIHttpAuthenticator.idl',
|
||||
|
@ -64,7 +63,6 @@ UNIFIED_SOURCES += [
|
|||
'BackgroundChannelRegistrar.cpp',
|
||||
'CacheControlParser.cpp',
|
||||
'ConnectionDiagnostics.cpp',
|
||||
'HSTSPrimerListener.cpp',
|
||||
'Http2Compression.cpp',
|
||||
'Http2Push.cpp',
|
||||
'Http2Session.cpp',
|
||||
|
|
|
@ -104,7 +104,6 @@
|
|||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "CacheControlParser.h"
|
||||
#include "nsMixedContentBlocker.h"
|
||||
#include "HSTSPrimerListener.h"
|
||||
#include "CacheStorageService.h"
|
||||
#include "HttpChannelParent.h"
|
||||
#include "InterceptedHttpChannel.h"
|
||||
|
@ -590,7 +589,7 @@ nsHttpChannel::ConnectOnTailUnblock()
|
|||
// Someone has called TriggerNetwork(), meaning we are racing the
|
||||
// network with the cache.
|
||||
mWaitingForProxy = false;
|
||||
return TryHSTSPriming();
|
||||
return ContinueConnect();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -630,70 +629,6 @@ nsHttpChannel::ConnectOnTailUnblock()
|
|||
return TriggerNetwork();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpChannel::TryHSTSPriming()
|
||||
{
|
||||
bool isHttpScheme;
|
||||
nsresult rv = mURI->SchemeIs("http", &isHttpScheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
bool isHttpsScheme;
|
||||
rv = mURI->SchemeIs("https", &isHttpsScheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if ((isHttpScheme || isHttpsScheme) && mLoadInfo) {
|
||||
if (mLoadInfo->GetIsHSTSPriming()) {
|
||||
// shortcut priming requests so they don't get counted
|
||||
return ContinueConnect();
|
||||
}
|
||||
|
||||
// HSTS priming requires the LoadInfo provided with AsyncOpen2
|
||||
bool requireHSTSPriming =
|
||||
mLoadInfo->GetForceHSTSPriming();
|
||||
|
||||
if (requireHSTSPriming &&
|
||||
nsMixedContentBlocker::sSendHSTSPriming) {
|
||||
if (!isHttpsScheme) {
|
||||
rv = HSTSPrimingListener::StartHSTSPriming(this, this);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
CloseCacheEntry(false);
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_REQUESTS,
|
||||
HSTSPrimingRequest::eHSTS_PRIMING_REQUEST_ERROR);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mLoadInfo->GetIsHSTSPrimingUpgrade()) {
|
||||
// The request was already upgraded, for example by a prior
|
||||
// successful priming request
|
||||
LOG(("HSTS Priming: request already upgraded"));
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
|
||||
HSTSPrimingResult::eHSTS_PRIMING_ALREADY_UPGRADED);
|
||||
|
||||
// No HSTS Priming request was sent.
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_REQUESTS,
|
||||
HSTSPrimingRequest::eHSTS_PRIMING_REQUEST_ALREADY_UPGRADED);
|
||||
}
|
||||
|
||||
mLoadInfo->ClearHSTSPriming();
|
||||
return ContinueConnect();
|
||||
}
|
||||
|
||||
if (!mLoadInfo->GetIsHSTSPrimingUpgrade()) {
|
||||
// No HSTS Priming request was sent, and we didn't already record this request
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_REQUESTS,
|
||||
HSTSPrimingRequest::eHSTS_PRIMING_NO_REQUEST);
|
||||
}
|
||||
} else {
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_REQUESTS,
|
||||
HSTSPrimingRequest::eHSTS_PRIMING_REQUEST_NO_LOAD_INFO);
|
||||
}
|
||||
|
||||
return ContinueConnect();
|
||||
}
|
||||
|
||||
// nsIInputAvailableCallback (nsIStreamTransportService.idl)
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::OnInputAvailableComplete(uint64_t size, nsresult status)
|
||||
|
@ -761,8 +696,6 @@ nsHttpChannel::ContinueConnect()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we have had HSTS priming, we need to reevaluate whether we need
|
||||
// a CORS preflight. Bug: 1272440
|
||||
// If we need to start a CORS preflight, do it now!
|
||||
// Note that it is important to do this before the early returns below.
|
||||
if (!mIsCorsPreflightDone && mRequireCORSPreflight) {
|
||||
|
@ -1898,9 +1831,6 @@ nsHttpChannel::ProcessSingleSecurityHeader(uint32_t aType,
|
|||
NS_GetOriginAttributes(this, originAttributes);
|
||||
uint32_t failureResult;
|
||||
uint32_t headerSource = nsISiteSecurityService::SOURCE_ORGANIC_REQUEST;
|
||||
if (mLoadInfo && mLoadInfo->GetIsHSTSPriming()) {
|
||||
headerSource = nsISiteSecurityService::SOURCE_HSTS_PRIMING;
|
||||
}
|
||||
rv = sss->ProcessHeader(aType, mURI, securityHeader, aSSLStatus,
|
||||
aFlags, headerSource, originAttributes,
|
||||
nullptr, nullptr, &failureResult);
|
||||
|
@ -5874,7 +5804,6 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
|
|||
NS_INTERFACE_MAP_ENTRY(nsICorsPreflightCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRaceCacheWithNetwork)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIHstsPrimingCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIChannelWithDivertableParentListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequestTailUnblockCallback)
|
||||
// we have no macro that covers this case.
|
||||
|
@ -8663,131 +8592,6 @@ nsHttpChannel::OnPreflightFailed(nsresult aError)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIHstsPrimingCallback functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* May be invoked synchronously if HSTS priming has already been performed
|
||||
* for the host.
|
||||
*/
|
||||
nsresult
|
||||
nsHttpChannel::OnHSTSPrimingSucceeded(bool aCached)
|
||||
{
|
||||
// If "security.mixed_content.use_hsts" is false, record the result of
|
||||
// HSTS priming and block or proceed with the load as required by
|
||||
// mixed-content blocking
|
||||
bool wouldBlock = mLoadInfo->GetMixedContentWouldBlock();
|
||||
// Clear out the HSTS priming flags on the LoadInfo to simplify the logic in
|
||||
// TryHSTSPriming()
|
||||
mLoadInfo->ClearHSTSPriming();
|
||||
|
||||
if (nsMixedContentBlocker::sUseHSTS) {
|
||||
// redirect the channel to HTTPS if the pref
|
||||
// "security.mixed_content.use_hsts" is true
|
||||
LOG(("HSTS Priming succeeded, redirecting to HTTPS [this=%p]", this));
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
|
||||
(aCached) ? HSTSPrimingResult::eHSTS_PRIMING_CACHED_DO_UPGRADE :
|
||||
HSTSPrimingResult::eHSTS_PRIMING_SUCCEEDED);
|
||||
// we have to record this upgrade here since we have already
|
||||
// been through NS_ShouldSecureUpgrade
|
||||
Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 3);
|
||||
Telemetry::Accumulate(Telemetry::HSTS_UPGRADE_SOURCE, 2);
|
||||
mLoadInfo->SetIsHSTSPrimingUpgrade(true);
|
||||
return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps);
|
||||
}
|
||||
|
||||
// preserve the mixed-content-before-hsts order and block if required
|
||||
if (wouldBlock) {
|
||||
LOG(("HSTS Priming succeeded, blocking for mixed-content [this=%p]",
|
||||
this));
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
|
||||
HSTSPrimingResult::eHSTS_PRIMING_SUCCEEDED_BLOCK);
|
||||
CloseCacheEntry(false);
|
||||
return AsyncAbort(NS_ERROR_CONTENT_BLOCKED);
|
||||
}
|
||||
|
||||
LOG(("HSTS Priming succeeded, loading insecure: [this=%p]", this));
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
|
||||
HSTSPrimingResult::eHSTS_PRIMING_SUCCEEDED_HTTP);
|
||||
|
||||
// log HTTP_SCHEME_UPGRADE telemetry
|
||||
Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 0);
|
||||
|
||||
nsresult rv = ContinueConnect();
|
||||
if (NS_FAILED(rv)) {
|
||||
CloseCacheEntry(false);
|
||||
return AsyncAbort(rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* May be invoked synchronously if HSTS priming has already been performed
|
||||
* for the host.
|
||||
*/
|
||||
nsresult
|
||||
nsHttpChannel::OnHSTSPrimingFailed(nsresult aError, bool aCached)
|
||||
{
|
||||
bool wouldBlock = mLoadInfo->GetMixedContentWouldBlock();
|
||||
// Clear out the HSTS priming flags on the LoadInfo to simplify the logic in
|
||||
// TryHSTSPriming()
|
||||
mLoadInfo->ClearHSTSPriming();
|
||||
|
||||
LOG(("HSTS Priming Failed [this=%p], %s the load", this,
|
||||
(wouldBlock) ? "blocking" : "allowing"));
|
||||
if (aError == NS_ERROR_HSTS_PRIMING_TIMEOUT) {
|
||||
// A priming request was sent, but timed out
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
|
||||
(wouldBlock) ? HSTSPrimingResult::eHSTS_PRIMING_TIMEOUT_BLOCK :
|
||||
HSTSPrimingResult::eHSTS_PRIMING_TIMEOUT_ACCEPT);
|
||||
} else if (aCached) {
|
||||
// Between the time we marked for priming and started the priming request,
|
||||
// the host was found to not allow the upgrade, probably from another
|
||||
// priming request.
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
|
||||
(wouldBlock) ? HSTSPrimingResult::eHSTS_PRIMING_CACHED_BLOCK :
|
||||
HSTSPrimingResult::eHSTS_PRIMING_CACHED_NO_UPGRADE);
|
||||
} else {
|
||||
// A priming request was sent, and no HSTS header was found that allows
|
||||
// the upgrade.
|
||||
Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
|
||||
(wouldBlock) ? HSTSPrimingResult::eHSTS_PRIMING_FAILED_BLOCK :
|
||||
HSTSPrimingResult::eHSTS_PRIMING_FAILED_ACCEPT);
|
||||
}
|
||||
|
||||
// Don't visit again for at least
|
||||
// security.mixed_content.hsts_priming_cache_timeout seconds.
|
||||
nsISiteSecurityService* sss = gHttpHandler->GetSSService();
|
||||
NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
|
||||
OriginAttributes originAttributes;
|
||||
NS_GetOriginAttributes(this, originAttributes);
|
||||
nsresult rv = sss->CacheNegativeHSTSResult(mURI,
|
||||
nsMixedContentBlocker::sHSTSPrimingCacheTimeout, originAttributes);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("nsISiteSecurityService::CacheNegativeHSTSResult failed");
|
||||
}
|
||||
|
||||
// If we would block, go ahead and abort with the error provided
|
||||
if (wouldBlock) {
|
||||
CloseCacheEntry(false);
|
||||
return AsyncAbort(aError);
|
||||
}
|
||||
|
||||
// log HTTP_SCHEME_UPGRADE telemetry
|
||||
Telemetry::Accumulate(Telemetry::HTTP_SCHEME_UPGRADE, 0);
|
||||
|
||||
// we can continue the load and the UI has been updated as mixed content
|
||||
rv = ContinueConnect();
|
||||
if (NS_FAILED(rv)) {
|
||||
CloseCacheEntry(false);
|
||||
return AsyncAbort(rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AChannelHasDivertableParentChannelAsListener internal functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -9287,8 +9091,8 @@ nsHttpChannel::TriggerNetwork()
|
|||
|
||||
// If we are waiting for a proxy request, that means we can't trigger
|
||||
// the next step just yet. We need for mConnectionInfo to be non-null
|
||||
// before we call TryHSTSPriming. OnProxyAvailable will trigger
|
||||
// BeginConnect, and Connect will call TryHSTSPriming even if it's
|
||||
// before we call ContinueConnect. OnProxyAvailable will trigger
|
||||
// BeginConnect, and Connect will call ContinueConnect even if it's
|
||||
// for the cache callbacks.
|
||||
if (mProxyRequest) {
|
||||
LOG((" proxy request in progress. Delaying network trigger.\n"));
|
||||
|
@ -9301,7 +9105,7 @@ nsHttpChannel::TriggerNetwork()
|
|||
}
|
||||
|
||||
LOG((" triggering network\n"));
|
||||
return TryHSTSPriming();
|
||||
return ContinueConnect();
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsICorsPreflightCallback.h"
|
||||
#include "AlternateServices.h"
|
||||
#include "nsIHstsPrimingCallback.h"
|
||||
#include "nsIRaceCacheWithNetwork.h"
|
||||
#include "mozilla/extensions/PStreamFilterParent.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
@ -84,7 +83,6 @@ class nsHttpChannel final : public HttpBaseChannel
|
|||
, public nsSupportsWeakReference
|
||||
, public nsICorsPreflightCallback
|
||||
, public nsIChannelWithDivertableParentListener
|
||||
, public nsIHstsPrimingCallback
|
||||
, public nsIRaceCacheWithNetwork
|
||||
, public nsIRequestTailUnblockCallback
|
||||
, public nsITimerCallback
|
||||
|
@ -104,7 +102,6 @@ public:
|
|||
NS_DECL_NSIAPPLICATIONCACHECONTAINER
|
||||
NS_DECL_NSIAPPLICATIONCACHECHANNEL
|
||||
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
|
||||
NS_DECL_NSIHSTSPRIMINGCALLBACK
|
||||
NS_DECL_NSITHREADRETARGETABLEREQUEST
|
||||
NS_DECL_NSIDNSLISTENER
|
||||
NS_DECL_NSICHANNELWITHDIVERTABLEPARENTLISTENER
|
||||
|
@ -212,9 +209,6 @@ public: /* internal necko use only */
|
|||
bool noAppCache);
|
||||
MOZ_MUST_USE nsresult ContinueConnect();
|
||||
|
||||
// If the load is mixed-content, build and send an HSTS priming request.
|
||||
MOZ_MUST_USE nsresult TryHSTSPriming();
|
||||
|
||||
MOZ_MUST_USE nsresult StartRedirectChannelToURI(nsIURI *, uint32_t);
|
||||
|
||||
// This allows cache entry to be marked as foreign even after channel itself
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* HSTS priming attempts to prevent mixed-content by looking for the
|
||||
* Strict-Transport-Security header as a signal from the server that it is
|
||||
* safe to upgrade HTTP to HTTPS.
|
||||
*
|
||||
* Since mixed-content blocking happens very early in the process in AsyncOpen2,
|
||||
* the status of mixed-content blocking is stored in the LoadInfo and then used
|
||||
* to determine whether to send a priming request or not.
|
||||
*
|
||||
* This interface is implemented by nsHttpChannel so that it can receive the
|
||||
* result of HSTS priming.
|
||||
*/
|
||||
[builtinclass, uuid(eca6daca-3f2a-4a2a-b3bf-9f24f79bc999)]
|
||||
interface nsIHstsPrimingCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* HSTS priming has succeeded with an STS header, and the site asserts it is
|
||||
* safe to upgrade the request from HTTP to HTTPS. The request may still be
|
||||
* blocked based on the user's preferences.
|
||||
*
|
||||
* May be invoked synchronously if HSTS priming has already been performed
|
||||
* for the host.
|
||||
*
|
||||
* @param aCached whether the result was already in the HSTS cache
|
||||
*/
|
||||
[noscript, nostdcall, must_use]
|
||||
void onHSTSPrimingSucceeded(in bool aCached);
|
||||
|
||||
/**
|
||||
* HSTS priming has seen no STS header, the request itself has failed,
|
||||
* or some other failure which does not constitute a positive signal that the
|
||||
* site can be upgraded safely to HTTPS. The request may still be allowed
|
||||
* based on the user's preferences.
|
||||
*
|
||||
* May be invoked synchronously if HSTS priming has already been performed
|
||||
* for the host.
|
||||
*
|
||||
* @param aError The error which caused this failure, or NS_ERROR_CONTENT_BLOCKED
|
||||
* @param aCached whether the result was already in the HSTS cache
|
||||
*/
|
||||
[noscript, nostdcall, must_use]
|
||||
void onHSTSPrimingFailed(in nsresult aError, in bool aCached);
|
||||
};
|
|
@ -99,7 +99,6 @@ interface nsISiteSecurityService : nsISupports
|
|||
const uint32_t SOURCE_UNKNOWN = 0;
|
||||
const uint32_t SOURCE_PRELOAD_LIST = 1;
|
||||
const uint32_t SOURCE_ORGANIC_REQUEST = 2;
|
||||
const uint32_t SOURCE_HSTS_PRIMING = 3;
|
||||
|
||||
/**
|
||||
* Parses a given HTTP header and records the results internally.
|
||||
|
@ -297,22 +296,6 @@ interface nsISiteSecurityService : nsISupports
|
|||
in boolean aIncludesSubdomains,
|
||||
in int64_t aExpires);
|
||||
|
||||
/**
|
||||
* Mark a host as declining to provide a given security state so that features
|
||||
* such as HSTS priming will not flood a server with requests.
|
||||
*
|
||||
* @param aURI the nsIURI that this applies to
|
||||
* @param aMaxAge lifetime (in seconds) of this negative cache
|
||||
* @param aOriginAttributes the origin attributes that isolate this origin,
|
||||
* (note that this implementation does not isolate
|
||||
* by userContextId because of the risk of man-in-
|
||||
* the-middle attacks before trust-on-second-use
|
||||
* happens).
|
||||
*/
|
||||
[noscript, must_use] void cacheNegativeHSTSResult(
|
||||
in nsIURI aURI, in unsigned long long aMaxAge,
|
||||
in const_OriginAttributesRef aOriginAttributes);
|
||||
|
||||
/**
|
||||
* Returns an enumerator of the nsISiteSecurityService storage. Each item in
|
||||
* the enumeration is a nsISiteSecurityState that can be QueryInterfaced to
|
||||
|
|
|
@ -129,7 +129,6 @@ public:
|
|||
case SourceUnknown:
|
||||
case SourcePreload:
|
||||
case SourceOrganic:
|
||||
case SourceHSTSPriming:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
@ -675,21 +674,6 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSiteSecurityService::CacheNegativeHSTSResult(
|
||||
nsIURI* aSourceURI,
|
||||
uint64_t aMaxAge,
|
||||
const OriginAttributes& aOriginAttributes)
|
||||
{
|
||||
nsAutoCString hostname;
|
||||
nsresult rv = GetHost(aSourceURI, hostname);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// SecurityPropertyNegative results only come from HSTS priming
|
||||
return SetHSTSState(nsISiteSecurityService::HEADER_HSTS, hostname.get(),
|
||||
aMaxAge, false, 0, SecurityPropertyNegative,
|
||||
SourceHSTSPriming, aOriginAttributes);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSiteSecurityService::RemoveStateInternal(
|
||||
uint32_t aType, nsIURI* aURI, uint32_t aFlags,
|
||||
|
@ -841,7 +825,6 @@ nsSiteSecurityService::ProcessHeader(uint32_t aType,
|
|||
case SourceUnknown:
|
||||
case SourcePreload:
|
||||
case SourceOrganic:
|
||||
case SourceHSTSPriming:
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
|
|
@ -47,7 +47,6 @@ enum SecurityPropertySource {
|
|||
SourceUnknown = nsISiteSecurityService::SOURCE_UNKNOWN,
|
||||
SourcePreload = nsISiteSecurityService::SOURCE_PRELOAD_LIST,
|
||||
SourceOrganic = nsISiteSecurityService::SOURCE_ORGANIC_REQUEST,
|
||||
SourceHSTSPriming = nsISiteSecurityService::SOURCE_HSTS_PRIMING,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -129,22 +129,3 @@ pref("security.ssl.errorReporting.automatic", false);
|
|||
// blacking themselves out by setting a bad pin. (60 days by default)
|
||||
// https://tools.ietf.org/html/rfc7469#section-4.1
|
||||
pref("security.cert_pinning.max_max_age_seconds", 5184000);
|
||||
|
||||
// HSTS Priming
|
||||
// If a request is mixed-content, send an HSTS priming request to attempt to
|
||||
// see if it is available over HTTPS.
|
||||
// Don't change the order of evaluation of mixed-content and HSTS upgrades in
|
||||
// order to be most compatible with current standards in Release
|
||||
pref("security.mixed_content.send_hsts_priming", false);
|
||||
pref("security.mixed_content.use_hsts", false);
|
||||
#ifdef EARLY_BETA_OR_EARLIER
|
||||
// Change the order of evaluation so HSTS upgrades happen before
|
||||
// mixed-content blocking
|
||||
pref("security.mixed_content.send_hsts_priming", true);
|
||||
pref("security.mixed_content.use_hsts", true);
|
||||
#endif
|
||||
// Approximately 1 week default cache for HSTS priming failures, in seconds
|
||||
pref ("security.mixed_content.hsts_priming_cache_timeout", 604800);
|
||||
// Force the channel to timeout in 2 seconds if we have not received
|
||||
// expects a time in milliseconds
|
||||
pref ("security.mixed_content.hsts_priming_request_timeout", 2000);
|
||||
|
|
|
@ -863,11 +863,6 @@
|
|||
"dom/security/test/cors/browser_CORS-console-warnings.js": 35545,
|
||||
"dom/security/test/csp/browser_manifest-src-override-default-src.js": 3586,
|
||||
"dom/security/test/csp/browser_test_web_manifest.js": 4283,
|
||||
"dom/security/test/hsts/browser_hsts-priming_allow_active.js": 3604,
|
||||
"dom/security/test/hsts/browser_hsts-priming_block_active.js": 3685,
|
||||
"dom/security/test/hsts/browser_hsts-priming_cache-timeout.js": 2657,
|
||||
"dom/security/test/hsts/browser_hsts-priming_no-duplicates.js": 3260,
|
||||
"dom/security/test/hsts/browser_hsts-priming_timeout.js": 3048,
|
||||
"dom/tests/browser/browser_ConsoleStorageAPITests.js": 3370,
|
||||
"dom/tests/browser/browser_ConsoleStoragePBTest_perwindowpb.js": 2854,
|
||||
"dom/tests/browser/browser_beforeunload_between_chrome_content.js": 7725,
|
||||
|
|
|
@ -782,17 +782,6 @@
|
|||
"dom/security/test/contentverifier/browser_verify_content_about_newtab2.js": 7915,
|
||||
"dom/security/test/cors/browser_CORS-console-warnings.js": 22469,
|
||||
"dom/security/test/csp/browser_test_web_manifest.js": 3266,
|
||||
"dom/security/test/hsts/browser_hsts-priming_allow_active.js": 2437,
|
||||
"dom/security/test/hsts/browser_hsts-priming_allow_display.js": 1726,
|
||||
"dom/security/test/hsts/browser_hsts-priming_block_active.js": 2803,
|
||||
"dom/security/test/hsts/browser_hsts-priming_block_active_css.js": 1771,
|
||||
"dom/security/test/hsts/browser_hsts-priming_block_active_with_redir_same.js": 2067,
|
||||
"dom/security/test/hsts/browser_hsts-priming_block_display.js": 1752,
|
||||
"dom/security/test/hsts/browser_hsts-priming_cache-timeout.js": 3386,
|
||||
"dom/security/test/hsts/browser_hsts-priming_hsts_after_mixed.js": 2328,
|
||||
"dom/security/test/hsts/browser_hsts-priming_no-duplicates.js": 2637,
|
||||
"dom/security/test/hsts/browser_hsts-priming_no-non-standard-ports.js": 3865,
|
||||
"dom/security/test/hsts/browser_hsts-priming_timeout.js": 3543,
|
||||
"dom/tests/browser/browser_ConsoleAPITests.js": 2336,
|
||||
"dom/tests/browser/browser_ConsoleStorageAPITests.js": 1843,
|
||||
"dom/tests/browser/browser_ConsoleStoragePBTest_perwindowpb.js": 2170,
|
||||
|
|
|
@ -10328,45 +10328,6 @@
|
|||
"n_values": 10,
|
||||
"description": "How often would blocked mixed content be allowed if HSTS upgrades were allowed? 0=display/no-HSTS, 1=display/HSTS, 2=active/no-HSTS, 3=active/HSTS"
|
||||
},
|
||||
"MIXED_CONTENT_HSTS_PRIMING_2": {
|
||||
"record_in_processes": [ "main" ],
|
||||
"alert_emails": ["seceng-telemetry@mozilla.com"],
|
||||
"bug_numbers": [1359987],
|
||||
"expires_in_version": "60",
|
||||
"kind": "enumerated",
|
||||
"n_values": 16,
|
||||
"description": "How often would blocked mixed content be allowed if HSTS upgrades were allowed, including how often would we send an HSTS priming request? 0=passive/HSTS, 1=active/HSTS, 2=passive/no priming, 3=passive/priming, 4=active/no priming, 5=active/priming, 6=passive/will HSTS upgrade, 7=active/will HSTS upgrade"
|
||||
},
|
||||
"MIXED_CONTENT_HSTS_PRIMING_RESULT": {
|
||||
"record_in_processes": [ "main" ],
|
||||
"alert_emails": ["seceng-telemetry@mozilla.com"],
|
||||
"bug_numbers": [1246540],
|
||||
"expires_in_version": "60",
|
||||
"kind": "enumerated",
|
||||
"n_values": 16,
|
||||
"description": "How often do we get back an HSTS priming result which upgrades the connection to HTTPS? 0=cached (no upgrade), 1=cached (do upgrade), 2=cached (blocked), 3=already upgraded, 4=priming succeeded, 5=priming succeeded (block due to pref), 6=priming succeeded (no upgrade due to pref), 7=priming failed (block), 8=priming failed (accept), 9=timeout (block), 10=timeout (accept)"
|
||||
},
|
||||
"MIXED_CONTENT_HSTS_PRIMING_REQUESTS": {
|
||||
"record_in_processes": [ "main" ],
|
||||
"alert_emails": ["seceng-telemetry@mozilla.com"],
|
||||
"bug_numbers": [1359987],
|
||||
"expires_in_version": "62",
|
||||
"kind": "enumerated",
|
||||
"n_values": 10,
|
||||
"description": "How often does a request result in HSTS priming? (0=Sent HSTS priming, 1=No priming, 2=Priming skipped due to cached HSTS, 3=Priming skipped due to cached NO HSTS, 4=Priming failed (request error), 5=Priming skipped (missing load info), 6=Priming skipped (already upgraded)"
|
||||
},
|
||||
"HSTS_PRIMING_REQUEST_DURATION": {
|
||||
"record_in_processes": [ "main" ],
|
||||
"alert_emails": ["seceng-telemetry@mozilla.com"],
|
||||
"bug_numbers": [1311893, 1359987],
|
||||
"expires_in_version": "62",
|
||||
"kind": "exponential",
|
||||
"low": 100,
|
||||
"high": 30000,
|
||||
"n_buckets": 100,
|
||||
"keyed": true,
|
||||
"description": "The amount of time required for HSTS priming requests (ms), keyed by success or failure of the priming request. (success, failure)"
|
||||
},
|
||||
"HSTS_UPGRADE_SOURCE": {
|
||||
"record_in_processes": [ "main" ],
|
||||
"alert_emails": ["seceng-telemetry@mozilla.com"],
|
||||
|
|
|
@ -450,10 +450,6 @@ with modules["NETWORK"]:
|
|||
# Generic error for non-specific failures during service worker interception
|
||||
errors["NS_ERROR_INTERCEPTION_FAILED"] = FAILURE(100)
|
||||
|
||||
# nsIHstsPrimingListener
|
||||
# Error code for HSTS priming timeout to distinguish from blocking
|
||||
errors["NS_ERROR_HSTS_PRIMING_TIMEOUT"] = FAILURE(110)
|
||||
|
||||
|
||||
|
||||
# =======================================================================
|
||||
|
|
Загрузка…
Ссылка в новой задаче