Index: Source/web/WebEmbeddedWorkerImpl.cpp |
diff --git a/Source/web/WebEmbeddedWorkerImpl.cpp b/Source/web/WebEmbeddedWorkerImpl.cpp |
index 7a5166085e9834875fbd5faa1c42ac7c0689b76d..5529a4251f83597dc512bb86337bb7ff4d19dc01 100644 |
--- a/Source/web/WebEmbeddedWorkerImpl.cpp |
+++ b/Source/web/WebEmbeddedWorkerImpl.cpp |
@@ -35,6 +35,7 @@ |
#include "core/dom/Document.h" |
#include "core/fetch/SubstituteData.h" |
#include "core/frame/csp/ContentSecurityPolicy.h" |
+#include "core/inspector/ConsoleMessage.h" |
#include "core/inspector/InspectorInstrumentation.h" |
#include "core/inspector/WorkerDebuggerAgent.h" |
#include "core/inspector/WorkerInspectorController.h" |
@@ -69,6 +70,15 @@ |
namespace blink { |
+namespace { |
+ |
+ bool IsAmpersandOrEqualsSign(UChar character) |
+ { |
+ return character == '=' || character == '&'; |
+ } |
+ |
+} // namespace |
+ |
WebEmbeddedWorker* WebEmbeddedWorker::create(WebServiceWorkerContextClient* client, WebWorkerContentSettingsClientProxy* contentSettingsClient) |
{ |
return new WebEmbeddedWorkerImpl(adoptPtr(client), adoptPtr(contentSettingsClient)); |
@@ -309,6 +319,37 @@ void WebEmbeddedWorkerImpl::onScriptLoaderFinished() |
startWorkerThread(); |
} |
+String WebEmbeddedWorkerImpl::checkForReflectedXSS() |
+{ |
+ ASSERT(m_mainScriptLoader); |
+ |
+ String queryString = m_mainScriptLoader->url().query(); |
+ String script = m_mainScriptLoader->script(); |
+ String segment, decoded; |
+ size_t offset = 0, next; |
+ |
+ do { |
+ next = queryString.find(IsAmpersandOrEqualsSign, offset); |
+ if (next == kNotFound) { |
+ segment = queryString.substring(offset); |
+ } else { |
+ offset = next + 1; |
+ segment = queryString.substring(offset, next - offset); |
+ } |
+ if (segment.sizeInBytes() > 20) { |
Tom Sepez
2015/08/31 16:41:19
why 20?
|
+ decoded = decodeURLEscapeSequences(segment); |
+ if (script.contains(segment)) { |
Tom Sepez
2015/08/31 16:41:19
what about multiple decodings? e.g. %2525332 etc.
|
+ return segment; |
+ } |
+ if (script.contains(decoded)) { |
+ return decoded; |
+ } |
+ } |
+ } while (next != kNotFound); |
+ |
+ return ""; |
+} |
+ |
void WebEmbeddedWorkerImpl::startWorkerThread() |
{ |
ASSERT(!m_askedToTerminate); |
@@ -330,11 +371,20 @@ void WebEmbeddedWorkerImpl::startWorkerThread() |
// We need to set the CSP to both the shadow page's document and the ServiceWorkerGlobalScope. |
document->initContentSecurityPolicy(m_mainScriptLoader->releaseContentSecurityPolicy()); |
+ // Verify that the query string contains nothing bad. |
+ String script = m_mainScriptLoader->script(); |
+ String potentialXSS = checkForReflectedXSS(); |
+ if (potentialXSS != "") { |
+ document->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Service Worker script invocation blocked; contained \"" + potentialXSS + "\", which was a query string parameter.")); |
+ m_workerContextClient->workerContextFailedToStart(); |
+ return; |
+ } |
+ |
KURL scriptURL = m_mainScriptLoader->url(); |
OwnPtr<WorkerThreadStartupData> startupData = WorkerThreadStartupData::create( |
scriptURL, |
m_workerStartData.userAgent, |
- m_mainScriptLoader->script(), |
+ script, |
m_mainScriptLoader->releaseCachedMetadata(), |
startMode, |
document->contentSecurityPolicy()->headers(), |