Bug 1139849 - postMessage to incorrect target domain should print a console security error draft
authorJames Burke <jrburke@gmail.com>
Wed, 27 Jan 2016 17:40:54 -0800
changeset 326435 960abbe3e1858f445a6887ee016bfff4ad8365c5
parent 325588 aa90f482e16db77cdb7dea84564ea1cbd8f7f6b3
child 513616 189d0ef73a7fb22717f67757033127e111f46128
push id10156
push userjrburke@gmail.com
push dateThu, 28 Jan 2016 01:44:33 +0000
bugs1139849
milestone47.0a1
Bug 1139849 - postMessage to incorrect target domain should print a console security error
dom/base/PostMessageEvent.cpp
dom/base/PostMessageEvent.h
dom/base/nsGlobalWindow.cpp
dom/locales/en-US/chrome/dom/dom.properties
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -23,23 +23,25 @@
 
 namespace mozilla {
 namespace dom {
 
 PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource,
                                    const nsAString& aCallerOrigin,
                                    nsGlobalWindow* aTargetWindow,
                                    nsIPrincipal* aProvidedPrincipal,
+                                   nsIDocument* aSourceDocument,
                                    bool aTrustedCaller)
 : StructuredCloneHolder(CloningSupported, TransferringSupported,
                         SameProcessSameThread),
   mSource(aSource),
   mCallerOrigin(aCallerOrigin),
   mTargetWindow(aTargetWindow),
   mProvidedPrincipal(aProvidedPrincipal),
+  mSourceDocument(aSourceDocument),
   mTrustedCaller(aTrustedCaller)
 {
   MOZ_COUNT_CTOR(PostMessageEvent);
 }
 
 PostMessageEvent::~PostMessageEvent()
 {
   MOZ_COUNT_DTOR(PostMessageEvent);
@@ -87,20 +89,40 @@ PostMessageEvent::Run()
       return NS_OK;
 
     // Note: This is contrary to the spec with respect to file: URLs, which
     //       the spec groups into a single origin, but given we intentionally
     //       don't do that in other places it seems better to hold the line for
     //       now.  Long-term, we want HTML5 to address this so that we can
     //       be compliant while being safer.
     if (!targetPrin->Equals(mProvidedPrincipal)) {
+      nsAutoCString origin, targetOrigin;
+      nsresult rv = targetPrin->GetOrigin(targetOrigin);
+      NS_ENSURE_SUCCESS(rv, rv);
+      rv = mProvidedPrincipal->GetOrigin(origin);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      NS_ConvertUTF8toUTF16 origin16(origin);
+      NS_ConvertUTF8toUTF16 targetOrigin16(targetOrigin);
+      const char16_t* params[] = { origin16.get(), targetOrigin16.get() };
+
+      nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
+        NS_LITERAL_CSTRING("DOM Window"), mSourceDocument,
+        nsContentUtils::eDOM_PROPERTIES,
+        "TargetPrincipalDoesNotMatch",
+        params, ArrayLength(params));
+
       return NS_OK;
     }
   }
 
+  // The document is just used for the principal mismatch check above, now it is
+  // no longer needed.
+  mSourceDocument = nullptr;
+
   ErrorResult rv;
   JS::Rooted<JS::Value> messageData(cx);
   nsCOMPtr<nsPIDOMWindow> window = targetWindow.get();
 
   Read(window, cx, &messageData, rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
--- a/dom/base/PostMessageEvent.h
+++ b/dom/base/PostMessageEvent.h
@@ -29,24 +29,26 @@ class PostMessageEvent final : public ns
 {
 public:
   NS_DECL_NSIRUNNABLE
 
   PostMessageEvent(nsGlobalWindow* aSource,
                    const nsAString& aCallerOrigin,
                    nsGlobalWindow* aTargetWindow,
                    nsIPrincipal* aProvidedPrincipal,
+                   nsIDocument* aSourceDocument,
                    bool aTrustedCaller);
 
 private:
   ~PostMessageEvent();
 
   RefPtr<nsGlobalWindow> mSource;
   nsString mCallerOrigin;
   RefPtr<nsGlobalWindow> mTargetWindow;
   nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
+  nsCOMPtr<nsIDocument> mSourceDocument;
   bool mTrustedCaller;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_PostMessageEvent_h
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7964,16 +7964,19 @@ nsGlobalWindow::PostMessageMozOuter(JSCo
   // event creation and dispatch.
   RefPtr<PostMessageEvent> event =
     new PostMessageEvent(nsContentUtils::IsCallerChrome() || !callerInnerWin
                          ? nullptr
                          : callerInnerWin->GetOuterWindowInternal(),
                          origin,
                          this,
                          providedPrincipal,
+                         !callerInnerWin
+                         ? nullptr
+                         : callerInnerWin->GetDoc(),
                          nsContentUtils::IsCallerChrome());
 
   JS::Rooted<JS::Value> message(aCx, aMessage);
   JS::Rooted<JS::Value> transfer(aCx, aTransfer);
 
   event->Write(aCx, message, transfer, aError);
   if (NS_WARN_IF(aError.Failed())) {
     return;
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -185,8 +185,10 @@ BadOpaqueRedirectInterceptionWithURL=Fai
 # LOCALIZATION NOTE: Do not translate "ServiceWorker" or "FetchEvent.preventDefault()". %S is a URL.
 InterceptionCanceledWithURL=Failed to load '%S'. A ServiceWorker canceled the load by calling FetchEvent.preventDefault().
 # LOCALIZATION NOTE: Do not translate "ServiceWorker", "promise", or "FetchEvent.respondWith()". %1$S is a URL. %2$S is an error string.
 InterceptionRejectedResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that rejected with '%2$S'.
 # LOCALIZATION NOTE: Do not translate "ServiceWorker", "promise", "FetchEvent.respondWith()", or "Response". %1$S is a URL. %2$S is an error string.
 InterceptedNonResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that resolved with non-Response value '%2$S'.
 ExecCommandCutCopyDeniedNotInputDriven=document.execCommand('cut'/'copy') was denied because it was not called from inside a short running user-generated event handler.
 PatternAttributeCompileFailure=Unable to check <input pattern='%S'> because the pattern is not a valid regexp: %S
+# LOCALIZATION NOTE: Do not translate "postMessage" or DOMWindow. %S values are origins, like https://domain.com:port
+TargetPrincipalDoesNotMatch=Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('%S') does not match the recipient window's origin ('%S').