From 4d82dd604c4f6aedbf3ed0eabcf89d3dca3d0a88 Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Wed, 24 Mar 2010 13:03:19 +1000 Subject: Origin safety testing for imported resources. Extends upon 95aa8c8fc76e2309a629b05994a2677b0887140b. Still under discussion. --- .../graphicsitems/qdeclarativeloader.cpp | 5 ++- .../qml/qdeclarativecompositetypemanager.cpp | 13 +++++++ src/declarative/qml/qdeclarativecontext.cpp | 14 +------ src/declarative/qml/qdeclarativeengine.cpp | 27 ++++++++++++++ src/declarative/qml/qdeclarativeengine.h | 2 + .../tst_qdeclarativelanguage.cpp | 43 +++++++++++++++++++++- .../qdeclarativeloader/tst_qdeclarativeloader.cpp | 2 +- 7 files changed, 91 insertions(+), 15 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativeloader.cpp b/src/declarative/graphicsitems/qdeclarativeloader.cpp index 3cbafd6..c0d316f 100644 --- a/src/declarative/graphicsitems/qdeclarativeloader.cpp +++ b/src/declarative/graphicsitems/qdeclarativeloader.cpp @@ -42,6 +42,7 @@ #include "qdeclarativeloader_p_p.h" #include +#include QT_BEGIN_NAMESPACE @@ -185,8 +186,10 @@ void QDeclarativeLoader::setSource(const QUrl &url) if (d->source == url) return; - if (!qmlContext(this)->isSafeOrigin(url)) + if (!qmlContext(this)->isSafeOrigin(url)) { + qmlInfo(this) << tr("\"%1\" is not a safe origin from \"%2\"").arg(url).arg(qmlContext(this)->baseUrl()); return; + } d->clear(); diff --git a/src/declarative/qml/qdeclarativecompositetypemanager.cpp b/src/declarative/qml/qdeclarativecompositetypemanager.cpp index c59e5e2..5160514 100644 --- a/src/declarative/qml/qdeclarativecompositetypemanager.cpp +++ b/src/declarative/qml/qdeclarativecompositetypemanager.cpp @@ -539,6 +539,19 @@ int QDeclarativeCompositeTypeManager::resolveTypes(QDeclarativeCompositeTypeData foreach (QDeclarativeScriptParser::Import imp, unit->data.imports()) { + if (imp.type != QDeclarativeScriptParser::Import::Library && !engine->isSafeOrigin(QUrl(imp.uri), unit->imports.baseUrl())) { + QDeclarativeError error; + error.setUrl(unit->imports.baseUrl()); + error.setDescription(tr("\"%1\" is not a safe origin").arg(imp.uri)); + error.setLine(imp.location.start.line); + error.setColumn(imp.location.start.column); + unit->status = QDeclarativeCompositeTypeData::Error; + unit->errorType = QDeclarativeCompositeTypeData::GeneralError; + unit->errors << error; + doComplete(unit); + return 0; + } + QDeclarativeDirComponents qmldircomponentsnetwork; if (imp.type == QDeclarativeScriptParser::Import::Script) continue; diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp index ab3849a..f801a88 100644 --- a/src/declarative/qml/qdeclarativecontext.cpp +++ b/src/declarative/qml/qdeclarativecontext.cpp @@ -363,18 +363,8 @@ QVariant QDeclarativeContext::contextProperty(const QString &name) const bool QDeclarativeContext::isSafeOrigin(const QUrl &src) const { - if (src.isRelative()) - return true; - if (src.scheme()==QLatin1String("https")) - return true; - - QUrl base = baseUrl(); - if (src.host() == base.host() && src.port() == base.port()) // including files (with no host) - return true; - - qWarning() << src << "is not a safe origin from" << base; - - return false; + Q_D(const QDeclarativeContext); + return !d->data->engine || d->data->engine->isSafeOrigin(src, baseUrl()); } /*! diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index d4872e2..d7f30d7 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -1883,6 +1883,33 @@ QString QDeclarativeEngine::offlineStoragePath() const } /*! + Returns whether \a to_url is considered safe content when reference by + content at \a from_url. + + The default implementation implements: + + \list + \i Relative URLs are safe + \i https content is safe + \i URLs from the same host and port are safe (including no-host) + \endlist + + You should consider whether this convention is adequate for your pareticular application. +*/ +bool QDeclarativeEngine::isSafeOrigin(const QUrl& to_url, const QUrl& from_url) const +{ + if (to_url.isRelative()) + return true; + if (to_url.scheme()==QLatin1String("https")) + return true; + + if (to_url.host() == from_url.host() && to_url.port() == from_url.port()) // including files (with no host) + return true; + + return false; +} + +/*! \internal Returns the result of the merge of \a baseName with \a dir, \a suffixes, and \a prefix. diff --git a/src/declarative/qml/qdeclarativeengine.h b/src/declarative/qml/qdeclarativeengine.h index 19e81b6..5c70b18 100644 --- a/src/declarative/qml/qdeclarativeengine.h +++ b/src/declarative/qml/qdeclarativeengine.h @@ -102,6 +102,8 @@ public: static void setObjectOwnership(QObject *, ObjectOwnership); static ObjectOwnership objectOwnership(QObject *); + virtual bool isSafeOrigin(const QUrl& to_url, const QUrl& from_url) const; + Q_SIGNALS: void quit (); diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp index 72b6b28..b6bd3f8 100644 --- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp +++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp @@ -53,6 +53,19 @@ #include "../../../shared/util.h" +class SafeLocalhostDeclarativeEngine : public QDeclarativeEngine { +public: + SafeLocalhostDeclarativeEngine() : QDeclarativeEngine() {} + + virtual bool isSafeOrigin(const QUrl& to_url, const QUrl& from_url) const + { + if (to_url.host() == "127.0.0.1") + return true; + else + return QDeclarativeEngine::isSafeOrigin(to_url,from_url); + } +}; + /* This test case covers QML language issues. This covers everything that does not involve evaluating ECMAScript expressions and bindings. @@ -121,6 +134,7 @@ private slots: void importsLocal(); void importsRemote_data(); void importsRemote(); + void importsUnsafe(); void importsInstalled_data(); void importsInstalled(); void importsOrder_data(); @@ -135,7 +149,7 @@ private slots: void crash2(); private: - QDeclarativeEngine engine; + SafeLocalhostDeclarativeEngine engine; void testType(const QString& qml, const QString& type); }; @@ -1262,6 +1276,33 @@ void tst_qdeclarativelanguage::importsRemote() testType(qml,type); } +void tst_qdeclarativelanguage::importsUnsafe() +{ + TestHTTPServer server(14445); + server.serveDirectory(SRCDIR); + + QString qml = "import \"http://127.0.0.1:14445/qtest/declarative/qmllanguage\"\n\nTest {}"; + + { + QDeclarativeEngine engine; // plain engine without special localhost handling + QDeclarativeComponent component(&engine); + component.setData(qml.toUtf8(), TEST_FILE("empty.qml")); // just a file for relative local imports + + QTRY_VERIFY(!component.isLoading()); + + QVERIFY(component.isError()); + } + + { + QDeclarativeComponent component(&engine); // engine special localhost handling + component.setData(qml.toUtf8(), TEST_FILE("empty.qml")); // just a file for relative local imports + + QTRY_VERIFY(!component.isLoading()); + + QVERIFY(!component.isError()); + } +} + void tst_qdeclarativelanguage::importsInstalled_data() { // QT-610 diff --git a/tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp b/tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp index 0deac3a..f27c1ce 100644 --- a/tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp +++ b/tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp @@ -491,7 +491,7 @@ void tst_QDeclarativeLoader::networkSafety_data() QTest::addColumn("message"); QTest::newRow("same origin") << QUrl("http://127.0.0.1:14445/sameorigin.qml") << QString(); - QTest::newRow("different origin") << QUrl("http://127.0.0.1:14445/differentorigin.qml") << QString(" QUrl( \"http://evil.place/evil.qml\" ) is not a safe origin from QUrl( \"http://127.0.0.1:14445/differentorigin.qml\" ) "); + QTest::newRow("different origin") << QUrl("http://127.0.0.1:14445/differentorigin.qml") << QString("QML Loader (http://127.0.0.1:14445/differentorigin.qml:3:1) \"http://evil.place/evil.qml\" is not a safe origin from \"http://127.0.0.1:14445/differentorigin.qml\""); } void tst_QDeclarativeLoader::networkSafety() -- cgit v0.12