From 95aa8c8fc76e2309a629b05994a2677b0887140b Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Tue, 23 Mar 2010 14:51:56 +1000 Subject: Basic Loader origin safety (for discussion). --- .../graphicsitems/qdeclarativeloader.cpp | 3 ++ src/declarative/qml/qdeclarativecontext.cpp | 16 +++++++++ src/declarative/qml/qdeclarativecontext.h | 2 ++ .../qdeclarativeloader/data/differentorigin.qml | 3 ++ .../qdeclarativeloader/data/sameorigin-load.qml | 3 ++ .../qdeclarativeloader/data/sameorigin.qml | 3 ++ .../qdeclarativeloader/tst_qdeclarativeloader.cpp | 41 ++++++++++++++++++++-- 7 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativeloader/data/differentorigin.qml create mode 100644 tests/auto/declarative/qdeclarativeloader/data/sameorigin-load.qml create mode 100644 tests/auto/declarative/qdeclarativeloader/data/sameorigin.qml diff --git a/src/declarative/graphicsitems/qdeclarativeloader.cpp b/src/declarative/graphicsitems/qdeclarativeloader.cpp index 745734e..3cbafd6 100644 --- a/src/declarative/graphicsitems/qdeclarativeloader.cpp +++ b/src/declarative/graphicsitems/qdeclarativeloader.cpp @@ -185,6 +185,9 @@ void QDeclarativeLoader::setSource(const QUrl &url) if (d->source == url) return; + if (!qmlContext(this)->isSafeOrigin(url)) + return; + d->clear(); d->source = url; diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp index 85896c4..ab3849a 100644 --- a/src/declarative/qml/qdeclarativecontext.cpp +++ b/src/declarative/qml/qdeclarativecontext.cpp @@ -361,6 +361,22 @@ QVariant QDeclarativeContext::contextProperty(const QString &name) const return value; } +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; +} + /*! Resolves the URL \a src relative to the URL of the containing component. diff --git a/src/declarative/qml/qdeclarativecontext.h b/src/declarative/qml/qdeclarativecontext.h index a349628..959af8b 100644 --- a/src/declarative/qml/qdeclarativecontext.h +++ b/src/declarative/qml/qdeclarativecontext.h @@ -85,6 +85,8 @@ public: void setBaseUrl(const QUrl &); QUrl baseUrl() const; + bool isSafeOrigin(const QUrl &src) const; + private: friend class QDeclarativeVME; friend class QDeclarativeEngine; diff --git a/tests/auto/declarative/qdeclarativeloader/data/differentorigin.qml b/tests/auto/declarative/qdeclarativeloader/data/differentorigin.qml new file mode 100644 index 0000000..e682d1c --- /dev/null +++ b/tests/auto/declarative/qdeclarativeloader/data/differentorigin.qml @@ -0,0 +1,3 @@ +import Qt 4.6 + +Loader { source: "http://evil.place/evil.qml" } diff --git a/tests/auto/declarative/qdeclarativeloader/data/sameorigin-load.qml b/tests/auto/declarative/qdeclarativeloader/data/sameorigin-load.qml new file mode 100644 index 0000000..e281246 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeloader/data/sameorigin-load.qml @@ -0,0 +1,3 @@ +import Qt 4.6 + +Item { } diff --git a/tests/auto/declarative/qdeclarativeloader/data/sameorigin.qml b/tests/auto/declarative/qdeclarativeloader/data/sameorigin.qml new file mode 100644 index 0000000..e7f5a14 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeloader/data/sameorigin.qml @@ -0,0 +1,3 @@ +import Qt 4.6 + +Loader { source: "sameorigin-load.qml" } diff --git a/tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp b/tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp index 2c20836..0deac3a 100644 --- a/tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp +++ b/tests/auto/declarative/qdeclarativeloader/tst_qdeclarativeloader.cpp @@ -86,6 +86,8 @@ private slots: void noResizeGraphicsWidget(); void networkRequestUrl(); void failNetworkRequest(); + void networkSafety(); + void networkSafety_data(); // void networkComponent(); void deleteComponentCrash(); @@ -394,7 +396,7 @@ void tst_QDeclarativeLoader::networkRequestUrl() server.serveDirectory(SRCDIR "/data"); QDeclarativeComponent component(&engine); - component.setData(QByteArray("import Qt 4.6\nLoader { source: \"http://127.0.0.1:14445/Rect120x60.qml\" }"), TEST_FILE("")); + component.setData(QByteArray("import Qt 4.6\nLoader { source: \"http://127.0.0.1:14445/Rect120x60.qml\" }"), QUrl("http://127.0.0.1:14445/dummy.qml")); QDeclarativeLoader *loader = qobject_cast(component.create()); QVERIFY(loader != 0); @@ -448,7 +450,7 @@ void tst_QDeclarativeLoader::failNetworkRequest() QTest::ignoreMessage(QtWarningMsg, "(:-1: Network error for URL http://127.0.0.1:14445/IDontExist.qml) "); QDeclarativeComponent component(&engine); - component.setData(QByteArray("import Qt 4.6\nLoader { source: \"http://127.0.0.1:14445/IDontExist.qml\" }"), TEST_FILE("")); + component.setData(QByteArray("import Qt 4.6\nLoader { source: \"http://127.0.0.1:14445/IDontExist.qml\" }"), QUrl("http://127.0.0.1:14445/dummy.qml")); QDeclarativeLoader *loader = qobject_cast(component.create()); QVERIFY(loader != 0); @@ -483,6 +485,41 @@ void tst_QDeclarativeLoader::deleteComponentCrash() delete item; } +void tst_QDeclarativeLoader::networkSafety_data() +{ + QTest::addColumn("url"); + 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\" ) "); +} + +void tst_QDeclarativeLoader::networkSafety() +{ + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + server.serveDirectory(SRCDIR "/data"); + + QFETCH(QUrl, url); + QFETCH(QString, message); + + if (!message.isEmpty()) + QTest::ignoreMessage(QtWarningMsg, message.toLatin1()); + + QDeclarativeComponent component(&engine, url); + TRY_WAIT(component.status() == QDeclarativeComponent::Ready); + QDeclarativeLoader *loader = qobject_cast(component.create()); + QVERIFY(loader != 0); + + if (message.isEmpty()) { + TRY_WAIT(loader->status() == QDeclarativeLoader::Ready); + } else { + TRY_WAIT(loader->status() == QDeclarativeLoader::Null); + } + + delete loader; +} + QTEST_MAIN(tst_QDeclarativeLoader) #include "tst_qdeclarativeloader.moc" -- cgit v0.12