Skip to content

Commit

Permalink
Block all network requests originating from QML
Browse files Browse the repository at this point in the history
Ricochet's UI does not make any network requests under any
circumstances; if one happens, it's likely a bug and potentially an
input sanitization issue that could lead to deanonymization.

Using QML's network access manager factory, intercept all of these
requests, trigger an assert, and make sure it's absolutely not possible
for any network traffic to occur as a result.

Contributes to ricochet-im#303, inspired by Sarah Jamie Lewis
  • Loading branch information
special committed Dec 12, 2015
1 parent 0370fa1 commit 1956d6c
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/ui/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@
#include "ui/LinkedText.h"
#include "utils/Settings.h"
#include "utils/PendingOperation.h"
#include "utils/Useful.h"
#include "ui/LanguagesModel.h"
#include <QtQml>
#include <QQmlApplicationEngine>
#include <QQmlNetworkAccessManagerFactory>
#include <QNetworkAccessManager>
#include <QQmlContext>
#include <QMessageBox>
#include <QPushButton>
Expand All @@ -61,13 +64,52 @@ static QObject *linkedtext_singleton(QQmlEngine *, QJSEngine *)
return new LinkedText;
}

/* Through the QQmlNetworkAccessManagerFactory below, all network requests
* created via QML will be passed to this object; including, for example,
* <img> tags parsed in rich Text items.
*
* Ricochet's UI does not directly cause network requests for any reason. These
* are always a potentially deanonymizing bug. This object will block them,
* and assert if appropriate.
*/
class BlockedNetworkAccessManager : public QNetworkAccessManager
{
public:
BlockedNetworkAccessManager(QObject *parent)
: QNetworkAccessManager(parent)
{
/* Either of these is sufficient to cause any network request to fail.
* Both of them should be redundant, because createRequest below also
* blackholes every request (and crashes for assert builds). */
setNetworkAccessible(QNetworkAccessManager::NotAccessible);
setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QLatin1String("0.0.0.0"), 0));
}

protected:
virtual QNetworkReply *createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData = 0)
{
BUG() << "QML attempted to load a network resource from" << req.url() << " - this is potentially an input sanitization flaw.";
return QNetworkAccessManager::createRequest(op, QNetworkRequest(), outgoingData);
}
};

class NetworkAccessBlockingFactory : public QQmlNetworkAccessManagerFactory
{
public:
virtual QNetworkAccessManager *create(QObject *parent)
{
return new BlockedNetworkAccessManager(parent);
}
};

MainWindow::MainWindow(QObject *parent)
: QObject(parent)
{
Q_ASSERT(!uiMain);
uiMain = this;

qml = new QQmlApplicationEngine(this);
qml->setNetworkAccessManagerFactory(new NetworkAccessBlockingFactory);

qmlRegisterUncreatableType<ContactUser>("im.ricochet", 1, 0, "ContactUser", QString());
qmlRegisterUncreatableType<UserIdentity>("im.ricochet", 1, 0, "UserIdentity", QString());
Expand Down

0 comments on commit 1956d6c

Please sign in to comment.