summaryrefslogtreecommitdiffstats
path: root/src/network/access
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2017-01-23 16:56:29 +0100
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2017-01-26 10:24:39 +0000
commite0b55e8b1cdfea3dcb22b949632e4f5bcc200a76 (patch)
tree99d482f4f9ed845527cd7e06ef07ec503154ba60 /src/network/access
parentfa15162700a18ff243de46954bb613988c199ce7 (diff)
Make our redirect policies STS-aware
This patch changes the way we ensure NoLessSafeRedirectsPolicy and also the way we create actual redirect requests: https->http redirect is now reported as InsecureRedirectError (under NoLessSafeRedirectsPolicy) only if STS is disabled or we were redirected to a host whithout Strict Transport Security policy. Otherwise, we replace 'http' scheme with 'https' and explicitly set port 80 with port 443 as defined by HTTP Strict Transport Security policy. This scheme/port replacement will affect both NoLessSafeRedirectsPolicy and UserVerifiedRedirectsPolicy (SameOriginRedirectsPolicy does not allow any scheme change and we continue to report such redirects as InsecureRedirectError). Change-Id: Ib370b830e5fb6a0fec503d6fa3a0dec771c4b741 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Diffstat (limited to 'src/network/access')
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp11
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp28
2 files changed, 31 insertions, 8 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 327eaf91bc..fd3cbbe36e 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -552,12 +552,11 @@ QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socke
if (redirectUrl.scheme() == QLatin1String("http") || redirectUrl.scheme() == QLatin1String("https")) {
switch (reply->request().redirectsPolicy()) {
case QNetworkRequest::NoLessSafeRedirectsPolicy:
- // Check if we're doing an unsecure redirect (https -> http)
- if (priorUrl.scheme() == QLatin1String("https")
- && redirectUrl.scheme() == QLatin1String("http")) {
- emitReplyError(socket, reply, QNetworkReply::InsecureRedirectError);
- return QUrl();
- }
+ // Here we could handle https->http redirects as InsecureProtocolError.
+ // However, if HSTS is enabled and redirectUrl.host() is a known STS
+ // host, then we'll replace its scheme and this won't downgrade protocol,
+ // after all. We cannot access QNAM's STS cache from here, so delegate
+ // this check to QNetworkReplyHttpImpl.
break;
case QNetworkRequest::SameOriginRedirectsPolicy:
if (priorUrl.host() != redirectUrl.host()
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index 7d863ef53c..ece08acc6b 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -1135,16 +1135,40 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
if (isFinished)
return;
+ const QString schemeBefore(url.scheme());
if (httpRequest.isFollowRedirects()) // update the reply's url as it could've changed
url = redirectUrl;
- redirectRequest = createRedirectRequest(originalRequest, redirectUrl, maxRedirectsRemaining);
+ if (managerPrivate->stsEnabled && managerPrivate->stsCache.isKnownHost(url)) {
+ // RFC6797, 8.3:
+ // The UA MUST replace the URI scheme with "https" [RFC2818],
+ // and if the URI contains an explicit port component of "80",
+ // then the UA MUST convert the port component to be "443", or
+ // if the URI contains an explicit port component that is not
+ // equal to "80", the port component value MUST be preserved;
+ // otherwise, if the URI does not contain an explicit port
+ // component, the UA MUST NOT add one.
+ url.setScheme(QLatin1String("https"));
+ if (url.port() == 80)
+ url.setPort(443);
+ }
+
+ const bool isLessSafe = schemeBefore == QLatin1String("https")
+ && url.scheme() == QLatin1String("http");
+ if (httpRequest.redirectsPolicy() == QNetworkRequest::NoLessSafeRedirectsPolicy
+ && isLessSafe) {
+ error(QNetworkReply::InsecureRedirectError,
+ QCoreApplication::translate("QHttp", "Insecure redirect"));
+ return;
+ }
+
+ redirectRequest = createRedirectRequest(originalRequest, url, maxRedirectsRemaining);
operation = getRedirectOperation(operation, httpStatus);
if (httpRequest.redirectsPolicy() != QNetworkRequest::UserVerifiedRedirectsPolicy)
followRedirect();
- emit q->redirected(redirectUrl);
+ emit q->redirected(url);
}
void QNetworkReplyHttpImplPrivate::followRedirect()